对于应该是公共的但却是私有的辅助应用程序,是否需要使用FirebaseMessaging.getInstance(firebaseApp)?

n6lpvg4x  于 2022-11-17  发布在  其他
关注(0)|答案(4)|浏览(110)

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?
Additional note: one of my main tasks with the secondary Firebase project is to subscribe to a topic. I'd also read and write date to the Forestore database in that secondary project.

// Secondary project
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}")
                }
            }
tpxzln5u

tpxzln5u1#

I have verified a way to do it as I had been facing a similar issue.
I registered one of the projects using the google-services.json file.
Now as per the documentation :
public void onNewToken (String token)
Called when a new token for the default Firebase project is generated.
Here the word "default" is of key importance. It mentions that the onNewToken method in the overridden FirebaseMessagingService (eg: MyFirebaseMessagingService) will only be called for the default project.
Hence in this case the first project configured using the google-services.json will be the default project and for that the onNewToken method will be called.
For the second project, I manually configured the project using the code below following the documentation:

val options = FirebaseOptions.Builder()
        .setProjectId("my-firebase-project")
        .setApplicationId("1:27992087142:android:ce3b6448250083d1")
        .setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
        .build()

The values for the parameters can be obtained from the google-services.json file of the second project. (NOTE: DON'T INCLUDE THE SECOND PROJECT'S google-services.json IN THE PROJECT)

google-services.json to manual code mapping

  1. projectId (setProjectId) : project_id key in the root of the json
  2. applicationid (setApplicationId): client > client_info > mobilesdk_app_id . Incase of multiple project make sure that the client used is of the package_name which matches the Android app
  3. apiKey (setApiKey) : client > api_key > current_key (make sure of the package name here as well.

KEY CODE

The most important part here which is tough to find in the documentation is to get the token of the second firebase project.

val app = Firebase.initialize(this, options, "ANY_FIXED_STRING_EXCEPT_DEFAULT")

val firebaseMessaging = app.get(FirebaseMessaging::class.java) as FirebaseMessaging

ymFirebaseMessaging.token.addOnCompleteListener{
                if (!it.isSuccessful) {
                    Log.d(TAG, "Fetching FCM token failed", it.exception)

                    return@addOnCompleteListener
                }

                val token = it.result
                Log.d(TAG, "YM: $token")
                Toast.makeText(
                    activity,
                    "$TAG: Got token",
                    Toast.LENGTH_LONG
                ).show()
}
mefy6pfw

mefy6pfw2#

注:根据我从Firebase支持部门收到的反馈,此答案使用的API在Firebase SDK的较新版本中已被弃用,并且没有替代品,也没有任何替代计划。
关于FCM和Crashlytics单独项目的回答:
在与团队讨论后,他们确认Firebase不支持您的用例。您应该使用一个Firebase项目/Firebase应用程序来同时支持FCM和Crashlytics。感谢您的理解。
有关获取发件人ID令牌的已弃用方法的解答:
我从我们的工程师那里得到了一个更新,目前替换FirebaseInstanceId.getToken(senderId, scope)的方法FirebaseMessaging.getToken()不支持多个Firebase应用示例。在我们这边检查时,有一个关于这个的现有功能请求。通过这个,我已经将这个支持案例链接到我们现有的功能请求,以支持FIS中的多个示例。但是,我们的工程师将讨论这个问题。我不能具体说明这将需要多长时间或确切的时间(或如果)这个功能将公开发布。
可以使用与示例化多个FirebaseApp不同的方法从多个发送者接收消息。
您可以在Firebase Console中的Settings -> Cloud Messaging下获取其他项目的Sender ID,并在客户端上将其用于此目的。
发件人ID也是您在FirebaseMessagingService.onMessageReceived(RemoteMessage)中收到的RemoteMessage.getFrom()

在你的客户端应用中,你必须为那个发送者检索一个令牌,以验证从另一个项目接收的消息,然后在后端使用那个令牌作为推送消息的目标。

val senderId = getSenderIdFromServer()

val token = FirebaseInstanceId.getInstance().getToken(senderId, "FCM")

sendTokenToServer(token)

警告:FirebaseInstanceId.getToken现在已被弃用,我在SDK中没有看到替代项。
看起来似乎不可能从不同的项目接收主题消息。而且目前新的服务器SDK缺乏发送到设备组的能力。

nimxete2

nimxete23#

您可以使用get()调用访问Firebase消息示例。

String appName = "FCM";
FirebaseOptions options = new FirebaseOptions.Builder()
                .setApplicationId(applicationId)
                .setApiKey(apiKey)
                .setGcmSenderId(gcmSenderId)
                .setProjectId(projectId)
                .build();

FirebaseApp app = FirebaseApp.initializeApp(context, options, appName);
FirebaseMessaging messageApp = app.get(FirebaseMessaging.class);
messageApp
     .getToken()
     .addOnFailureListener(
         ex -> {
            Log.w(TAG, "FAILED to get FCM token ", ex);
         })
     .addOnSuccessListener(
        instanceIdResult -> {
            String token = instanceIdResult;
            mPrefs.edit().putString(DEVICE_FCM_ID_KEY, token)
                         .putString(DEVICE_REG_ID_APP_VERSION_KEY, mWsiApp.getAppVersion())
                         .apply();
     });
mzmfm0qo

mzmfm0qo4#

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!!!

相关问题