Firebase云功能令牌

问题描述 投票:0回答:1

我需要帮助。在node.js中编写的云函数抛出错误并且不会导致推送通知(警报器)在我的Android java应用程序中警告已发表评论或用户喜欢帖子。在Firebase控制台上,我能够在云功能日志中收到错误消息:

Successfully sent message: { results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 7952971403531609000 }

当我在Firebase云功能日志中查看错误消息时,我还会收到以下信息:

Error: { Error: The provided registration token is not registered. A previously valid registration token can be unregistered for a variety of reasons. See the error documentation for more details. Remove this registration token and stop using it to send messages.
at FirebaseMessagingError.Error (native)
at FirebaseMessagingError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/user_code/node_modules/firebase-admin/lib/utils/error.js:253:16)
at Function.FirebaseMessagingError.fromServerError (/user_code/node_modules/firebase-admin/lib/utils/error.js:283:16)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging.js:381:63
at Array.forEach (native)
at mapRawResponseToDevicesResponse (/user_code/node_modules/firebase-admin/lib/messaging/messaging.js:377:26)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging.js:558:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
errorInfo:
{ code: 'messaging/registration-token-not-registered',
message: 'The provided registration token is not registered. A previously valid registration token can be unregistered for a variety of reasons. See the error documentation for more details. Remove this registration token and stop using it to send messages.' },
codePrefix: 'messaging' }

消息非常清楚:出于各种原因,可以取消注册以前有效的注册令牌。我已经看到有关这些错误主题的其他帖子,但没有一个概述在注册和登录期间如何处理和使用令牌。

这是Firebase云功能代码......

'use-strict'

const functions = require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);


exports.sendCommentNotification=functions.firestore.document("Notifications/{user_id}/Comment/{comment_id}").onWrite((change,context)=> {

    const user_id=context.params.user_id;
    const comment_id=context.params.comment_id;

  console.log(user_id+":"+comment_id);

  return admin.firestore().collection("Notifications").doc(user_id).collection("Comment").doc(comment_id).get().then((queryResult)=>{

        const post_id=queryResult.data().post_id;
        const admin_user_id=queryResult.data().admin_id;
        const noti_id=queryResult.data().notification_id;
        const timestamp=queryResult.data().timestamp;    
        const post_desc=queryResult.data().post_desc;

        const admin_data=admin.firestore().collection("Users").doc(admin_user_id).get();
        const commenter_data=admin.firestore().collection("Users").doc(user_id).get();

        return Promise.all([commenter_data,admin_data]).then(result=>{

            const commenter_name=result[0].data().name;
            const commenter_image=result[0].data().image;
            const admin_token=result[1].data().token_id;
            const admin_name=result[1].data().name;

           if(commenter_name!=admin_name)
           {
               const payload={
               data:{
                notification_id:noti_id,
                timestamp:timestamp,
                post_id:post_id,
                admin_id:admin_user_id,
                title:commenter_name,
                from_image:commenter_image,

                post_desc:post_desc,
                body:"Commented on your post",
                click_action:"com.app.ej.ms.TARGET_COMMENT"
              }

            };


           admin.messaging().sendToDevice(admin_token,payload).then(function (response) {
            console.log("Successfully sent message:", response);
            return;
            })
            .catch(function (error) {
                console.log("Error sending message:", error);
            });


           }

          });
    });

});

...

这是在RegisterActivity.java中

...

