This question already has an answer here:
How set Firebase notification ChannelID in Android O?
(1 answer)
Closed 3 years ago.
I followed official sample and extends FirebaseMessagingService
<service android:name=".service.MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
and my push json
{
"message":{
"token":"my fcm token",
"android":{
"priority": "high",
"data":{
"key1":"123","key2":"456"
}
}
}
}
I reveived fcm from
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {}
until I killed my app from recent application.
My android os is Android 8.1 (API level 27)
I have test on android 7.1(API level 25), it can receive message, even app got killed.
See this part :
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
System.out.println("Remote Data" + remoteMessage);
//Check if msg contains Data'
if (remoteMessage.getData().size() > 0) {
System.out.println("Message Data : " + remoteMessage.getData());
sendNotification(remoteMessage.getData().get("body"));
}
//Check if message contains notification
if (remoteMessage.getNotification() != null) {
System.out.println("Message Body " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
Reference link :
Check Here
Deat #youteng notification in oreo must needed Channel Id inside notification builder object. So check in your code if you have added channel id or not. you can have look in below code. Also have look here
// Sets an ID for the notification, so it can be updated.
int notifyID = 1;
String CHANNEL_ID = "my_channel";// channel id
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
// Create a notification and set the notification channel.
Notification notification = new Notification.Builder(MainActivity.this)
.setContentTitle("New Message")
.setContentText("You've received new messages.")
.setSmallIcon(R.drawable.ic_notify_status)
.setChannelId(CHANNEL_ID)
.build();
There are so many details while implementing FCM. Use tools to check the sender side and receiver side. And there comes the background/foreground parts.
If your message format aren't correct, it will not trigger onReceive() when app is in background.
By correct I mean it contains only data{...}, without notification{...}
Before dig into your server side's code, have you test your client side by sending a message from Firebase Console's web tool or the FCM API?
POST https://fcm.googleapis.com/fcm/send
I don't know what language you're using on server side, but the original message should look like this (from official)
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message":{
"topic" : "foo-bar",
"notification" : {
"body" : "This is a Firebase Cloud Messaging Topic Message!",
"title" : "FCM Message"
}
}
}
Related
I am trying to display a notification when the fcm message received and the APP is in the background. I tried different flavors of notifications but not luck. The notification won't show
Here is the code
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(GlobalVar.TAG, "From: " + remoteMessage.getFrom());
super.onMessageReceived(remoteMessage);
String channelId = getString(R.string.notification_channel_id);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody()).setAutoCancel(true);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
I know this is getting called because I get the log.
If the app is in the background then FCM displays notifications. It is the above code that is not displaying it when app is in foreground
Any suggestions?
PS: I created the channel in the Application class
I don't get errors in the log cat. I am also setting all the notifications settings as per code below. Please note my device receive and display notifications already from FCM when it is in background. But when it is in foreground and "I" handle the display of notification then it does not work
Hopefully your server is sending you notification in data key.
Here as I saw your code, You are getting notification data using remoteMessage.getNotification()
Now you have to make changes in your server side script that they send in data key as follow (You can test temporary before changing server code):
{
"to" : "YOUR_FCM_TOKEN_WILL_BE_HERE",
"collapse_key" : "type_a",
"data" : {
"body" : "Body of Your Notification in Data",
"title": "Title of Your Notification in Title",
"key_1" : "Value for key_1",
"key_2" : "Value for key_2"
}
}
and after that you can receive like this:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
}
To know more about it:
Hope you will get help in this. Do let me know if you get any problem.
If you're not using your own server, then you can't achieve this. You need to use your own server to modify the JSON format from this:
{
"to" : "YOUR_FCM_TOKEN_WILL_BE_HERE",
"collapse_key" : "type_a",
"notification" : {
"body" : "Body of Your Notification in Data",
"title": "Title of Your Notification in Title",
"key_1" : "Value for key_1",
"key_2" : "Value for key_2"
}
}
to:
{
"to" : "YOUR_FCM_TOKEN_WILL_BE_HERE",
"collapse_key" : "type_a",
"data" : {
"body" : "Body of Your Notification in Data",
"title": "Title of Your Notification in Title",
"key_1" : "Value for key_1",
"key_2" : "Value for key_2"
}
}
when your server will modify "notification" tag with "data" then only you can recieve notification in background.
I'm trying to send the click-action data with the notification to handle the onClick event for it but unfortunately the app receives no data through the onMessageReceived(). I have tried plenty of things but all in vain.
Here is my code:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String notification_title =
remoteMessage.getNotification().getTitle();
String notification_message =
remoteMessage.getNotification().getBody();
String click_action =
remoteMessage.getNotification().getClickAction();
String from_user_id = remoteMessage.getData().get("from_user");
Log.v("user id", from_user_id);
if(from_user_id!= null){
Toast.makeText(this, from_user_id, Toast.LENGTH_SHORT).show();
}
NotificationCompat.Builder mBuilder = new
NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(notification_title)
.setContentText(notification_message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
Intent resultIntent = new Intent(click_action);
resultIntent.putExtra("user_id", from_user_id);
Log.v("user id", from_user_id);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntentWithParentStack(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
int mNotificationID = (int)System.currentTimeMillis();
NotificationManager mNotifyManger =
(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
mNotifyManger.notify(mNotificationID, mBuilder.build());
}
and here is my mainfest:
<service android:name=".FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
and this is my gradle:
implementation 'com.google.firebase:firebase-core:16.0.4'
implementation 'com.google.firebase:firebase-database:16.0.3'
implementation 'com.google.firebase:firebase-storage:16.0.3'
implementation 'com.google.firebase:firebase-auth:16.0.5'
implementation 'com.firebaseui:firebase-ui-database:4.2.1'
implementation 'com.google.firebase:firebase-messaging:17.3.4'
Edited:
Here is the data I'm expecting:
const deviceToken =
admin.database().ref(`/Users/${user_id}/device_token`).once('value');
return deviceToken.then(result => {
if (!result || !result.exists){throw new Error("Profile doesn't exist")}
const token_id = result.val();
const payload = {
notification: {
title: "New Friend Request",
body: `${userName} has sent you a Friend Request`,
icon: "default",
click_action: "com.example.alaa.lapitchatapp.Target_Notification"
},
data:{
from_user: from_user_id
}
};
If your RemoteMessage contains notification key onMessageReceived is only called if your app in background.
Move notification part into data. If you have notification setup from the request, FCM uses system notification tray to display the notification you wouldn't have any control over it, On the other hand if you need to process the push response, You should avoid using the notification part in the request
const payload = {
data:{
from_user: from_user_id,
title: "New Friend Request",
body: `${userName} has sent you a Friend Request`,
icon: "default",
click_action: "com.example.alaa.lapitchatapp.Target_Notification"
}
};
Firstly, are you passing your device's firebase ID in the payload? If yes, Please update your payload body mentioned. I don't see it there.
Your payload must have the firebase ID something like this :
"registration_ids":[
"your device's firebase ID"
]
or
"to":"your device's firebase ID"
or
"token":"your device's firebase ID"
Secondly, I don't see the point of this code :
if (true) {
Log.d(TAG, "Message data payload: there is not a problem");
} else {
// Handle message within 10 seconds
Log.d(TAG, "Message data payload: there is a problem");
}
What is the point of an else for an if statement which is always true?
Thirdly, the click action value you have given in the payload - com.example.alaa.lapitchatapp.Target_Notification
Is this a class you are trying to open on click of the notification?
I've found the answer to my question after too much digging in the firebase documentation.
You'll find it there:
Firebase Message Service not called but one time only
Thank you All.
Let me go straight to the point, with Firebase Cloud Messaging and Android Oreo there have been some major changes when it comes to using their APIs.
I have entered my Firebase Server Api Key in the PubNub Console, push notification works absolutely fine on the Firebase console, but when publishing notification with PubNub, remoteMessage.toString gives => com.google.firebase.messaging.RemoteMessage#ffe9xxx in the OnMessageReceived function.
I am publishing something like this
JsonObject payload = new JsonObject();
JsonObject androidData = new JsonObject();
androidData.addProperty("contentText","test content");
androidData.addProperty("contentTitle","Title");
JsonObject notification = new JsonObject();
notification.add("notification",androidData);
JsonObject data = new JsonObject();
data.add("data", notification);
payload.add("pn_gcm", data);
in
PubNubObject.publish()
.message(payload)
etc..
Any idea why is this happening?
Thank you in advance.
Code on the receiving end
There is a class which extends FirebaseMessagingService, codes for OnMessageReceived function:
if (remoteMessage.getNotification() != null) {
//for testing firebase notification
Log.d(TAG, "Message Notification
Body:"+remoteMessage.getNotification().getBody());
} else {
//for anything else, I wanted to see what was coming from the server
//this is where I am getting the message when using PubNub notification
Log.d(TAG, "onMessageReceived: remoteMessage to
str:"+remoteMessage.toString() );
}
Android getData vs getNotification API
You are nesting the notification key/value inside of the data key and just need to use the API, remoteMessage.getData() instead of remoteMessage.getNotification().
If notification key was at the top level, it would work. See Android docs here.
Instead of this:
{
"pn_gcm": {
"data": {
"notification": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
}
This if switing to remoteMessage.getData():
{
"pn_gcm": {
"data": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
Or this if sticking with remoteMessage.getNotification():
{
"pn_gcm": {
"notification": {
"contentText": "test content",
"contentTitle": "Title"
}
}
}
}
PubNub basically just looks for the pn_gcm in the message payload when it is published and grabs whatever is inside of it and passes that directly to Google's FCM service for the devices that are registered (with PubNub) for that channel to receive GCM (FCM).
If the data is not formatted properly we would receive an error back from FCM which should be reported on the channel's -pndebug channel (assuming pn_debug:true was included in the published message payload).
For full details on troubleshooting FCM (GCM) or APONS issues with PubNub, please review How can I troubleshoot my push notification issues?
I am dealing with FCM messages and I have the following function:
public void onMessageReceived(final RemoteMessage remoteMessage)
{
final Map<String, String> data = remoteMessage.getData();
//...
}
For testing purposes, I have a Json file containing data- and I want to send that Json file from my test method to onMessagereceived() . Hence I need to initialize a RemoteMessage object with the Json file and pass this RemoteMessage object to the function. How do I initialize this?
My JSON file:
{
"data": {
"id" : "4422",
"type" : "1",
"imageUrl" : "https://image.freepik.com/free-vector/android-boot-logo_634639.jpg",
"smallTitle" : "DoJMA v2",
"smallSubTitle" : "Update now from Google Play Store",
"ticker" : "New update for DoJMA",
"contentInfo" : "",
"link" : "https://photo2.tinhte.vn/data/avatars/l/1885/1885712.jpg?1402763583",
"className" : "HomeActivity",
"page" : "2",
"bigTitle" : "DoJMA Android app version 2 released!",
"bigSubTitle" : "Hi folks! New DoJMA update is here! Major redesigning and improvements! This app was made by the Mobile App Club.They work really hard man...and get good products",
"bigSummaryText" : "Update now"
},
"registration_ids": ["dQYmpLUACXQ:APA91bGl-NoIMJ2_DcctF5-OA8ghyWuyrMfsz3uhlj1BySl6axkAsmv5y_7YGfpQQJ2E0lP_fTcxpHpZdkJzY1tbcWA36e78ooxC_b0a1PAank9gFIAUHVZkHKmZT70MPZosCgvRlVfq","dfLXnRI36qY:APA91bFyjLblijVIjGLCGWVeB1B0z5j_3TYqRytJ-8hvuUESpDlX59gWF3hU-I-kA4VrRCPpEVFWl18ZarnPjqxxtZgFkVxoLr77HRex27VN7Mh3xupWykmKq_nnVIlVzrODKwKI7ktM"]
}
you can test using Postman For Single User.
Send a notification with a JSON payload
URL: https://fcm.googleapis.com/fcm/send
Headers:
Authorization: key=<your-api-key>
Content-Type: application/json
Body (click on the 'raw' tab):
{
"to": "dQYmpLUACXQ:APA91bGl-NoIMJ2_DcctF5-OA8ghyWuyrMfsz3uhlj1BySl6axkAsmv5y_7YGfpQQJ2E0lP_fTcxpHpZdkJzY1tbcWA36e78ooxC_b0a1PAank9gFIAUHVZkHKmZT70MPZosCgvRlVfq",
"data": {
"id": "4422",
"type": "1",
"imageUrl": "https://image.freepik.com/free-vector/android-boot-logo_634639.jpg",
"smallTitle": "DoJMA v2",
"smallSubTitle": "Update now from Google Play Store",
"ticker": "New update for DoJMA",
"contentInfo": "",
"link": "https://photo2.tinhte.vn/data/avatars/l/1885/1885712.jpg?1402763583",
"className": "HomeActivity",
"page": "2",
"bigTitle": "DoJMA Android app version 2 released!",
"bigSubTitle": "Hi folks! New DoJMA update is here! Major redesigning and improvements! This app was made by the Mobile App Club.They work really hard man...and get good products",
"bigSummaryText": "Update now"
}
}
Source : https://firebase.google.com/docs/cloud-messaging/concept-options
TL;DR: Initializing a RemoteMessage object is not possible.
Attempting to access initialize a RemoteMessage from your own class would return an error:
'RemoteMessage(android.os.Bundle)' is not public in 'com.google.firebase.messaging.RemoteMessage'. Cannot be accessed from outside package.
I presume you're attempting to do this for testing purposes (stubbing?). In general (not gonna say best practice, since I'm not that entirely sure that it is best practice), it is advisable to have a separate method that accepts a specific value that you need. Referring to the official example (onMessageReceived) (removed some stuff):
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
/**
* Schedule a job using FirebaseJobDispatcher.
*/
private void scheduleJob() {
// [START dispatch_job]
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
Job myJob = dispatcher.newJobBuilder()
.setService(MyJobService.class)
.setTag("my-job-tag")
.build();
dispatcher.schedule(myJob);
// [END dispatch_job]
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
Focusing on the comment that mentions:
Also if you intend on generating your own notifications as a result of a received FCM message, here is where that should be initiated. See sendNotification method below.
This points out the sendNotification() method that accepts a String parameter. Depending on your case, instead of attempting to pass an initialized RemoteMessage (which sadly isn't possible, or at the very least is not advisable), you could simply pass an object that your method needs.
With that, you pretty much tested the method that handles the message without depending on an object that isn't a class you made in the first place.
PS: Some of my explanations can be confusing, but I hope this made sense.
I need to use non-collapsible notification by Firebase. For that I am using data-message like this:
{
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data" : {
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
},
}
This message is interpreted in the onMessageReceived() method.
I still want to display this data-message in the tray just like notification-messages are displayed by the system automatically.
How to I achieve this? I cannot find documentation on this.
Thanks!
You can retrieve the values from your data payload in onMessageReceived() by calling RemoteMessage.getData(), then .get("<KEY_HERE>"). Like so:
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "onMessageReceived()");
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
String dataTitle = remoteMessage.getData().get("data_title");
String dataBody = remoteMessage.getData().get("data_body");
sendNotification(dataTitle, dataBody);
}
You have to then build and display the Notification yourself. Like so:
private void sendNotification(String title, String body) {
Notification notif = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(0, notif);
}