I want to integrate fcm for having push notification functionality in my app. But the problem is my fcm token is not getting generated at all. I used the same code I used in this project into a new project and it worked without any issue.
But with this project I have tried everything to no result at all.
I tried with both the deprecated onTokenRefresh() method as well as the new onNewToken() method but none of them is working for me.
Below is the code for the same.
public class CustomFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
// TODO(developer): Handle FCM messages here.
Log.d("Firebase", "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d("Firebase", "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d("Firebase", "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.
}
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.d("token",s);
}
}
And this is the code with onTokenRefresh() method
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("Firebase", "Refreshed token: " + refreshedToken);
}
}
I have declared both services in the manifest too.
<service android:name=".notification.CustomFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".notification.MyFirebaseInstanceIdService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
What I have tried
Deleted the project on console and creating again
Copying whole project to a new folder and open again in Android Studio
Tried with both of the above service
Tried calling FirebaseInstanceId.getToken() but this gives null pointer exception.
Aside from the implementation errors, have a look at how instance ID works: https://developers.google.com/instance-id/, check the chapter Instance ID lifecycle at the bottom.
I can see 2 points where it might go wrong:
You don't have a connection with the Google servers. Check if you have a working internet connection by opening the device and opening a webpage. Also take proxies and firewalls into account, those might block your traffic (for example, if you are in China, the Great Firewall might block your connection with the Instance ID servers).
Make sure you don't already have a token. This is quite a common error. You implement the ID token service, and run the app. It works fine, now you want to send the token to the server, and write the code for it. When you run the app again, you will see no connection to the server, and think there's an issue with your implementation.
What actually happened, is that you already got your token on the first run, and it was cached by the app. The second time it already has a token, and the onNewToken() will not be called.
If you uninstall the app, and install it again, it will ask for a new token on launch.
Finally got the solution to my problem. I got this hint when I was trying to integrate OneSignal notification sdk. The problem was that I had the below code in the application tag of manifest.
tools:node="replace"
This was written in OneSignal docs.
Make sure you are not replacing the tag in your AndroidManifest.xml with tools:node="replace"
As OneSignal was also internally using FireBase I thought to give it a try with the firebase directly and it worked after I removed it.
Hope this will help someone else too
As said by #Nilesh Rathod FirebaseInstanceIdService is depreciated. So no you need only one service in the manifest.
Try this way.
1. First Create a Service
public class YourService extends FirebaseMessagingService {
public static int NOTIFICATION_ID = 1;
#Override
public void onNewToken(String s) {
super.onNewToken(s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mNotifyBuilder = new NotificationCompat.Builder(this, "2")
.setSmallIcon(R.drawable.your_icon)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody())
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (NOTIFICATION_ID > 1073741824) {
NOTIFICATION_ID = 0;
}
Objects.requireNonNull(notificationManager).notify(NOTIFICATION_ID++, mNotifyBuilder.build());
}
}
Now add this to Manifest
<service
android:name=".YourService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
the generate of token for firebase is in first install of app or when you delete the cache for app ,this example of code work for me
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
SharedPreferences sharedPreferences1;
SharedPreferences.Editor editor1;
private static final String PREF_NAME1 = "prefs_token";
private static final String KEY_FCM = "devices_token";
//this method will be called
//when the token is generated
#Override
public void onTokenRefresh() {
sharedPreferences1 = getSharedPreferences(PREF_NAME1, Context.MODE_PRIVATE);
editor1 = sharedPreferences1.edit();
super.onTokenRefresh();
//now we will have the token
String token = FirebaseInstanceId.getInstance().getToken();
editor1.putString(KEY_FCM,token.toString());
editor1.apply();
//for now we are displaying the token in the log
//copy it as this method is called only when the new token is generated
//and usually new token is only generated when the app is reinstalled or the data is cleared
Log.d("MyRefreshedToken", token);
String device_token = sharedPreferences1.getString(KEY_FCM, "");
}
}
The onTokenRefresh/onNewToken methods are only called when a token is generated. Most of the time a token just exists, and is not modified. During that time, onTokenRefresh/onNewToken won't be called.
So most likely, your token was generated when you first add the app, before you had the onTokenRefresh/onNewToken. So to now get the token, you can do two things:
Uninstall and reinstall the app. Deleting the app will delete the existing token, then it will generate a new token on the reinstall, and call your onTokenRefresh/onNewToken.
Also request the token in e.g. your MainActivity.onCreate.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
String iidToken = FirebaseInstanceId.getInstance().getToken();
Log.d("Firebase", "Got token: " + iidToken);
Create two java classes and one interface in APP
Interface:
public interface FCMTokenInterface {
void onTokenReceived(String token);
void onFailure();
}
Token Listener Class:
public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
private static FCMTokenInterface fcmTokenCallback;
private static Handler handlerOs = new Handler();
private static int delay=20000;
private static final String TAG = "MyFirebaseIIDService";
private static final String FRIENDLY_ENGAGE_TOPIC = "friendly_engage";
#Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "FCM Token: 3" + token);
//putting token in preference
Prefs.putString(Constant.FCM_TOKEN,token);
FirebaseMessaging.getInstance()
.subscribeToTopic(FRIENDLY_ENGAGE_TOPIC);
}
public static void setCallback(FCMTokenInterface callback) {
try {
String token = FirebaseInstanceId.getInstance().getToken();
if (token != null && !token.isEmpty()) {
//putting token in preference
Prefs.putString(Constant.FCM_TOKEN,token);
callback.onTokenReceived(token);
return;
}
} catch (Exception e) {
retry(callback);
Log.v("SetCallback EXP= ", e.toString());
}
fcmTokenCallback = callback;
// startHandler();
}
public static void retry(FCMTokenInterface callback)
{
setCallback(callback);
}
private static void startHandler() {
handlerOs.postDelayed(new Runnable() {
#Override
public void run() {
retry(fcmTokenCallback);
// fcmTokenCallback.onFailure();
fcmTokenCallback = null;
}
}, delay);
}
private static void clearHandler() {
handlerOs.removeCallbacksAndMessages(null);
}
}
Message Receiving Class:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFMService";
String CHANNEL_ID = "com.app.app";
NotificationChannel mChannel;
private NotificationManager mManager;
private String title, msg, actionCode;
private int badge = 0;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Handle data payload of FCM messages.
Log.d(TAG, "FCM Message Id: " + remoteMessage.getMessageId());
Log.d(TAG, "FCM Notification Message: " + remoteMessage.getData() + "...." +
remoteMessage.getFrom());
if (remoteMessage.getData() != null) {
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
//Log.e("JSON_OBJECT", object.toString());
title = object.optString("title","");
actionCode = object.optString("action_code", "");
msg = object.optString("body", "");
if (remoteMessage.getData().containsKey("badge")) {
badge = Integer.parseInt(remoteMessage.getData().get("badge"));
//Log.d("notificationNUmber", ":" + badge);
setBadge(getApplicationContext(), badge);
Prefs.putBoolean(Constant.HAS_BADGE,true);
}
if (!(title.equals("") && msg.equals("") && actionCode.equals(""))) {
createNotification(actionCode, msg, title);
}
else {
//Log.e("Notification", "Invalid Data");
}
}
}
public void createNotification(String action_code, String msg, String title) {
Intent intent = null;
intent = new Intent(this, HomeActivity.class);
intent.putExtra(Constant.ACTION_CODE, action_code);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel androidChannel = new NotificationChannel(CHANNEL_ID,
title, NotificationManager.IMPORTANCE_DEFAULT);
// Sets whether notifications posted to this channel should display notification lights
androidChannel.enableLights(true);
// Sets whether notification posted to this channel should vibrate.
androidChannel.enableVibration(true);
// Sets the notification light color for notifications posted to this channel
androidChannel.setLightColor(Color.GREEN);
// Sets whether notifications posted to this channel appear on the lockscreen or not
androidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(androidChannel);
Notification.Builder nb = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
.setContentTitle(title)
.setContentText(msg)
.setTicker(title)
.setShowWhen(true)
.setSmallIcon(R.mipmap.ic_small_notification)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
R.mipmap.ic_launcher_round))
.setAutoCancel(true)
.setContentIntent(contentIntent);
getManager().notify(101, nb.build());
} else {
try {
#SuppressLint({"NewApi", "LocalSuppress"}) android.support.v4.app.NotificationCompat.Builder notificationBuilder = new android.support.v4.app.NotificationCompat.Builder(this).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setSmallIcon(R.mipmap.ic_small_notification)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
R.mipmap.ic_launcher_round))
.setContentTitle(title)
.setTicker(title)
.setContentText(msg)
.setShowWhen(true)
.setContentIntent(contentIntent)
.setLights(0xFF760193, 300, 1000)
.setAutoCancel(true).setVibrate(new long[]{200, 400});
/*.setSound(Uri.parse("android.resource://"
+ getApplicationContext().getPackageName() + "/" + R.raw.tone));*/
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify((int) System.currentTimeMillis() /* ID of notification */, notificationBuilder.build());
} catch (SecurityException se) {
se.printStackTrace();
}
}
}
private NotificationManager getManager() {
if (mManager == null) {
mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return mManager;
}
}
Implement Interface on your Splash:
class SplashActivity : AppCompatActivity(), FCMTokenInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
MyInstanceIDListenerService.setCallback(this)
}
override fun onFailure() {
Log.d("Token", "Unable to get token.")
}
override fun onTokenReceived(token: String?) {
Log.d("Token", token)
Prefs.putString(Constant.FCM_TOKEN, token)
}
}
Manifest under Application TAG
<service android:name="fcm.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="fcm.MyInstanceIDListenerService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#mipmap/ic_launcher_round" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
Related
I am using Azure Hubs to send notifications. I am able to receive the notification and it displays on the device when I pull down the notifications window. However, I do not see the notification display at the top of the screen as expected. I even "locked" the screen and it didn't display. I got the notification sound and my logs show I received it.
Screen showing received notification
My FirebaseMessageService:
using System;
using System.Linq;
using WindowsAzure.Messaging;
using Android.App;
using Android.Content;
using Android.Support.V4.App;
using Android.Util;
using Firebase.Messaging;
using IDEQ.AQI.Pages;
namespace IDEQ.AQI.Droid
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
const string Tag = "FirebaseMsgService";
public override void OnNewToken(string token)
{
// NOTE: save token instance locally, or log if desired
SendRegistrationToServer(token);
}
private void SendRegistrationToServer(string token)
{
try
{
var hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString, this);
// register device with Azure Notification Hub using the token from FCM
var registration = hub.Register(token, Constants.SubscriptionTags);
// subscribe to the SubscriptionTags list with a simple template.
var pnsHandle = registration.PNSHandle;
var templateReg = hub.RegisterTemplate(pnsHandle, "defaultTemplate", Constants.FCMTemplateBody, Constants.SubscriptionTags);
}
catch (Exception e)
{
Log.Error(Constants.DebugTag, $"Error registering device: {e.Message}");
}
}
public override void OnMessageReceived(RemoteMessage message)
{
base.OnMessageReceived(message);
string messageBody;
Log.Info(Tag, "From: " + message.From);
if (message.GetNotification() != null)
{
Log.Info(Tag, "Notification Message Body: " + message.GetNotification().Body);
messageBody = message.GetNotification().Body;
}
// NOTE: test messages sent via the Azure portal will be received here
else
{
messageBody = message.Data.Values.First();
}
// convert the incoming message to a local notification
SendLocalNotification(messageBody);
// send the incoming message directly to the MainPage
SendMessageToMainPage(messageBody);
}
private void SendLocalNotification(string body)
{
try
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.PutExtra("message", body);
var requestCode = new Random().Next();
var pendingIntent = PendingIntent.GetActivity(this, requestCode, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new NotificationCompat.Builder(this, Constants.NotificationChannelId)
.SetContentTitle("IDEQ Alert")
.SetSmallIcon(Resource.Drawable.ic_launcher)
.SetContentText(body)
.SetAutoCancel(true)
.SetShowWhen(false)
.SetContentIntent(pendingIntent);
var notificationManager = NotificationManagerCompat.From(this);
notificationManager.Notify(0, notificationBuilder.Build());
}
catch (Exception e)
{
Log.Error(Tag, e.ToString());
}
}
private void SendMessageToMainPage(string body)
{
(Xamarin.Forms.Application.Current.MainPage as MainPage)?.AddMessage(body);
}
}
}
//My main activity where I create the channel:
private void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var channel = new NotificationChannel(Constants.NotificationChannelId, Constants.NotificationChannelName, NotificationImportance.Default)
{
Description = string.Empty
};
var notificationManager = (NotificationManager) GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
Notification in your system tray will only be displayed if application is in background or turned off. If your application is running, your OnMessageRecieved method will get hit, however Android will not display notification in the system try. This is how life cycle of push notification works in Android.
The only way u can display notification in system tray when application in in foreground is when you force Local Notification like you did in SendLocalNotification method.
I am trying to integrate Firebase Cloud Messaging into my Android Studio project. I began by going to tools, clicking Firebase, going to Cloud Messaging, and then clicking "Connect your app to Firebase" and "Add FCM to your App". Both processes went without a hitch, but the problem came up later. When I was following step 3, there were two blocks of code that we were supposed to integrate. The first block was supposed to be a service that extends FirebaseMessagingService. The second block was a dependency that was supposed to be placed in the manifest. These are the two blocks respectively:
The problem is that the service file is returning the error "Cannot resolve method 'scheduleJob()'", 'handleNow()', and 'sendRegistrationToServer(token)'
I suspected that new methods had to be created, but these methods were supposed to draw from the parent class (I think). I have not clicked the suggestion to create the new methods because I was uncertain whether there would be any functionality.
The first set of code below is the file I made by doing
File->New->Service->Service.
I named the file "MyFirebaseMessagingService". The second set of code is my manifest.
package com.example.piggybank_v3;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import static androidx.constraintlayout.widget.Constraints.TAG;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public MyFirebaseMessagingService() {
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// ...
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be:
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.
}
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true"></service>
<service android:name=".java.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
The ideal result is that the project should sync when running, but it returns these errors: "Cannot resolve method 'scheduleJob()'", 'handleNow()', and 'sendRegistrationToServer(token)'
This is how service class work to receive notification message. So you've to edit your event in it then it'll works fine.
Firebase cloud message demo's are provided on github so can download it and can change firebase keys and package name to test it.
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.google.firebase.quickstart.fcm.R;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
// [START receive_message]
#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 WorkManager.
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.
}
// [END receive_message]
// [START on_new_token]
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
// [END on_new_token]
/**
* Schedule async work using WorkManager.
*/
private void scheduleJob() {
// [START dispatch_job]
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager.getInstance().beginWith(work).enqueue();
// [END dispatch_job]
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
/**
* 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);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle(getString(R.string.fcm_message))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
Try this:
1.- Verify that the library is added in build.gradle:
implementation 'com.google.firebase: firebase-messaging: 19.0.1'
2.- As indicated, you must add the 'MyFirebaseMessagingService' service (previously created) to the AndroidManifest.xml and provide a default notification channel: (click here to learn more about the channels)
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel_id" />
3.- Add the following in MainActivity.java to retrieve the current token when you need it:
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
4.- Fill in the file 'MyFirebaseMessagingService.java':
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a data payload (beauty messages).
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
createAndSendNotificationB(remoteMessage);
}
// Check if message contains a notification payload (from console).
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
createAndSendNotificationC(remoteMessage.getNotification().getBody());
}
}
private void createAndSendNotificationB(RemoteMessage remoteMessage){
//Code here
}
private void createAndSendNotificationC(String messageBody){
//Code here
}
}
With this it should work.
I have taken everything from the official documentation, I recommend you read it: https://firebase.google.com/docs/cloud-messaging/android/client
I have an android app that successfully receives notifications from the Firebase console. I now intend to build a nodejs server where we can send these notifications to save logging into the firebase console, however, it appears that the node.js library 'firebase-admin' only supports sending to individual device ids or topics rather than all devices as per the console.
So I've made a nodejs service to send to topic 'all', and tried to alter android to receive these notifications, however I get no notifications on my device from this nodejs server.
Here is my server code:
var admin = require("firebase-admin");
var serviceAccount = require("./firebase-privatekey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myapp-android-xxx.firebaseio.com"
});
var payload = {
notification: {
title: "Account Deposit",
body: "A deposit to your savings account has just cleared."
},
data: {
account: "Savings",
balance: "$3020.25"
},
topic: "all",
};
admin.messaging().send(payload)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
This is the android code that worked with the console notifications:
public class MyNotificationService extends FirebaseMessagingService {
public MyNotificationService() {
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("Firebase", "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d("Firebase", "Message data payload: " + remoteMessage.getData());
handleNow(remoteMessage.getData(), remoteMessage.getNotification().getBody());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d("Firebase", "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
public void handleNow(Map<String, String> data, String title) {
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
int notificationId = 1;
String channelId = "channel-01";
String channelName = "Channel Name";
int importance = NotificationManager.IMPORTANCE_HIGH;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(
channelId, channelName, importance);
notificationManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), channelId)
.setSmallIcon(R.drawable.myapp_notification_icon)
.setBadgeIconType(R.drawable.myapp_notification_icon)
.setContentTitle(title)
.setContentText(data.get("information"));
notificationManager.notify(notificationId, mBuilder.build());
}
}
and this is the new (Additional not replaced) code, with the intention of receiving topic messages:
#Override
protected void onCreate(Bundle savedInstanceState) {
//other code...
FirebaseMessaging.getInstance().subscribeToTopic("all")
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
System.out.println("win");
} else {
System.out.println("fail");
}
}
});
}
The nodejs server tells me it was a successful send of a message, yet a breakpoint on either the win or fail message never gets hit on android
I had quite the same problem. The solution I found was adding:
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
to AndroidManifest.xml and:
#Override
public void onDeletedMessages() {
super.onDeletedMessages();
}
to MyFirebaseMessagingService.
According to the docs.
Override onDeletedMessages
In some situations, FCM may not deliver a message. This occurs when
there are too many messages (>100) pending for your app on a
particular device at the time it connects or if the device hasn't
connected to FCM in more than one month. In these cases, you may
receive a callback to FirebaseMessagingService.onDeletedMessages()
When the app instance receives this callback, it should perform a full
sync with your app server. If you haven't sent a message to the app on
that device within the last 4 weeks, FCM won't call
onDeletedMessages().
I used firebase to build My project.
It will also use the FCM (firebase cloud message).
But there is a problem. I can't handle the FCM (create my custom notificaion) when app is in background.
The official site tutorial said that
case 1: App foreground -> override the "onMessageReceived()" to create your custom notification.
case 2: App background -> System will create the notification directly. We needn't and can't do anything. Because it doesn't trigger the "onMessageReceived()" in this case.
However if I can do nothing when app is background, I can't create my custom notification. (e.g. After Users click the notification and it will pop up a window to show detail information.)
So how do I handle notifications with FCM when app is in background?
There is a bad news. Google change the Firebase source code in version 'com.google.firebase:firebase-messaging:11.6.0'.
handelIntent is "public final void method" now. which means we can't override it .
If you want to use the solution, change the version to be "com.google.firebase:firebase-messaging:11.4.2"
Try my way. It can perfectly work on the project build version is Android 6.0 above(api level 23) and I have tried it already.
There is better way than official site tutorial
The official site said that the notification will be created by system when app is in background. So you can't handle it by overriding the "onMessageReceived()". Because the "onMessageReceived()" is only triggered when app is in foreground.
But the truth is not. Actually the notificaions (when app is in background) are created by Firebase Library.
After I traced the firebase library code. I find a better way.
Step 1. Override the "handleIntent()" instead of "onMessageReceived()" in FirebaseMessagingService
why:
Because the method will be trigger either app is in foreground or the background. So we can handle FCM message and create our custom notifications in both cases.
#Override
public void handleIntent(Intent intent) {
Log.d( "FCM", "handleIntent ");
}
Step 2. Parse the message from FCM
how:
If you don't know the format of the message you set. Print it and try to parse it.
Here is the basic illustration
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
Step 2. Remove the notifications created by Firebase library when the app is in background
why:
We can create our custom notification. But the notification created by Firebase Library will still be there (Actually it created by ""super.handleIntent(intent)"". There is detail explaination below.). Then we'll have two notifcations. That is rather weird. So we have to remove the notificaion created by Firebase Library
how (project build level is Android 6.0 above):
Recognize the notifications which we want to remove and get the informaion. And use the "notificationManager.cancel()" to remove them.
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"StatusBarNotification tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
The my whole sample code:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static int notificationCount=0;
#Override
public void handleIntent(Intent intent) {
//add a log, and you'll see the method will be triggered all the time (both foreground and background).
Log.d( "FCM", "handleIntent");
//if you don't know the format of your FCM message,
//just print it out, and you'll know how to parse it
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
//the background notification is created by super method
//but you can't remove the super method.
//the super method do other things, not just creating the notification
super.handleIntent(intent);
//remove the Notificaitons
removeFirebaseOrigianlNotificaitons();
if (bundle ==null)
return;
//pares the message
CloudMsg cloudMsg = parseCloudMsg(bundle);
//if you want take the data to Activity, set it
Bundle myBundle = new Bundle();
myBundle.putSerializable(TYPE_FCM_PLATFORM, cloudMsg);
Intent myIntent = new Intent(this, NotificationActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.putExtras(myBundle);
PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//set the Notification
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.icon)
.setContentTitle(cloudMsg.getTitle())
.setContentText(cloudMsg.getMessage())
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationCount++, notificationBuilder.build());
}
/**
* parse the message which is from FCM
* #param bundle
*/
private CloudMsg parseCloudMsg(Bundle bundle) {
String title = null, msg=null;
//if the message is sent from Firebase platform, the key will be that
msg = (String) bundle.get("gcm.notification.body");
if(bundle.containsKey("gcm.notification.title"))
title = (String) bundle.get("gcm.notification.title");
//parse your custom message
String testValue=null;
testValue = (String) bundle.get("testKey");
//package them into a object(CloudMsg is your own structure), it is easy to send to Activity.
CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);
return cloudMsg;
}
/**
* remove the notification created by "super.handleIntent(intent)"
*/
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
}
However if I can do nothing when app is background, I can't create my custom notification. (e.g. After Users click the notification and it will pop up a window to show detail information.)
So how do I handle notifications with FCM when app is in background?
First, you need to create correct message payload that you send to fcm server. Example:
{
"to": "topic_name",
"priority": "high",
"data": {
"field1": "field1 value"
"field2": "field2 value"
}
"notification" : {
"body" : "Lorem ipsum",
"title" : "sampke title"
"click_action": "SHOW_DETAILS"
}
}
data payload is actual data you want to show as message details after user clicks on notification, notification payload represents how generated notification should look (there are much more attributes possible to set), you don't need to build notification by yourself, you only need to set it properties here.
To show your activity after user taps on notication, you need to set intent filter corresponding to click_action:
<intent-filter>
<action android:name="SHOW_DETAILS"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
so activity that have above intent filter will be launched automatically when user taps to notification.
Last step is to retrieve data when activity is launched after notification tap. It's pretty easy. Custom data is passed to activity via bundle. Inside onCreate method for your activity do something like that:
Bundle bundle = getIntent().getExtras();
if(bundle.getString("action").equals("SHOW_DETAILS")) /*This indicates activity is launched from notification, not directly*/
{
//Data retrieved from notification payload send
String filed1 = bundle.getString("field1");
String filed2 = bundle.getString("field2");
}
All of above is valid if app is not running or it's in background. If your app is foreground, no notification will be created. Instead, you will receive onMessageReceived() event so you can handle the same data there (I guess you know how).
Reference:
https://firebase.google.com/docs/cloud-messaging/http-server-ref
https://github.com/firebase/quickstart-android/tree/master/messaging
You need to use FCM data messages in order to create custom notification in a android app.Even your app is in background, onMessageReceived will be called, so you can process the data and show the custom notification.
https://firebase.google.com/docs/cloud-messaging/android/receive
Data message format which has to be sent from server:
{"message":{
"token":"Your Device Token",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
FCM Won't send a background notification if your app is killed any more, and as you described in your answer about the handleIntent() solution It may work for some devices and for some old version of the FCM, also if you #override method that doesn't described in the official doc's of firebase you may struggle some problems here, and you use it on your own risk!.
What is the solution?
You need to use your own push-notification-service beside FCM like Telegram.
OR using SyncAdapter beside GCM like Gmail.
So if you need it to work successfully like those apps, you have to use your own hack.
public class FirebaseMessageReceiver extends FirebaseMessagingService{
private static final String TAG = "main";
String s12;
String channel_id = "general";
Intent intent;
#Override
public void onNewToken(#NonNull String token)
{
Log.d(TAG, "Refreshed token: " + token);
}
#Override
public void
onMessageReceived(RemoteMessage remoteMessage) {
s12=remoteMessage.getNotification().getClickAction();
Log.d("tttt",(remoteMessage.getData().toString()));
Log.d("ttttttt",(remoteMessage.getNotification().toString()));
if (remoteMessage.getNotification() != null) {
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
}
//
}
public void handleIntent(Intent intent)
{
try
{
if (intent.getExtras() != null)
{
RemoteMessage.Builder builder = new RemoteMessage.Builder("FirebaseMessageReceiver");
for (String key : intent.getExtras().keySet())
{
builder.addData(key, intent.getExtras().get(key).toString());
}
onMessageReceived(builder.build());
}
else
{
super.handleIntent(intent);
}
}
catch (Exception e)
{
super.handleIntent(intent);
}
}
private RemoteViews getCustomDesign(String title, String message) {
RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.title111, title);
remoteViews.setTextViewText(R.id.message111, message);
remoteViews.setImageViewResource(R.id.icon111, R.drawable.favicon);
return remoteViews;
}
// Method to display the notifications
public void showNotification(String title, String message) {
intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(s12));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent notifyIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Log.d("notifyy",notifyIntent.toString());
NotificationCompat.Builder builder
= new NotificationCompat
.Builder(getApplicationContext(),
channel_id)
.setSmallIcon(R.drawable.favicon)
.setAutoCancel(true)
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
.setOnlyAlertOnce(true)
.setContentIntent(notifyIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
builder = builder.setContent(getCustomDesign(title, message));
}
else {
builder = builder.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.favicon);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Check if the Android Version is greater than Oreo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app",
NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(
notificationChannel);
}
notificationManager.notify(0, builder.build());
}
}
I am trying to use FCM to send UpStream Message, so I followed the tutorial on google and it works.
As shown in the code below in MainActivity, I send Upstream message when the button is clicked, then in MyAndroidFirebaseMsgService I should see a Log message as shown
below in MyAndroidFirebaseMsgService.
But what happen is, the Log messages in MyAndroidFirebaseMsgService in onMessageSent in do not get displayed even I kept pressing the button several times.
the Log message in MyAndroidFirebaseMsgService in onMessageSent can be displayed only if sent a downstream messagefrom FCM to the App, in this case, both the Logs in
in MyAndroidFirebaseMsgService will be displayed.
Please let me know why the Log message in onMessageSent is not getting displayed once there is an UpStream message sent?and how to fix it.
Mainactivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnSendUpstreamMsg = (Button) findViewById(R.id.btn_send_upstream_message);
mBtnSendUpstreamMsg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseMessaging fm = FirebaseMessaging.getInstance();
fm.send(new RemoteMessage.Builder("673xxxxx" + "#gcm.googleapis.com")
.setMessageId("2")
.addData("my_message", "Hello World")
.addData("my_action","SAY_HELLO")
.build());
}
});
}
MyAndroidFirebaseMsgService:
public class MyAndroidFirebaseMsgService extends FirebaseMessagingService {
private final static String TAG = MyAndroidFirebaseMsgService.class.getSimpleName();
#Override
public void onMessageSent(String s) {
super.onMessageSent(s);
Log.d(TAG, "onMessageSent: upstream message");
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "onMessageReceived: downstream message");
//Log data to Log Cat
Log.d(TAG, "onMessageReceived->From: " + remoteMessage.getFrom());
Log.d(TAG, "onMessageReceived->Notification Message Body: " + remoteMessage.getNotification().getBody());
//create notification
createNotification(remoteMessage.getNotification().getBody());
}
private void createNotification( String messageBody) {
Intent intent = new Intent( this , ResultActivity.class );
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent resultIntent = PendingIntent.getActivity( this , 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder( this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Android Tutorial Point FCM Tutorial")
.setContentText(messageBody)
.setAutoCancel( true )
.setSound(notificationSoundURI)
.setContentIntent(resultIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, mNotificationBuilder.build());
}
}
Yes, is possible to send a Firebase messaging push notification and receive it in all app life cycles using onMessageReceived.
But is necessary to change the default Firebase behaviour, intercepting the intent request before everything else.
** IMPORTANT NOTE **
This was a pretty stupid idea from Firebase by remove the developers processment capability when the FCM message arives with the notification message format, but not for data message.
This created a bunch of "workarounds" in many solutions, which made the analythics and everything else being messed up.
If I had designed this solution, I would always call the onMessageReceived method with a completion handle. Let the developer decide what to do (free tip for you, Firebase).
Use onMessageReceived is the correct way to do. This method is the only one who brings RemoteMessage object, that have every information what you need. It was designed for it. You are on correct path.
** HOW TO DO **
In your Firebase Class MyAndroidFirebaseMsgService, which extends FirebaseMessagingService, override the public method handleIntent to intercep the intent request before Firebase catch it.
#Override
public void handleIntent(Intent intent){
if(intent.hasExtra("google.message_id")){
intent = handleFirebaseIntent(intent);
}
super.handleIntent(intent);
}
After, transform the notification message package into an data message, removing all "gcm.notification.%" and "gcm.n.%" extras from intent, and translating "gcm.notification.title", "gcm.notification.body" and "gcm.notification.image" elements into what you need:
// Thank you Google, for that brilliant idea to treat notification message and notification data
// differently on Android, depending of what app life cycle is. Because of that, all the developers
// are doing "workarounds", using data to send push notifications, and that's not what you planned for.
// Let the developers decide what to do on their apps and ALWAYS deliver the notification
// to "onMessageReceived" method. Its simple, is freedom and its what the creative ones need.
private Intent handleFirebaseIntent(Intent intent){
//printIntentExtras(intent);
String FCM_TITLE_KEY = "gcm.notification.title";
String FCM_BODY_KEY = "gcm.notification.body";
String FCM_IMAGE_KEY = "gcm.notification.image";
String title = intent.getStringExtra(FCM_TITLE_KEY);
String body = intent.getStringExtra(FCM_BODY_KEY);
String image = intent.getStringExtra(FCM_IMAGE_KEY);
// Remove the key extras that identifies an Notification type message
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
if (key.startsWith("gcm.notification.") || key.startsWith("gcm.n."))
{
intent.removeExtra(key);
}
}
}
Boolean isTitleEmpty = StringUtils.isNullOrEmpty(title);
Boolean isBodyEmpty = StringUtils.isNullOrEmpty(body);
Boolean isImageEmpty = StringUtils.isNullOrEmpty(image);
// Notification title and body has prevalence over Data title and body
if(
!isTitleEmpty || !isBodyEmpty || !isImageEmpty
){
// This is my personalized translation method, designed for my solution.
// Probably you gonna need to do it by your own
String contentData = intent.getStringExtra(Definitions.PUSH_NOTIFICATION_CONTENT);
Map<String, Object> content;
if(StringUtils.isNullOrEmpty(contentData)){
content = new HashMap<String, Object>();
content.put(Definitions.NOTIFICATION_ID, new Random().nextInt(65536) - 32768);
content.put(Definitions.NOTIFICATION_CHANNEL_KEY, "basic_channel" );
} else {
content = JsonUtils.fromJson(new TypeToken<Map<String, Object>>(){}.getType(),contentData);
}
if(!isTitleEmpty) content.put(Definitions.NOTIFICATION_TITLE, title);
if(!isBodyEmpty) content.put(Definitions.NOTIFICATION_BODY, body);
if(!isImageEmpty){
content.put(Definitions.NOTIFICATION_BIG_PICTURE, image);
content.put(Definitions.NOTIFICATION_LAYOUT, NotificationLayout.BigPicture.toString());
}
contentData = JsonUtils.toJson(content);
intent.putExtra(Definitions.PUSH_NOTIFICATION_CONTENT, contentData);
}
//printIntentExtras(intent);
return intent;
}
private void printIntentExtras(Intent intent){
Bundle bundle;
if ((bundle = intent.getExtras()) != null) {
for (String key : bundle.keySet()) {
System.out.println(key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
}
}
}
You can check my entire solution here.