How to change Firebase topic for some users in specified time? - android

We have an Android education app and we use FCM Topic Messaging for sending specific notifications to each user. We categorized each user according to academic year.
Now, we have one problem for topic messaging, in the specified time, these students goes to one level higher and if we don't change the topic in Firebase for new academic year, it gives the last year notification.
How can we do this? Does Firebase have a solution for this problem? Thanks <3

This can be done through your App Server by using the InstanceID API.
You can batchAdd the corresponding tokens to the new topic (i.e. academicy year) you need, then batchRemove them from the old topic (i.e. last year).
From the link above:
Manage relationship maps for multiple app instances
Using the Instance ID service's batch methods, you can perform batch management of app instances. For example, you can perform bulk addition or removal of app instances to an FCM or GCM topic. To manage app instances, call the Instance ID service at this endpoint, providing the app instance tokens in the JSON body:
https://iid.googleapis.com/iid/v1:batchAdd
https://iid.googleapis.com/iid/v1:batchRemove
Parameters
Authorization: key=YOUR_API_KEY. Set this parameter in the header.
to : The topic name.
registration_tokens : The array of IID tokens for the app instances you want to add or remove.
Results
On success the call returns HTTP status 200. Empty results indicate successful subscription for the token. For failed subscriptions, the result contains one of these error codes:
NOT_FOUND — The registration token has been deleted or the app has been uninstalled.
INVALID_ARGUMENT — The registration token provided is not valid for the Sender ID.
INTERNAL — The backend server failed for unknown reasons. Retry the request.
TOO_MANY_TOPICS — Excessive number of topics per app instance.
Example POST request
https://iid.googleapis.com/iid/v1:batchAdd
Content-Type:application/json
Authorization:key=API_KEY
{
"to": "/topics/movies",
"registration_tokens": ["nKctODamlM4:CKrh_PC8kIb7O...", "1uoasi24:9jsjwuw...", "798aywu:cba420..."],
}
Example result
HTTP 200 OK
{
"results":[
{},
{"error":"NOT_FOUND"},
{},
]
}

Related

How to test Google Play Real Time Notifications for Subscriptions?

I'm trying to implement in-app subscriptions in my app. So ,first I set upped the real time notifications. But the problem is that I can't test them for in-app subscriptions. Can anyone help me with this? Let me describe what I have.
I created the topic
Created the subscription in that topic
Added the endpoint in the subscription
Added topic name in the play.google.com in the Services and APIs section
Added the endpoint on my server, so I can receive the requests
When I hit the SEND TEST NOTIFICATION button, I can successfully receive the request, but the problem is that the request has no any values, as described here.
https://developer.android.com/google/play/billing/realtime_developer_notifications
According to link,
Each publish made to a Pub/Sub topic contains a single base64-encoded DeveloperNotification with the following fields:
{
"version": string,
"packageName": string
"eventTimeMillis": long
"oneTimeProductNotification": OneTimeProductNotification
"subscriptionNotification": SubscriptionNotification
"testNotification": TestNotification
}
and
A TestNotification contains the following fields:
{
"version": string
}
So my question is , how can test this Json? I mean why the request has no values ?
Thanks.
Sorry Guys.
I found the problem.
I was trying to get the fields in the wrong way. As my server technology is PHP,I was trying to get from $_POST array, but the right way is
$result = file_get_contents("php://input");

FCM TOPIC Creation in APP Server