private void registerUser() {

        mAuth.createUserWithEmailAndPassword(email_, pass_).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull final Task<AuthResult> task) {
                if (task.isSuccessful()) {

                    Map<String,Object> usernameMap=new HashMap<String, Object>();
                    usernameMap.put("username",username_);

                    firebaseFirestore.collection("Usernames")
                            .document(username_)
                            .set(usernameMap)
                            .addOnSuccessListener(new OnSuccessListener<Void>() {
                                @Override
                                public void onSuccess(Void aVoid) {
                                    task.getResult()
                                            .getUser()
                                            .sendEmailVerification()
                                            .addOnSuccessListener(new OnSuccessListener<Void>() {
                                                @Override
                                                public void onSuccess(Void aVoid) {

                                                    final String userUid = task.getResult().getUser().getUid();
                                                    final StorageReference user_profile = storageReference.child(userUid + ".png");
                                                    user_profile.putFile(imageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
                                                        @Override
                                                        public void onComplete(@NonNull final Task<UploadTask.TaskSnapshot> task) {
                                                            if (task.isSuccessful()) {

                                                               user_profile.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                                                                   @Override
                                                                   public void onSuccess(Uri uri) {

                                                                       //String token_id = FirebaseInstanceId.getInstance().getToken(); // Deprecated
                                                                       // TODO https://firebase.google.com/docs/cloud-messaging/android/client#retrieve-the-current-registration-token.
                                                                       // FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( RegisterActivity.this,  new OnSuccessListener<InstanceIdResult>() {

                                                                       FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                                                                           @Override
                                                                           public void onComplete(@NonNull Task<InstanceIdResult> task) {
                                                                               if (!task.isSuccessful()) {
                                                                                   Log.w(TAG, "getInstanceId failed", task.getException());
                                                                                   return;
                                                                               }
                                                                               // String token_id = instanceIdResult.getToken();
                                                                               String token_id = task.getResult().getToken();
                                                                               Log.i(TAG, "RegisterActivity Token ID (token_id): " + token_id);

                                                                               Map<String, Object> userMap = new HashMap<>();
                                                                               userMap.put("id", userUid);
userMap.put("name", name_);
userMap.put("image", uri.toString());
userMap.put("email", email_);
userMap.put("bio",getString(R.string.default_bio));
userMap.put("username", username_);
userMap.put("location", location_);
userMap.put("token_id", ""); //token_id

                           firebaseFirestore.collection("Users").document(userUid).set(userMap).addOnSuccessListener(new OnSuccessListener<Void>() {
                                                                                   @Override
                                                                                   public void onSuccess(Void aVoid) {
                                                                                       mDialog.dismiss();
                                                                                       Toast.makeText(RegisterActivity.this, "Verification email sent", Toast.LENGTH_SHORT).show();
                                                                                       finish();
                                                                                   } 

...

这是在LoginActivity.java中

...

public void performLogin(final boolean override) {

        final String email_, pass_;
        email_ = email.getText().toString();
        pass_ = password.getText().toString();

        if (!TextUtils.isEmpty(email_) && !TextUtils.isEmpty(pass_)) {
            mDialog.show();

            mAuth.signInWithEmailAndPassword(email_, pass_).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull final Task<AuthResult> task) {
                    if (task.isSuccessful()) {

                        //Toast.makeText(LoginActivity.this, "Login Successful, continue to email verified", Toast.LENGTH_LONG).show();
                        Log.i(TAG, "Login Successful, continue to email verified");

                        if (task.getResult().getUser().isEmailVerified()) {

                            //Toast.makeText(LoginActivity.this, "Email is verified Successful, continue to get token", Toast.LENGTH_LONG).show();
                            Log.i(TAG, "Email is verified Successful, continue to get token");

                            //final String token_id = FirebaseInstanceId.getInstance().getToken(); Deprecated
                            // FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( LoginActivity.this,  new OnSuccessListener<InstanceIdResult>() {
                            FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                                @Override
                                public void onComplete(@NonNull Task<InstanceIdResult> task2) {
                                    if (!task2.isSuccessful()) {
                                        Log.w(TAG, "getInstanceId failed", task2.getException());
                                        return;
                                    }

                                    // Get new Instance ID token
                                    String token_id = task2.getResult().getToken();


                                    Log.i(TAG, "Get Token Listener, Token ID (token_id): " + token_id);

                                    final String current_id = task.getResult().getUser().getUid();

                                    mFirestore.collection("Users").document(current_id).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                                        @Override
                                        public void onSuccess(DocumentSnapshot documentSnapshot) {
                                            if (!override) {
                                                if (documentSnapshot.getString("token_id").equals(token_id) || documentSnapshot.getString("token_id").equals("")) {

                                                    Map<String, Object> tokenMap = new HashMap<>();
                                                    tokenMap.put("token_id", token_id);

                                                    mFirestore.collection("Users").document(current_id).update(tokenMap).addOnSuccessListener(new OnSuccessListener<Void>() {
                                                        @Override
                                                        public void onSuccess(Void aVoid) {

                                                            FirebaseFirestore.getInstance().collection("Users").document(current_id).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                                                                @Override
                                                                public void onSuccess(DocumentSnapshot documentSnapshot) {

                                                                    String username = documentSnapshot.getString("username");
                                                                    String name = documentSnapshot.getString("name");
                                                                    String email = documentSnapshot.getString("email");
                                                                    String image = documentSnapshot.getString("image");
                                                                    String password = pass_;
                                                                    String location = documentSnapshot.getString("location");
                                                                    String bio = documentSnapshot.getString("bio");

                                                                    // TODO Added Qiscus login here
                                                                    userHelper.insertContact(username, name, email, image, password, location, bio);
                                                                    loginPresenter.login(name, email, password);

                                                                    // TODO Add to Override option
                                                                    // Original placement of functions:
                                                                    mDialog.dismiss();
                                                                    MainActivity.startActivity(LoginActivity.this);
                                                                    finish();

                                                            }

...

这是我的FCM代码......

public class FCMService extends FirebaseMessagingService {

    private static final String TAG = FCMService.class.getSimpleName();

    private NotificationUtil notificationUtils;
    private String cDesc;


    @Override
    public void onNewToken(String token) {
        super.onNewToken(token);
        Log.d("NEW_TOKEN",token);

        //String refreshedToken = FirebaseInstanceId.getInstance().getToken(); 
        // Deprecated
        storeRegIdInPref(token);
        sendRegistrationToServer(token);

        Intent registrationComplete = new Intent(Config.REGISTRATION_COMPLETE);
        registrationComplete.putExtra("token", token);
        LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
    }


    private void sendRegistrationToServer(final String token) {
        Log.i(TAG, "sendRegistrationToServer:" + token);
    }

    private void storeRegIdInPref(String token) {
        SharedPreferences pref = getApplicationContext().getSharedPreferences(Config.SHARED_PREF, MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        editor.putString("regId", token);
        editor.apply();
    }




    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        handleDataMessage(remoteMessage);
    }

   }

...

(编辑)Firestore Database Structure

我很欣赏弗兰克的答案,但这是我数据库的结构。我知道我可能需要重构我的数据库,以便它可以同时保存多个token_id,以便朋友/评论者云功能可以执行删除产生错误的令牌的工作。但我坦率地说不知道该怎么做。欢迎任何帮助或网站。

node.js firebase google-cloud-firestore firebase-cloud-messaging
1个回答
0
投票

在你的问题中有太多的代码,所以我没有阅读所有的代码。但是错误消息的要点是您正在向FCM发送一个不是(或不再知道)的实例ID令牌。您需要从所谓的令牌注册表中删除令牌,通常只是您保留令牌的数据库。

我最喜欢的example of how to remove expired tokens is in the functions-samples repo

  tokens = Object.keys(tokensSnapshot.val());
  // Send notifications to all tokens.
  const response = await admin.messaging().sendToDevice(tokens, payload);
  // For each message check if there was an error.
  const tokensToRemove = [];
  response.results.forEach((result, index) => {
    const error = result.error;
    if (error) {
      console.error('Failure sending notification to', tokens[index], error);
      // Cleanup the tokens who are not registered anymore.
      if (error.code === 'messaging/invalid-registration-token' ||
          error.code === 'messaging/registration-token-not-registered') {
        tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
      }
    }
  });
  return Promise.all(tokensToRemove);

上面的代码调用sendToDevice(...),然后解析过期令牌错误的结果。然后它会从数据库中删除这些令牌,这样它们就不会一直导致错误。

© www.soinside.com 2019 - 2024. All rights reserved.