Send Notification specific logged User Using Firebase Cloud Messeging - android

On my android app have many users but I want to send notification only specific user who is suitable. I don't want to send all users. if a user is already logged on app notification will pop up on the screen.
Need help, Suggestion will be highly appreciatable.

When the device firebase initialized, it will return a device token, which we normally send it the backend so it will be stored in the backend database together with the user id, then later can used for your purpose.

When a user first runs your app Firebase generates a Token for that user and his device. Each time user deletes the app and reinstalls it will re-generate this Token. This also includes new devices of course since that is just like the first installation ever.
What I did with this is that I used the Firebase Realtime database in which I stored this Token for each user I have. Then when I need to send the notification to that user I just get that token and send it within my application. This is one old example on how I did that:
OkHttpClient client = new OkHttpClient();
Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);
JSONObject json = new JSONObject();
JSONObject notifJson = new JSONObject();
JSONObject dataJson = new JSONObject();
notifJson.put("text", body);
notifJson.put("title", title);
dataJson.put("customId", "02");
json.put("notification", notifJson);
json.put("data", dataJson);
json.put("to", firebase_token);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json.toString());
.header("Authorization", "key="+server_key)
.url("https://fcm.googleapis.com/fcm/send")
.post(body)
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) { //do something if notification is sent successfully }
You can do this using your code to send notifications to a specific user. This is, of course, if you want to send a notification from your code. If you want to use a server or something there is documentation you can follow here: https://firebase.google.com/docs/cloud-messaging/android/send-multiple
What I used in this example:
notifJson - notification part
dataJson - data part of notification
body - the body of my notification
title - the title of my notification
firebase_token - Token of user I am sending a notification to, this is retrieved earlier with Firebase real-time database
server_key - Server key from Firebase configuration
In the IF statement below if the response was successful I add some data to my real-time database but you can do anything else you want.

Related

Impossible to create a device group from android device

Since few days my app is not able anymore to create a device group from my android app. According to Firebase docs we should be able to manage device groups from server or client side. I didn't change my app from few years! So I guess something is changed without any reference in the docs. Currently my app does:
JSONObject data = new JSONObject();
data.put("operation", "add");
data.put("notification_key_name", notificationKeyName);
data.put("registration_ids", new
JSONArray(Collections.singletonList(registrationId)));
data.put("id_token", idToken);
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, data.toString());
Request oreq = new
Request.Builder().url("https://fcm.googleapis.com/fcm/googlenotification")
.addHeader("project_id", projectId)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.post(body)
.build();
where the notification key name is the user email of Google account the token is retrieved using
String idToken = GoogleAuthUtil.getToken(this, account, scope);
and the registration id is retrieved using
FirebaseMessaging.getInstance().getToken()
When the app now sends the request the result is "sender denied" but as I said I didn't change anything. In the Firebase docs however I can't find anymore any reference to the endpoint https://fcm.googleapis.com/fcm/googlenotification so is it changed anything?
I tracked the web page with firebase doc and I saw that the section relative to the client android app management of device groups has been removed one year ago, on 18th March 2020.
I reply to myself: Firebase support finally replied saying that the client support has been removed without any advice. No solution to this problem. Personal note: don't use anymore Firebase products.

How to send a firebase message to topic from Android

