我正在开发一个以Firebase作为后端的reactJS网站。我为用户提供的主要服务之一是每天通知。我已经实现了一个代码来请求权限,如果他们授予访问权限,则将它们存储到我的数据库中。但过了一段时间,我注意到代币即将到期。我对此进行了研究,并发现了onTokenRefresh((方法。我也实现了。但我相信出于某种原因,它无法正常工作。如果令牌过期,我不会获得新令牌。我将粘贴下面我正在尝试执行的操作的代码段。
在主页上,
if (!("Notification" in window)) {
//alert("This browser does not support desktop notification");
}
// Check whether notification permissions have already been granted
else if (Notification.permission === "granted") {
// Refresh logic here
this.checkForRefreshToken();
}
// Otherwise, ask the user for permission
else if (Notification.permission !== "denied") {
//Ask user here, then call another function for storing token
this.addNewToken()
}
如果用户第一次接受通知,我调用addNewToken((方法
addNewToken = () => {
this.auth.onAuthStateChanged(authUser => {
const messaging = firebase.messaging();
messaging
.requestPermission()
.then(() => {
return messaging.getToken();
})
.then(token => {
firebase.database().ref('tokens').once('value')
.then(snapshots => {
let tokenExist = false
snapshots.forEach(childSnapshot => {
// console.log("Child snapshot: ", childSnapshot.key);
if (childSnapshot.val().token === token) {
tokenExist = true
return console.log('Device already registered.');
}
})
if (!tokenExist) {
// console.log('Device subscribed successfully');
return firebase.database().ref('tokens').push(token);
}
})
})
.catch(error => {
if (error.code === "messaging/permission-blocked") {
// console.log("Please Unblock Notification Request Manually");
} else {
// console.log("Error Occurred", error);
}
});
})
}
现在,如果用户已经订阅,我正在检查是否调用了onTokenRefresh((,基本上是令牌是否需要刷新。
checkForRefreshToken = () => {
this.auth.onAuthStateChanged(authUser => {
const messaging = firebase.messaging();
messaging.onTokenRefresh(() => {
messaging.getToken().then((refreshedToken) => {
const token = refreshedToken;
firebase.database().ref('tokens').once('value')
.then(snapshots => {
let tokenExist = false
snapshots.forEach(childSnapshot => {
if (childSnapshot.val().token === token) {
tokenExist = true
return console.log('Device already registered.');
}
})
if (!tokenExist) {
return firebase.database().ref('device_ids').push(token);
}
})
})
})
})
}
我不知道这里出了什么问题,但我无法获得新的代币。
出于测试目的,我有自己的令牌过期设备,我部署了此代码并在设备上打开了我的网站,刷新了页面等,但没有获得新令牌。
此外,如果有人可以帮助我如何在本地测试过期的令牌,那就太好了。 我为应用程序找到了不同的方法,但没有为网站(javascript(找到不同的方法。
谢谢
>auth.onAuthStateChanged(...)
将事件侦听器添加到事件中,以指示身份验证状态的更改。在上面的代码中,您希望立即评估addNewToken
和checkForRefreshToken
的代码,但它们只是添加新的事件侦听器。这同样适用于onTokenRefresh()
。
因此,将addNewToken()
返工为按需函数会产生:
requestMessagingToken = () => {
let authUser = this.auth.currentUser;
if (!authUser) {
console.log("Not logged in!");
return Promise.resolve(false); // silently ignore & fail
}
const messaging = firebase.messaging();
return messaging
.requestPermission()
.then((permission) => {
if (permission !== 'granted') {
throw 'insufficient permissions'; // notification permission was denied/ignored
}
return messaging.getToken();
})
.then(token => saveMessagingTokenForUser(authUser.uid, token))
.catch(error => {
if (error && error.code === "messaging/permission-blocked") {
// console.log("Please Unblock Notification Request Manually");
} else {
// console.log("Error Occurred", error);
}
return false; // silently fail
});
};
这还有一个额外的好处,即能够使用以下方法轻松处理身份验证状态更改:
this.auth.onAuthStateChanged(requestMessagingToken);
获得发送通知的权限后,可以使用以下命令激活刷新的令牌侦听器:
const messaging = firebase.messaging();
messaging.onTokenRefresh(() => {
let authUser = this.auth.currentUser;
if (!authUser) {
console.log("Not logged in!");
return; // ignore
}
messaging.getToken().then((refreshedToken) => {
return saveMessagingTokenForUser(authUser.uid, refreshedToken);
}).catch((err) => {
console.log('Unable to retrieve/store messaging token ', err);
});
});
最后,若要将令牌保存到数据库,可以使用令牌本身作为密钥,而不是在数据库中搜索匹配的设备令牌作为推送 ID 的值。此外,为了使过时的令牌管理更容易,最好按用户拆分令牌。
"userData": {
"userId1": {
"tokens": {
"deviceToken1": true,
"deviceToken2": true,
"deviceToken3": true,
},
...
},
"userId2": {
"tokens": {
"deviceToken4": true,
"deviceToken5": true
},
...
},
...
}
使用此结构,您可以使用事务来检查数据是否已存储在数据库中,并使用云函数检查无效令牌。
saveMessagingTokenForUser = (uid, token) => {
return firebase.database().ref('userData/' + uid + '/tokens/' + token)
.transaction((currentData) => {
if (currentData != null) {
console.log('Device already registered.');
return; // abort transaction, no changes needed
} else {
console.log('Saving token to database.');
return true;
}
})
.then(() => true); // no errors = success
};
在服务器上,您可以运行 Cloud Function,侦听添加到数据库的新设备令牌,并检查该用户的其他设备令牌是否过期。
exports.checkUserForOutdatedTokens = functions.database.ref('/userData/{userId}/tokens/{tokenId}')
.onCreate((newTokenSnapshot, context) => {
return newTokenSnapshot.ref.once('value')
.then((tokensSnapshot) => {
let tokens = Object.keys(tokensSnapshot.val());
const message = {
data: {heartbeat: true},
tokens: tokens,
}
return admin.messaging().sendMulticast(message)
.then((response) => {
if (response.failureCount > 0) {
const dataToDelete = {};
response.responses.forEach((resp, idx) => {
if (!resp.success) {
dataToDelete[tokens[idx]] = null;
}
});
console.log('List of tokens that caused failures: ' + Object.keys(dataToDelete));
return tokensSnapshot.ref.update(dataToDelete); // deletes failed tokens
}
});
});
});