问题
I'm trying to subscribe to an FCM (Firebase Cloud Messaging) topic for a secondary Firebase App and according to the documentation this could be done by the overloaded getInstance
which takes the secondary FirebaseApp instance as a parameter:
https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/messaging/FirebaseMessaging#public-static-synchronized-firebasemessaging-getinstance-firebaseapp-app
public static synchronized FirebaseMessaging getInstance (FirebaseApp app)
Gets the FirebaseMessaging instance for the specified FirebaseApp.
I'm using Kotlin and I'm pulling in the package in build.gradle
like this:
implementation "com.google.firebase:firebase-messaging:20.2.0"
But when I try to instantiate the FirebaseMessaging
with the overloaded getInstance
, I get an error stating that it's not accessible. When I look at the package source, the decompilation shows that the overloaded constructor is not public like the parameterless getInstance
:
public class FirebaseMessaging {
public static final String INSTANCE_ID_SCOPE = "FCM";
private final Context zzb;
private final FirebaseInstanceId zzc;
private final Task<zzab> zzd;
@Nullable
@SuppressLint({"FirebaseUnknownNullness"})
@VisibleForTesting
static TransportFactory zza;
@NonNull
public static synchronized FirebaseMessaging getInstance() {
return getInstance(FirebaseApp.getInstance());
}
@Keep
@NonNull
static synchronized FirebaseMessaging getInstance(@NonNull FirebaseApp var0) {
return (FirebaseMessaging)var0.get(FirebaseMessaging.class);
}
Did I miss something?
回答1:
I reached into my Java background to pull a hack along the lines of "sudo make me a sandwich". Basically I forcefully obtain the other getInstance
through reflection, force it to be accessible and call it anyway. But this is clearly a hack, so I'm waiting for a legit solution.
val getInstance2: Method =
FirebaseMessaging::class.java.getDeclaredMethod("getInstance", FirebaseApp::class.javaObjectType)
getInstance2.setAccessible(true) // if security settings allow this
// null - for static methods
val firebaseMessaging: FirebaseMessaging =
getInstance2.invoke(null, appSingleton.firebaseApp!!) as FirebaseMessaging
firebaseMessaging.subscribeToTopic(GEO_FENCE_TOPIC)
.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Timber.d("Could not subscribe to topic ${GEO_FENCE_TOPIC}")
} else {
Timber.d("Subscribed to topic ${GEO_FENCE_TOPIC}")
}
}
sudo make me a sandwich!!!
回答2:
It is possible to receive messages from multiple senders using a different approach than instantiating multiple FirebaseApp
s.
You can get the Sender ID of the other project under Settings -> Cloud Messaging
in Firebase Console and use it on the client to this end.
Sender ID is also what you will receive as RemoteMessage.getFrom()
in FirebaseMessagingService.onMessageReceived(RemoteMessage)
.
In your client app, you will have to retrieve a token for that sender, to authenticate receiving messages from the other project. Then use that token in the backend as the target of the push message.
val senderId = getSenderIdFromServer()
val token = FirebaseInstanceId.getInstance().getToken(senderId, "FCM")
sendTokenToServer(token)
Warning: FirebaseInstanceId.getToken
is now deprecated and there is no replacement that I see in the SDK.
Looks like it's not possible to receive topic messages from a different project though. And currently the new server SDK lacks the ability to send to a device group.
来源:https://stackoverflow.com/questions/62253691/firebasemessaging-getinstancefirebaseapp-for-secondary-app-supposed-to-be-publ