我需要帮助。node.js编写的云功能正在抛出错误,并且不会在我的Android java应用程序中引起推送通知(警报)提醒已发表评论或用户喜欢帖子。在Firebase Console上,我能够在云功能日志中获取错误消息:
Successfully sent message: { results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 7952971403531609000 }
当我在Firebase Cloud函数日志上查看错误消息时,我还得到以下信息:
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);
});
}
});
});
});
...
这里是注册活动。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_ID,以便friends/commenter cloud函数可以删除产生错误的token。但坦率地说,我不知道该怎么做。欢迎任何帮助或网站。
您的问题中代码太多,所以我没有全部阅读。但错误消息的要点是您正在向FCM发送一个不(或不再知道)的实例ID令牌。您需要从所谓的令牌注册表中删除令牌,通常只是保存令牌的数据库。
关于如何删除过期令牌,我最喜欢的例子是函数-样本
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(…)
,然后分析过期令牌错误的结果。然后,它会从数据库中删除这些令牌,这样它们就不会一直导致错误。
问题 你构建了一个自定义容器对象,里面包含有列表、元组或其他可迭代对象。 你想直接在你的这个新容器对象上执行迭代操作。 解决方案 实际上你只需要定义一个 __iter__() 方法,将迭代操作代理到容器内部的对象上去。比如: class Node: def __init__(self, value): self._value = value self._ch
问题内容: 我在做找零钱的问题。我已经解决了这个问题,因为它会打印出我需要进行最少更改的硬币数量,但是我该如何更改程序以使其也打印那些硬币呢? 这是一个示例: 输入: 输出: 目前,我的代码仅返回。 顺便说一句,这只能通过递归来完成。 不允许循环 码: 问题答案: 程序的其他版本: 输出: PS:如果您愿意,我会添加一个说明。
代币信息API,接口的参数说明请参考Etherscan API 约定, 文档中不单独说明。 通过合约地址获取ERC20 Token总供应量 了解ERC20 代币定义与创建 https://api.etherscan.io/api?module=stats&action=tokensupply&contractaddress=0x57d90b64a1a57749b0f932f1a3395792e12
问题内容: 这是一个从来没有一个正确答案的问题,我已经在网上搜索了很多次,却找不到解决方案。 它适用于Firefox,Chrome。我的responseText将像Réunion这样返回char,它将显示为奇怪的符号。 我尝试了许多方法,例如编码和解码,在响应文件中设置标头都无效。我没主意了。请帮助某人。 在主文件中,确保设置了内容类型和字符集。 在您的AJAX加载页面中,确保您位于顶部。 问题解
用于行内代码片断以及更长的、多行代码的样式。 内联代码 用code包裹内联代码片断。勿忘转义HTML尖括号。 For example, <code><section></code> should be wrapped as inline. 预格式化文本 或者说,代码块,使用<pre>的多行代码文本。再一次提醒,请勿忘转义代码中的所有尖括号,以实现正确的渲染。你可以视情况添加.pre-scrolla
你竟任着刚硬不悔改的心,为自己积蓄忿怒,以致神震怒,显他公义审判的日子来到。他必照各人的行为报应各人。凡恒心行善,寻求荣耀、尊贵和不能朽坏之福的,就以永生报应他们;惟有结党不顺从真理,反顺从不义的,就以忿怒、恼恨报应他们。(ROMANS 2:7-8) 迭代 Bill正在介绍他的项目,嘴里不断蹦出“loop、iterate、traversal、recursion”这些单词,夹杂在汉语汇总。旁边的小白