Recently I migrated from GCM to FCM for sending the notification via my app, i want to know whether can able to subscribe the members in particular topic from my app server. If possible, then how will find out if a particular member token valid or expired.
Because in my database, i have near to 22L people GCM Registration TOKEN id, so that i will create one topic and subscribe those members via my app server.
Any ideas to resolve this kind of issues.
You can subscribe multiple tokens to Topic via your App Server using the Instance ID API, specifically, using batchAdd. It can also identify if the Registration Token that you were subscribing is invalid by returning a NOT_FOUND error. From the docs:
Manage relationship maps for multiple app instances
Using the Instance ID service's batch methods, you can perform batch management of app instances. For example, you can perform bulk addition or removal of app instances to an FCM or GCM topic. To manage app instances, call the Instance ID service at this endpoint, providing the app instance tokens in the JSON body:
https://iid.googleapis.com/iid/v1:batchAdd
https://iid.googleapis.com/iid/v1:batchRemove
Parameters
Authorization: key=YOUR_API_KEY. Set this parameter in the header.
to : The topic name.
registration_tokens : The array of IID tokens for the app instances you want to add or remove.
Results
On success the call returns HTTP status 200. Empty results indicate successful subscription for the token. For failed subscriptions, the result contains one of these error codes:
NOT_FOUND — The registration token has been deleted or the app has been uninstalled.
INVALID_ARGUMENT — The registration token provided is not valid for the Sender ID.
INTERNAL — The backend server failed for unknown reasons. Retry the request.
TOO_MANY_TOPICS — Excessive number of topics per app instance.
Example POST request
https://iid.googleapis.com/iid/v1:batchAdd
Content-Type:application/json
Authorization:key=API_KEY
{
"to": "/topics/movies",
"registration_tokens": ["nKctODamlM4:CKrh_PC8kIb7O...", "1uoasi24:9jsjwuw...", "798aywu:cba420..."],
}
Example result
HTTP 200 OK
{
"results":[
{},
{"error":"NOT_FOUND"},
{},
]
}

How to structure a notification system for a chat app using Firebase Database and Firebase Notification

