Мне нужна помощь. Облачные функции, написанные в файле node.js, выдают ошибки и не вызывают push-уведомлений (оповещателей) для оповещения в моем java-приложении Android о том, что был сделан комментарий или что пользователю понравилась запись. На консоли Firebase мне удалось получить сообщение об ошибке в журнале облачных функций:
Successfully sent message: { results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 7952971403531609000 }
Когда я просматриваю сообщение об ошибке в журнале Firebase Cloud Functions, я также получаю следующее:
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
Я ценю ответ Фрэнка, но вот структура моей базы данных. Я понимаю, что мне может понадобиться реструктурировать мою базу данных, чтобы она могла одновременно хранить несколько идентификаторов token_ids, чтобы облачные функции друзей / комментатора могли выполнять работу по удалению токенов, которые выдают ошибку. Но, честно говоря, я не знаю, как это сделать. Любая помощь или сайт приветствуется.