简体   繁体   English

Firebase云功能令牌

[英]Firebase Cloud Functions Tokens

I need help. 我需要帮助。 Cloud functions written in node.js are throwing errors and not causing push notifications (alerter) to alert in my Android java app that a comment has been made or that a user has liked a post. 在node.js中编写的云函数抛出错误并且不会导致推送通知(警报器)在我的Android java应用程序中警告已发表评论或用户喜欢帖子。 On Firebase Console, I was able to get the error message in cloud functions log: 在Firebase控制台上,我能够在云功能日志中收到错误消息:

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

When I view the error message on Firebase Cloud Functions log, I also get the following: 当我在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' }

The message is very clear: A previously valid registration token can be unregistered for a variety of reasons. 消息非常清楚:出于各种原因,可以取消注册以前有效的注册令牌。 I have seen other posts on these error topics but none outlines exactly how to treat and use tokens during registration and login. 我已经看到有关这些错误主题的其他帖子,但没有一个概述在注册和登录期间如何处理和使用令牌。

Here is the Firebase Cloud Function Code ... 这是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);
            });


           }

          });
    });

});

... ...

Here is in the RegisterActivity.java 这是在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();
                                                                                   } 

... ...

Here is in the LoginActivity.java 这是在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();

                                                            }

... ...

Here's my code for FCM ... 这是我的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);
    }

   }

... ...

(Edit) Firestore Database Structure (编辑) Firestore数据库结构

I appreciate Frank's answer but here is the structure of my database. 我很欣赏弗兰克的答案,但这是我数据库的结构。 I understand that I may need to restructure my database so that it can hold multiple token_ids at once so that the friends/commenter cloud functions can do the work of deleting the tokens that produce error. 我知道我可能需要重构我的数据库,以便它可以同时保存多个token_id,以便朋友/评论者云功能可以执行删除产生错误的令牌的工作。 But I quite frankly don't know how to do that. 但我坦率地说不知道该怎么做。 Any help or website welcomed. 欢迎任何帮助或网站。

There is way too much code in your question, so I didn't read all of it. 在你的问题中有太多的代码,所以我没有阅读所有的代码。 But the gist of the error message is that you're sending an instance ID token to FCM that is not (or no longer known). 但是错误消息的要点是您正在向FCM发送一个不是(或不再知道)的实例ID令牌。 You will need to remove the token from your so-called token registry , usually simply the database where you keep the tokens. 您需要从所谓的令牌注册表中删除令牌,通常只是您保留令牌的数据库。

My favorite example of how to remove expired tokens is in the functions-samples repo : 我最喜欢的删除过期令牌的例子是在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);

The above code calls sendToDevice(...) , and then parses the results for expired token errors. 上面的代码调用sendToDevice(...) ,然后解析过期令牌错误的结果。 It then deletes those tokens from the database, so that they won't keep causing errors. 然后它会从数据库中删除这些令牌,这样它们就不会一直导致错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM