There is another way to solve this problem using Cloud Firebase Functions.
How will I distinguish which token to change as all will be belonging
to the same user?
Using Firebase Functions, you don't have to. Within onTokenRefresh(), you send the new token to the server.
For Example:
The user has 3 devices, each of which have a token that has been sent to server.
*** deviceTokenA/B/C represent UIDs of the token ... we do not know what they are, or which device they belong to.
UserId:
Device Tokens:
deviceTokenA: true,
deviceTokenB: true,
deviceTokenC: true,
Now, the User is on the device that triggered deviceTokenA. The token is refreshed, and onTokenRefresh() is called, sending the token to that collection.
onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
sendTokenToServer(refreshedToken);
}
sendTokenToServer(String refreshedToken) {
// send to Firebase or Firestore Database, put in the Device_Tokens collection. }
Now, you will have 4 tokens in the collection.
UserId:
Device Tokens:
deviceTokenA: true, // this one has been "unregistered"
deviceTokenB: true,
deviceTokenC: true,
deviceTokenD: true, // this one has been registered.
The deviceTokenA no longer applies, because it was refreshed, and is not attached to an actual device anymore.
When looking at the device Tokens, we still don't know which ones are good, which are bad, and which tokens belong to which device. That's ok!
So, then create a forEach loop, getting each Token, and then send an FCM to each of these Tokens, FCM can let us know which tokens were sent successfully. One of them will return an error. If it returns an error saying the token was bad, we can then catch the error and delete that token, so it will not be called again.
// outside for Each loop
var promiseHolder = [];
// create a forEach loop, iterating through the collection of deviceTokens
// within that loop, put:
let innerPromise = admin.messaging().send(message)
.then(response => {
console.log('notification sent success: ' + response);
})
.catch((error) => {
console.log('Error sending notification: ' + error);
// if the error == bad token message, then Delete the Token.
if (error == 'Error: Requested entity was not found.') {
console.log('you matched the error, token doesn't work, handle here.');
//delete the old token
return admin.firestore()doc(`users/${userID}/device_tokens/${token_id}`).delete();
}
}
// still within forEach loop
promiseHolder.push(innerPromise);
// end the forEach Loop, and outside forEachLoop put:
return Promise.all(promiseHolder);