I want to send a message to FCM topics from within my Android app. Sending the message through the Firebase console is working well, but once a user executes a particular action, I want a message to be sent to all other users who have subscribed to a particular topic.
In the documentation there is this code:
// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";
// See documentation on defining a message payload.
Message message = Message.builder()
.putData("score", "850")
.putData("time", "2:45")
.setTopic(topic)
.build();
// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);
I can't figure out from which class Message is. It is obviously not RemoteMessage.
You can do it by Volley and FCM API
here an example to send notification from user to "newOrder" Topic and have title and body
RequestQueue mRequestQue = Volley.newRequestQueue(this);
JSONObject json = new JSONObject();
try {
json.put("to", "/topics/" + "newOrder");
JSONObject notificationObj = new JSONObject();
notificationObj.put("title", "new Order");
notificationObj.put("body", "New order from : " + phoneNum.replace("+", " "));
//replace notification with data when went send data
json.put("notification", notificationObj);
String URL = "https://fcm.googleapis.com/fcm/send";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, URL,
json,
response -> Log.d("MUR", "onResponse: "),
error -> Log.d("MUR", "onError: " + error.networkResponse)
) {
#Override
public Map<String, String> getHeaders() {
Map<String, String> header = new HashMap<>();
header.put("content-type", "application/json");
header.put("authorization", "key=yourKey");
return header;
}
};
mRequestQue.add(request);
} catch (JSONException e) {
e.printStackTrace();
}
Replace yourKey with server key in your project in firebase
UPDATE :
as #frank say in correct answer You will always need a server (or otherwise trusted environment) to hold yourKey and make it not public
so this answer is already work and can send notifications from android to topic or token
but if anyone take your key can send also to your apps notifications in any time
so i suggest to use firebase functions or any service on your server just make sure your key in trusted environment and not reachable
also when get key there two type :
1 - Server key
2 - Legacy server key
like firebase say below also i suggested to use first because is more flexible to change or deleted
Firebase has upgraded our server keys to a new version. You may
continue to use your Legacy server key, but it is recommended that you
upgrade to the newest version
There is no way to securely send messages directly from one Android device to another device with Firebase Cloud Messaging. You will always need a server (or otherwise trusted environment) to do that. See this docs section showing how messages are sent and my answer. here: How to send one to one message using Firebase Messaging.
The code sample you shared is using the Admin SDK for Java to send a message, which is meant to be run in a trusted environment. It can't be used in your Android app.
Refer this link.. You can do what you need via this official google documentation.
But I can show you an example that I wrote via AndroidFastNetworking library:
JSONObject dataJsonObject = new JSONObject();
dataJsonObject.put("anyDataYouWant":"value");
try {
bodyJsonObject.put("to", "/topics/topic");
bodyJsonObject.put("data", dataJsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
AndroidNetworking.post("https://fcm.googleapis.com/fcm/send")
.setContentType("application/json; charset=utf-8")
.addJSONObjectBody(bodyJsonObject)
.addHeaders("Authorization", "Your Firebase Authorization Key with 'key=' prefix: ("key=AAAAjHK....") ")
.setPriority(Priority.HIGH)
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(ANError anError) {
Toast.makeText(context, "Error: " + anError.toString(), Toast.LENGTH_SHORT).show();
}
});
Here's an implementation using OkHttp 4.x and Kotlin:
// create the payload
val payload = JSONObject()
.put("key", "value")
// create the request body (POST request)
val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = JSONObject()
.put("to", "/topics/my_topic")
.put("data", payload)
.toString().toRequestBody(mediaType)
// create request
val request = Request.Builder()
.url("https://fcm.googleapis.com/fcm/send")
.post(requestBody)
.addHeader("Authorization", "key=${server_key_please_replace}")
.addHeader("Content-Type", "application/json")
.build()
// execute the call
val response = OkHttpClient().newCall(request).execute()
val responseBody = response.body?.charStream()?.readLines()
val httpCode = response.code
// error handling goes here, it's an error if the http response code is not 200
// or if the responseBody contains an error message like
// [{"multicast_id":2633602252647458018,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}]
Security Considerations
It's not recommended to use the server API key on client side since the key can be extracted by an attacker and then used to send messages on behalf of the key owner (that would be you). I would however argue that the risk is quite low under certain circumstances:
Notification messages: the ability to send notifications to all app users is only a risk if those messages can do harm. In my case it's not possible to surface notifications because the app only processes data messages.
Data messages: in my case the app accepts specific topics but only when they are sent from the same user id (I use FCM to sync data for the same user across multiple devices). Without knowing all user ids an attacker could not even send messages. The user ids are impossible to retrieve because they are stored on the device and the user's Google Drive only so unless the Google Drive service as a whole is compromised this is a theoretical risk. On top of that, the data messages are harmless in my case.
The only real risk I see is that an attacker can launch a DOS attack so that Google shuts down access to FCM for your app. If FCM is business critical for your app then that's a real threat. BUT preventing the same attack against your backend API isn't trivial. If you have an API to send messages, that API needs to be protected. Having an endpoint to send messages might protect the FCM key but won't protect against a DOS attack per se. If users are not authenticated (in many apps they aren't) then providing that protection is a non trivial task (bot manager solutions are expensive and implementing mTLS between client and server isn't simple).
To summarize: while it's not recommended to use the server API key on client side, depending on the use case, the security risk is very low. Many apps can't afford to run a backend service just for that one functionality so I would argue using the server key client side can be justified in some cases.

One Signal Push Notification?

I have made movie review app on android.Users create an account with firebase authentication and review movies and rate them.Admin of app can add new movies.
My question is how can I(admin) send a notification to all users (of firebase) whenever I added a new movie?And I want to use one signal push notification.
Please Help me.
Using Tags its possible to send the notification to all users.
1.Primarily you have create a channel eg: allusers from mobile end need to register
JSONObject tags = new JSONObject();
tags.put("allusers", "1");
OneSignal.sendTags(tags);
2.From server end who are all registered in the tag allusers=1 ..Notification will send to all the users
Sending Push from serverside
https://documentation.onesignal.com/reference#create-notification

handling token changes in notification groups fcm

I have implemented Fcm in my App and thats working great.. In My app i am creating notification groups by
$data = array();
$data["operation"] = "create";
$data["notification_key_name"] = "gcm";
$data["registration_ids"] = array("token");
and iam successfully received my notificationkey for frequent use... and if the token changes to another should i remove the tokenid from the notification group and add the new one everytime ?? or fcm will take care of it???
Yes. It's the developer's responsibility to manage these changes in the Device Group Messaging (see my answer here).
You'll have overwrite/replace the old token with the new one.

How do I send FCM messages from an Android Device to the Server?

There is a ton of documentation explaining how to send messages from the server to the Android device, but next to nothing available for how to send it from the Android device to the server.
We are working on making an app where the users can receive notifications from one another in certain circumstances. I am receiving messages just fine and my code works to parse them when received. Sending messages, on the other hand, is not working.
The code I am attempting to work with is:
public static void sendNotificationToUser(String userId, final String message){
FirebaseMessaging messaging = FirebaseMessaging.getInstance();
Bundle someBundle = new Bundle();
someBundle.putString("STRING_KEY_HERE", "STRING_VALUE_HERE");
//I have tried excluding the #gcm as well, no luck.
String str = "user_" + userId + "#gcm.googleapis.com";
RemoteMessage.Builder myBuilder = new RemoteMessage.Builder(str);
Map<String, String> aMap = new HashMap<>();
aMap.put("DATA_KEY_1", "DATA_VALUE_1");
myBuilder.setData(aMap);
myBuilder.addData("ADD_DATA1", "ADD_DATA11");
myBuilder.setMessageId("SOME_MESSAGE_ID123");
myBuilder.setTtl(0); //Send immediately
myBuilder.setMessageType("SOME_MESSAGE_TYPE");
myBuilder.setCollapseKey("SOME_COLLAPSE_KEY");
//Can't do this, private access, how do I instantiate this?
RemoteMessage.Notification notification = new RemoteMessage.Notification();
RemoteMessage remoteMessage = myBuilder.build();
messaging.send(remoteMessage);
}
The problem here is that once this fires off, nothing ever happens. Specifically, what I am trying to do is send a message as per subscribed topics. So, if I were subscribed to android_tag, I want to send this message to the android_tag, which is where the userId is set; I have that user subscribed to user_{theirtag}.
Does anyone have any clue how to go about sending an outbound FCM message to a specific topic? Also, how do I instantiate and include a RemoteMessage.Notification object since it cannot be done the way I have listed above?
Thanks all.
EDIT:
It looks like the answer as per Mr Frank van Puffelen is that no, it cannot be done via the SDK directly. It can be done via a combination of topic subscriptions and including a server to process the actual sends (here), but it should not be done without the use of a server in order to prevent secret/ server key exposure.

Categories

Resources