I'm developing a chat application using Firebase Database in Android.
I've already done the core (chat and user's list activities), but I have yet to do the notification system.
What I want is that when a user is added to a conversation (single or group) and another user writes a new message to the conversation, the first user has to receive a notification that if clicked opens the conversation activity.
My big dilemma is how to structure the service that runs in background to receive the push notification or to listen to the firebase database node I need to look at to know if there are any messages.
I figured out two different approaches:
Approach 1) Use the firebase notification
With this approach I simply send a data notification from the sender client to all the other clients in the conversation when the sender sends a message, and so the receiver will decide to show the notification (if the chat activity it's not opened) and handle the click action.
With this approach I think I will save CPU consumption and then battery.
What I don't understand is how to register a user to receive a group notification (topic notification) because as I understood, I have to subscribe that client to the topic, but if the application is in background or close, how does it knows that a new group, with its user inside, has been created and so it has to subscribe to the topic?
For the two-users conversation scenario this is not a problem as I can send the notification directly to the destination user without needing him to be subscribed to any topic.
Approach 2) Listen to a firebase database data node with a background service
With this approach I just need to create a bootable service that listen to a specific node of the database (with ValueEventListener) and show a notification when data shows that a new message/conversation is coming.
An example of the node to listen to, can be the data about the unseen messages as following:
conversation_user_unseen_messages
$conversationId1
$user1: 3
$conversationId2
$user2: 1
Then, if the data shows new messages/conversations the android app client will decide to show a system notification.
I think that with this approach there will be more energy consumption as it has to constantly check if there are any new message on the db.
Final consideration
I have found a very useful guide written by the mythical Frank van Puffelen,that explains how to set up the system I need, with using an additional server side component (node.js server).
My last question is: do I need to set up a server? Is a better solution than handling everything by the clients (using for example http requests)?
What solution do you think is the best?
Many thanks.
EDIT
I'm still figuring it out, but here it is some consideration.
I have to requesting and using a InstanceID
Instance ID provides a unique ID per instance of your apps.
So i have to request an InstanceID when user is connected and the InstanceId it is avalaible.
And then don't use topics.
Topic messages are optimized for throughput rather than latency. For
fast, secure delivery to single devices or small groups of devices,
target messages to tokens, not topics.
as said in the topic messagin guide that instead suggests to target message to tokens .
To do so I have to collect the user token in my user database reference:
users: {
$userId1: {
name: "John",
email: "john#gmail.com",
token: "Ax8HiP3Edf7....",
}
}
and then when my app client send a new message it has to also has to send a notification for all users involved in the chat, thing that I already can do with my current db structure.
How do I handle and collect the requests?
I implement a node.js server app that connect to Firebase Database and listens for the notification requests made by the app and then sends the notification request by http call to every destination app.
When do I have to register the user token?
When a app client starts for the first time or when the InstanceID expire (onTokenRefresh).
Is this the right way to do it?
EDIT 2
I found a big hole in the FCM implementation. It seems that I can not handle at all notifications delivered to iOs apps that are not in foreground.
As found in the Data notification documentation
On iOS, FCM stores the message and delivers it only when the app is in the foreground and has established a FCM connection. On Android, a client app receives a data message in onMessageReceived() and can handle the key-value pairs accordingly.
And I need to catch the data notification even when the app is in background, I need that specifically because I want to update my badge counter on the app icon to let the user know how many unread messages he has.
I'm now tryng the OneSignal solution can receive notification even when in background, it's free and interfaces with GCM. I'm sad to not stay with Google but if I can't update the badge count using FCM I have to look to an other side.
Any consideration will be appreciated.
Approach 1 is the one that you should use. Frank's guide is using the first approach, so you need to set up a server.
Is it a better solution than handling everything by the clients (using for example http requests)?
Yes. If you send the notification in the client (the app), your API Key will be exposed (via network sniffing or reverse engineering) and you definitely would want to avoid that.
how to subscribe a user to a new group topic if the app is closed or in the background?
Looks like you have to create relation mapping on the server, by calling https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME with Authorization: key=YOUR_API_KEY as the header, the full description is here. Follow this guide to get the Instance ID token.
I hope my answer answers your questions. Cheers :)
Now you can simply achieve this using firebase functions ...
Here's mine
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendFollowerNotification =
functions.database.ref('/whatever/{groupUID}/{userUID}/{todoUID}')
.onWrite(async (change, context) => {
const useruuid = context.params.userUID;
const thisdata = change.after.val();
console.log('sendto:'+useruuid);
var ref = admin.database().ref(`userdatas/${useruuid}/phonetkn`);
return ref.once("value", function(snapshot){
const payload = {
notification: {
image: "default",
sound:"default",
vibrate:"true" ,
title: 'New Mission !',
body: thisdata.titre ,
color: '#22c064',
icon: "notification_icon"
}
};
admin.messaging().sendToDevice(snapshot.val(), payload)
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
});
//

Receive messages from 2 different senders in FCM [duplicate]

I want to be able to add more than one sender id in my android app.
From https://developers.google.com/cloud-messaging/concept-options
GCM allows multiple parties to send messages to the same client app. For example, suppose the client app is an articles aggregator with multiple contributors, and each of them should be able to send a message when they publish a new article. This message might contain a URL so that the client app can download the article. Instead of having to centralize all sending activity in one location, GCM gives you the ability to let each of these contributors send its own messages.
How is this achieved using google-services.json configuration file?
UPDATE: Going to refer to the official and recommended way in doing this instead of the hacky and unofficial approach to prevent/avoid unknown problems. From my answer here.
There is actually a part in the documentation about this topic:
Receiving messages from multiple senders
FCM allows multiple parties to send messages to the same client app. For example, suppose the client app is an article aggregator with multiple contributors, and each of them should be able to send a message when they publish a new article. This message might contain a URL so that the client app can download the article. Instead of having to centralize all sending activity in one location, FCM gives you the ability to let each of these contributors send its own messages.
To make this possible, make sure each sender generates its own sender ID. See the client documentation for your platform for information on on how to obtain the FCM sender ID. When requesting registration, the client app fetches the token multiple times, each time with a different sender ID in audience field.
Finally, share the registration token with the corresponding app servers (to complete the FCM registration client/server handshake), and they'll be able to send messages to the client app using their own authentication keys.
Note that there is limit of 100 multiple senders.
I think the confusing but important part here is:
When requesting registration, the client app fetches the token multiple times, each time with a different sender ID in audience field.
In other terms, you'll have to call getToken() passing the Sender ID and simply "FCM" (e.g. getToken("2xxxxx3344", "FCM")) as the parameters. You'll have to make sure that you call this for each sender (project) that you need.
Also, note from the getToken() docs:
This is a blocking function so do not call it on the main thread.
Some additional good-to-knows:
It does not auto retry if it fails like the default one.
It returns an IOException when it fails.
As of Dec. 2016, there's a very simple, non-hacky way to do this, which still works now (Jul 2018).
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("1:something:android:something_else") // Required for Analytics.
.setApiKey("your apikey") // Required for Auth.
.setDatabaseUrl("https://your-database.firebaseio.com/") // Required for RTDB.
.build();
FirebaseApp.initializeApp(this /* Context */, options, "secondary");
Source: The official Firebase blog
Comma seperated senderID solution is still working and able to register same token for 2 different sender. I sent push notif to that single magical token with using 2 different api key and able to receive push notifs for both api key. Hope it works at least till the end of 2020. Because I'm trying to make a seamless transition between an old GCM and FCM projects which targets more than 1 million user. (hear me google and thank you google for not deprecating this great solution)
String magicalToken = FirebaseInstanceId.getInstance().getToken("senderId, anotherSenderId", "FCM");
You can get the single token for multiple sender by passing them as comma separated string and then these sender will be able to send the push notification using the common token, try calling
FirebaseInstanceId.getInstance() .getToken("senderId1,senderId2",
FirebaseMessaging.INSTANCE_ID_SCOPE);
make sure you call this from a background thread.

How to put multiple project_number/sender id in google-services.json

I want to be able to add more than one sender id in my android app.
From https://developers.google.com/cloud-messaging/concept-options
GCM allows multiple parties to send messages to the same client app. For example, suppose the client app is an articles aggregator with multiple contributors, and each of them should be able to send a message when they publish a new article. This message might contain a URL so that the client app can download the article. Instead of having to centralize all sending activity in one location, GCM gives you the ability to let each of these contributors send its own messages.
How is this achieved using google-services.json configuration file?
UPDATE: Going to refer to the official and recommended way in doing this instead of the hacky and unofficial approach to prevent/avoid unknown problems. From my answer here.
There is actually a part in the documentation about this topic:
Receiving messages from multiple senders
FCM allows multiple parties to send messages to the same client app. For example, suppose the client app is an article aggregator with multiple contributors, and each of them should be able to send a message when they publish a new article. This message might contain a URL so that the client app can download the article. Instead of having to centralize all sending activity in one location, FCM gives you the ability to let each of these contributors send its own messages.
To make this possible, make sure each sender generates its own sender ID. See the client documentation for your platform for information on on how to obtain the FCM sender ID. When requesting registration, the client app fetches the token multiple times, each time with a different sender ID in audience field.
Finally, share the registration token with the corresponding app servers (to complete the FCM registration client/server handshake), and they'll be able to send messages to the client app using their own authentication keys.
Note that there is limit of 100 multiple senders.
I think the confusing but important part here is:
When requesting registration, the client app fetches the token multiple times, each time with a different sender ID in audience field.
In other terms, you'll have to call getToken() passing the Sender ID and simply "FCM" (e.g. getToken("2xxxxx3344", "FCM")) as the parameters. You'll have to make sure that you call this for each sender (project) that you need.
Also, note from the getToken() docs:
This is a blocking function so do not call it on the main thread.
Some additional good-to-knows:
It does not auto retry if it fails like the default one.
It returns an IOException when it fails.
As of Dec. 2016, there's a very simple, non-hacky way to do this, which still works now (Jul 2018).
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("1:something:android:something_else") // Required for Analytics.
.setApiKey("your apikey") // Required for Auth.
.setDatabaseUrl("https://your-database.firebaseio.com/") // Required for RTDB.
.build();
FirebaseApp.initializeApp(this /* Context */, options, "secondary");
Source: The official Firebase blog
Comma seperated senderID solution is still working and able to register same token for 2 different sender. I sent push notif to that single magical token with using 2 different api key and able to receive push notifs for both api key. Hope it works at least till the end of 2020. Because I'm trying to make a seamless transition between an old GCM and FCM projects which targets more than 1 million user. (hear me google and thank you google for not deprecating this great solution)
String magicalToken = FirebaseInstanceId.getInstance().getToken("senderId, anotherSenderId", "FCM");
You can get the single token for multiple sender by passing them as comma separated string and then these sender will be able to send the push notification using the common token, try calling
FirebaseInstanceId.getInstance() .getToken("senderId1,senderId2",
FirebaseMessaging.INSTANCE_ID_SCOPE);
make sure you call this from a background thread.

Categories

Resources