We have developed an app in iOS and Android which stores the FCM tokens in a database in order to send PUSH notifications depending on the user configuration.
Users install the app and the token of every device is stored in the database, so we would like to know what of those tokens are invalid because the app has been uninstalled.
On the other hand, we send the notifications through the website using JSON. Is there any limitation (I mean, is there any limit of elements in a JSON request)?
Thank you very much!
I recently noticed that step 9 in the Cloud Functions codelab uses the response it gets from the FCM API to remove invalid registration tokens from its database.
The relevant code from there:
// Get the list of device tokens.
return admin.database().ref('fcmTokens').once('value').then(allTokens => {
if (allTokens.val()) {
// Listing all tokens.
const tokens = Object.keys(allTokens.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// 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(allTokens.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}
});
I quickly checked and this same approach is also used in the Cloud Functions sample for sending notifications.
Related
I am building an Android App, using Firebase as Backend. Firebase will be used for authentication, storage, some data in firebase database, and also using cloud functions.
There are subsriptions in my app with Google Play Billing Library v5.
After the subscription is purchased and acknowledged, I'd like to do some server side verification, where my problems begin. I have created cloud function - thank you guys - that listens to pub/sub topic and to verify the subscription I call the google api - Method: purchases.subscriptionsv2.get . After the successful response, I'd like to write this data to my database.
Response I get is ok in the form of JSON object like here
This is the function:
exports.insertFromPubSubTopic = functions.pubsub.topic('mytopic').onPublish(async(message, context) => {
if (message.json.subscriptionNotification) {
console.log("ok - we have message.json.subscriptionNotification")
try {
await authClient.authorize();
const subscription = await playDeveloperApiClient.purchases.subscriptionsv2.get({
packageName: data.packageName,
token: data.subscriptionNotification.purchaseToken
});
if (subscription.status === 200) {
// Subscription response is successful.
console.log("subscription.status===200")
var message = {
'data': data
}
return firestore.collection('billing-verified').add(message)
}
} catch (error) {
// Logging error for debugging
console.log(error)
}
return {
status: 500,
message: "Failed to verify subscription, Try again!"
}
} else {
console.log('Test event... logging test');
//return admin.firestore().collection('mp-billing-messages-error').add(data)
return firestore.collection('mp-billing-messages-error').add(data)
}
})
My question is: How do I get user's data from successfully returned subscription object, so that I can store in firestore database something like - this purchase was made by this user.
I know Firebase and GooglePlayBilling are not related and have different purposes and functionalities. But let's say I have anonymous user who did not login in my app. So I don't know anything about her and cannot identify her in firebase so far. And then she gets and buys the subscription. Does anyone have any suggestions of how do I get the data about this user from verified purchased object?? Any suggestion would be helpful.
In our project, we activated cloud functions and deployed a function into the cloud to notify all the clients whenever a Remote Config value has changed on firebase remote config.
Cloud function:
exports.pushConfig = functions.remoteConfig.onUpdate(versionMetadata => {
// Create FCM payload to send data message to PUSH_RC topic.
const payload = {
topic: "PUSH_RC",
data: {
"CONFIG_STATE": "STALE"
}
};
// Use the Admin SDK to send the ping via FCM.
return admin.messaging().send(payload, false).then(resp => {
console.log(resp);
return null;
});
});
And I also have done everything mentioned in
https://firebase.google.com/docs/cloud-messaging/ios/send-image
But still, when I update a key on remote config, I can see that the function is triggered by the firebase from the cloud function logs, but it won't call my client-side function, which is registered to messaging.
I have an app where a user can register/login via Firebase. A user can have multiple devices among which all his data is being shared (of course he must be logged in). I keep track of all devices by their firebase device token and send appropriate update notifications when the user updates something on a particular device
Now I know that the firebase token is being refreshed, but how do I know that a token is invalid? Lets say a user has 4 devices where he is logged with one account. Now he delete the app on one of them, and installs it again, so he gets a new token. This means that now I have 5 device tokens on my server but still just 4 devices. The best approach would be to tie a token to some non-changeable device id like MAC oder IMEI but because of privacy policies that is not possible.
Is there some other way to fish out the tokens that have been revoked/invalidated?
The common way to detect expired/revoked FCM tokens is during sending of messages. FCM will at that point tell you exactly which tokens have expired, and you can then remove them from your database.
For an example of this, see this Node.js code from the 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);
I have just started learning react-native and thinking of integrating firebase to it. Now consider my question scenario:
There are two users A & Bwho have the react app running in their device( none of them are admin). Now I have studied that when we connect our react native app to firebase, every instance of the app running on a device gets a unique token and that token is stored in firebase itself.
Now suppose user A wants to send a " notification or message" to user B. Now see the below code I saw on firebase official website:
// This registration token comes from the client FCM SDKs.
var registrationToken = 'YOUR_REGISTRATION_TOKEN';
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
This method seems quite straightforward, but is there really any method using which user A can know the unique token of user B like this:
const token= firebase.getToken('B');
And then use this token in the above code to send notification to user B. Is it poosible to do it using firebase?
Thank You.
The code you found uses the Firebase Admin SDK to send messages. This SDK grants its users full administrative access to the Firebase project, so can only be used in trusted environments, such as your development machine, a server you control, or Cloud Functions. It cannot be used in the app you send to your users.
You will need a trusted environment to send the messages to the users. For more on this, see:
The Firebase documentation on FCM architecture, which has this handy diagram
How to send one to one message using Firebase Messaging
How to send Device to device notification by using FCM without using XMPP or any other script.?
I am using Cloud Firestore to keep app tokens to send push notifications. However, when the user uninstalls and reinstalls the app, Firestore receives a different token for the same user. How can I delete the relevant row of the previous token when the user uninstalls the app?
Thanks in advance.
Usually you'll want to detect when a token becomes invalid, and remove it at that time. E.g. when a token gets cycled (which happens every few weeks while the user has the app installed), you'll want to use that moment to remove the old token from your database and add the new one. Doing so minimizes the number of outdated tokens you have in your database.
So in steps that means in onTokenRefresh():
Check if there is a token in local storage (e.g. shared preferences). If so, remove that token from both the database and local storage.
Store the new token in both the database and local storage.
But in your case that is not possible, since onTokenRefresh won't be called when the app is uninstalled, and you won't have knowledge of the previous token when it gets reinstalled.
The easiest way to deal with outdated tokens left behind in this and other ways is to delete them when sending to that token fails. The sample of sending FCM notifications using Cloud Functions has a good example of that:
admin
.messaging()
.sendToDevice(tokens, payload)
.then((response) => {
// 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') {
tokensSnapshot.ref.child(tokens[index]).remove();
}
}
});
});
It's quite simple, when the user reinstalls the app and logs in again, just override the old token with the new one. If you have also other stuff that needs to be deleted once the new token is generated, just check the existing token with the new one. If the tokens are different, you may delete all the unnecessary stuff.