I am trying to get notification generated by FCM console and I am receiving them but I am unable to override onMessageReceived of FirebaseMessagingService. Don't know what I am doing wrong.
MyFirebaseMessagingService class responsible for handling notifications:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "FROM:" + remoteMessage.getFrom());
//Check if the message contains data
if(remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data: " + remoteMessage.getData());
}
//Check if the message contains notification
if(remoteMessage.getNotification() != null) {
Log.d(TAG, "Mesage body:" + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody(),remoteMessage.getData());
}
}
/**
* Dispay the notification
* #param body
*/
private void sendNotification(String body , Map<String,String> data) {
// int finalSecId = Integer.parseInt((String) data.get("sec_id"));
// int sec = Integer.parseInt((String) data.get("sec"));
Intent intent = new Intent(this, InsuranceActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0/*Request code*/, intent, PendingIntent.FLAG_ONE_SHOT);
//Set sound of notification
Uri notificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notifiBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.login_meter)
.setContentTitle(getString(R.string.app_name))
.setContentText((String) data.get("sec_id")+ " "+(String) data.get("sec"))
.setAutoCancel(true)
.setSound(notificationSound)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /*ID of notification*/, notifiBuilder.build());
}
}
And Inside Application tag
<service android:name=".Fcm.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service android:name=".Fcm.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
There are two types of FCM
notification Messages: Sending a payload with this message type triggers onMessageReceived() only when your app is in foreground.
data Messages: Sending a payload with only this specific message type triggers onMessageReceived() regardless if your app is in foreground/background.
Reference:here
Extending #Sudip Podder comments and #Ratilal Chopda answer
Follow these steps:
Step1:
<activity android:name=".SplashActivity">
<intent-filter>
<action android:name=".SplashActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Step2:
I am using php at server so you need to adjust things the way you like but in notification payload add "click_action" : ".SplashActivity"
$fields = array(
'to' => $token,
'notification' => array(
'title' => 'Motors City',
'body' => $message,
"click_action" => ".AppSplash",
),
'data' => array(
'sec_id' => $secID,
'sec' => $sec,
'extra1'=>$extra1,
'extra2'=>$extra2
)
);
$headers = array(
'Authorization:key=' . $server_key,
'Content-Type:application/json'
);
Step3:
In Oncreate of your SplashActivity
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
Log.d(TAG,bundle.toString);
}}
and you are done
I had this problem of handling the notifications from FCM.
First we have to understand that there are 2 types of notifications.
Notification - It will trigger when your app is not in foreground and generate a notification. If you click on it then it will open the launcher activity.
Data notification - This one is used to parse the data and it is received in background as well as foreground. So you can build a custom notification based on the data provided in the data object by the FCM Push.
Map<String ,String> dataMap = remoteMessage.getData();
Here i created a simple Map with key value pairs. Now i can receive the title of the notification in the data object and make a simple notification with a custom intent.
I personally use a context object to determine if the app is in foreground or background. Based on that i decide if i have to show the notification or just update the data.
Hope this helps.
Right now you are having Notification in notification type, which triggers Notification Default,and Just open the app on the click of the notification.
So you need to change server side code from notification type to data type.
And try to get Message from
`remoteMessage.getData()` not from `remoteMessage.getNotification()`
if you want to manage click of the notification use data type notification.to understand more about this types go through this link
https://firebase.google.com/docs/cloud-messaging/concept-options
Try this
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);
Related
I have a small application where I receive the message from the Firabase cloud Messaging just fine while the app is running our while is on background. I search a lot about this and I could not find a proper answer on how to receive/create notifications in android while the app is closed so please do not think this is a duplicate question. Can someone show me an example about this and how its done?
This is my Firebase messaging service class
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public static final String tag = "TAG";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(tag,"FROM"+remoteMessage.getFrom());
//check if message contains data
if(remoteMessage.getData().size()>0){
Log.d(tag,"Message Data" + remoteMessage.getData());
}
//check if message constains notification
if(remoteMessage.getNotification() != null){
sendNotification(remoteMessage.getNotification().getBody());
}
}
private void sendNotification(String body){
Intent i = new Intent(this,MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Firebase CLoud Messaging")
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0,notificationBuilder.build());
}
}
This is my manifest
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
As per the docs, there are two types of notifications you can send through FCM.
Notification message
Data message
The firebase console can only send the first type of message. And the Notification message will be handled by the system if your app is in the backgroud, but it won't work if your app is stopped.
Switch to your own API, and send data messages.
So after hours with this problem and with the help of #Mauker I finally did it. These are the steps I took and all the information I received from the internet.
First of all forget Firebase Cloud Message to send notifications to your mobile app.
Second use postman to do those actions.
Notifications are of two types, group notifications where all the people receive the notification at the same time and direct notifications where the notification itself is only for the user to see.
1º If you want group notifications you have to do in you Application launcher class this:
FirebaseMessaging.getInstance().subscribeToTopic("groupNameChoosenByYou");
2º Then you have to create a class to handle this
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
String myCustomKey = data.get("title"); //received from postman POST as you can see above
Intent i = new Intent(this,MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(myCustomKey)
.setContentText(myCustomKey+myCustomKey)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0,notificationBuilder.build());
}
}
3º Go to postman and do this in your body
This should be your URL : https://fcm.googleapis.com/fcm/send
{
"to":"/topics/groupNameChoosenByYou",
"data":
{
"title":"Your title",
"message":"Your message"
}
}
4º While in postman and do this in your Headers
Authorization -> Project settings in Firebase -> Cloud Messaging and take the Server key
Content-type -> application/json
5º If you want to do a direct notification for some specific user in the
"to":"/topics/groupNameChoosenByYou", replace with the device token id that is generated on the first connection with firebase(when the application is installed)
6º If you want to send notifications while the application is closed some ROMs dont allow this except facebook, whatsapp(golden apps) etc you must go to your battery optimization and put your app in the protected application(this changes from brand to brand). The ideal approach is to give the user an initial popup to help him do this.
This is what I learned and it works for me. Any question post above, I will try to research more about this and update while I get more information.
I’m new to android.I programmed an app that uses Firebase to get push notifications. If I send a notification from the Firebase interface, the device receives the notification only when the app is running. Is there a way to get the notifications when the app is not running or at least to get all the unseen notifications when the app starts up?
Thank you in advance!
I add my code...
This is the class extending the FirebaseMessagingService:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public MyFirebaseMessagingService() {
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
sendNotification(remoteMessage.getNotification().getBody());
}
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, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
notificationBuilder.setContentTitle("My app");
notificationBuilder.setContentText(messageBody);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSound(defaultSoundUri);
//notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0,notificationBuilder.build());
}
}
and this is the class extending the FirebaseInstanceIdService:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService{
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
// 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(refreshedToken);
}
private void sendRegistrationToServer(String token)
{
}
}
Finally, this is the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="user.pushnotificationexample">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application>
</manifest>
This is Xamarin Android solution, but it should get you close to native.
Try test sending a "data" push notification from an online tester like "pushwatch". Make sure to click the json checkbox and add a json payload that includes the key, "data":
{"data": {"title":"This is a title!","body":"This is the body text!"}}
The OnMessageReceived(RemoteMessage message) method, message parameter, has a dictionary property "Data": i.e. message.Data. You'll find the json payload key value pairs (title & body) in that dictionary.
Note, if the app is STOPPED, the user will OPEN the notification and Android will open the app, targeting the Activity used in the pending intent created and used to build the local notification (see below). You will need to handle the notification intent from the OnCreate method of your target Activity ( otherwise if the app is running, you'll handle the intent from an override of OnNewIntent).
public class MainActivity....
{
protected override void OnCreate(Bundle bundle)
{
...
var pushExtra = Intent.GetStringExtra("your.pushextra.key");
if(pushExtra != null)
{
MyType myType = JsonConvert.Deserialize<MyType>(pushExtra);
//if you have a framework like MVVM or startup process
//and your type
//is used for app navigation, you may need to store
//the string value in shared preferences and deserialize
//and use it later
//after the app has completely finished starting
}
}
}
Save yourself some effort, if you need a type or dictionary here, make sure to serialize the object when putting the extra (when you create the local notification) and then deserialize the pushExtra to your concrete type to use an instance of it above. You may find most examples put a string, or int or dictionary of key value pairs.
void ConfigureLocalNotification(MyType typeInstance)
{
...
var intent = new Intent(context, typeof(MainActivity));
var jsonData = JsonConvert.SerializeObject(typeInstance);
Log.Info(TAG, $"Adding IntentExtra: {jsonData}");
intent.PutExtra("your.pushextra.key", jsonData);
intent.AddFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop |
ActivityFlags.IncludeStoppedPackages); //| ActivityFlags.NewTask);
var pendingIntent = PendingIntent.GetActivity(context, 0, intent,
PendingIntentFlags.OneShot);
....
NotificationCompat.Builder builder = null;
builder = new NotificationCompat.Builder(context ...);
builder.SetContentIntent(pendingIntent) ....
}
Hope this helps
I can receive push notification when my app is in foreground or background
I added FcmBroadcastReceiver extends WakefulBroadcastReceiver in order to get push
when I close my application.
But I continue without receiving notifications when the app is closed.
Thanks for your help.
manifest.xml
<pre>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="<package>.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.package.name.permission.C2D_MESSAGE" />
<receiver
android:name="<package>.Notification.FcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="<package>" />
</intent-filter>
</receiver>
<service android:name=".Notification.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
public class FcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("receiver","okey");
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
MyFirebaseMessagingService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
public class MyFirebaseMessagingService extends FirebaseMessagingService {
Intent i;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
System.out.println("******************** + getMessageType "+remoteMessage.getMessageType());
System.out.println("******************** + getFrom "+remoteMessage.getFrom());
System.out.println("******************** + getMessageId "+remoteMessage.getMessageId());
System.out.println("******************** + getTo "+remoteMessage.getTo());
System.out.println("******************** + getData "+remoteMessage.getData());
System.out.println("******************** + getData().get(message) "+remoteMessage.getData().get("message"));
System.out.println("******************** + getData().get(title) "+remoteMessage.getData().get("title"));
showNotification(remoteMessage.getData().get("type"),remoteMessage.getNotification().getTitle(),remoteMessage.getNotification().getBody());
}
private void showNotification(String to , String title, String message) {
i = new Intent(this,ProfileActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i, PendingIntent.FLAG_UPDATE_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setAutoCancel(true)
.setContentTitle(title)
.setContentText(message)
.setSound(defaultSoundUri)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0,builder.build());
}
}
<code>
The issue that I can see in your code is that you are implementing the FireBase push notification but you are trying to implement that in a way that was used to implement GCM. You don't need to set any Broadcast Receivers, Firebase is doing that by itself. You just have to run "FirebaseMessagingService". The services looks like this:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO: Handle FCM messages here.
// If the application is in the foreground handle both data and notification messages here.
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated.
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
}
}
As you can see it has it's own "onMessageReceived" method that takes care of Broadcast Receiver's functionality.
Check this tutorial, it will help you to understand:
https://www.codementor.io/flame3/send-push-notifications-to-android-with-firebase-du10860kb
Note: If you want your app to work in each situation even app is in background, foreground or even closed then you need to send some data through payload in your notification.then it will work for all conditions. To do that you need your own server, Firebase doesn't facilitate for that.
I try this code for GCM push notification.
In this for send notification I use this. But it shows the message like Cool! Message sent successfully check your device... But My device does not receive Notification.
Try Firebase, here is the documentation of Push-Notification https://firebase.google.com/docs/cloud-messaging/ or you can check this tutorial https://www.simplifiedcoding.net/android-push-notification-tutorial-using-firebase/
You should use FCM. See
1) Add this line to build.gradle: dependencies {
compile 'com.google.firebase:firebase-messaging:9.8.0'}
2) Add this service to manifest.
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
3) Add this class to your project. I suggest to you to save your FCM Token:
public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("FirebaseService", "Refreshed token: " + refreshedToken);
SharedPreferences sharedPref = getSharedPreferences("YOUR_SETTING_NAME", Context.MODE_PRIVATE);
//There are optional steps
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("token", refreshedToken);
//notify the token update
editor.putBoolean("tokenUpdate",true);
editor.commit();
//You can send this token to your server (if you have)
sendServer(refreshedToken)
}
}
4) Now register your app to https://console.firebase.google.com/. This will generate a JSON file that's you must put inside app folders.
5) For generate FCM message you have 2 possibility:
5.1) Use the default Firebase Console: https://console.firebase.google.com/project/fantamanager-2017/notification/compose
5.2) Built your server app (If you want, i can send to you my Php Server Code)
6) Add this Service to your Manifest.xml
<service android:name="FcmBroadcastReceiver">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
And create a class that can intercept the push:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final ID_NOTIFICATION = ...
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String from,data;
from=remoteMessage.getFrom());
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
data=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.
sendNotification(data);
}
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(ID_NOTIFICATION, notificationBuilder.build());
}
}
Or, if you have a custom service, change the body of onMessageReceived function with this:
Map data = message.getData();
if (data.containsKey(YOUR_DATA_FIELD_1)) {
String field1= data.get(YOUR_DATA_FIELD_1).toString();
String field2= data.get(YOUR_DATA_FIELD_2).toString();
....
sendNotification(field1,field2...);
return;
}
Did you try a part or whole code ? Coz last I saw , new applications for gcm are closed. Only FCM is available. So you need to register as they say , implement the json file in app and proceed. If you already had a project which implemented gcm and you tried part of this code , then please check if the key is proper and you have not copied they key from this project or something . or maybe some meta data from manifest file is missing.
I've searched a lot about notifications when the app is in the background or closed. I'm using Firebase Cloud Messaging by the way. It won't work for me. I've used the Android setup and when the app is in the foreground or the phone is not locked the notification is received.
When installed the token is printed correctly and subscribed to the topic.
When I send a notification when the app is active in the foreground (so screen is unlocked and app is shown) I receive the notification and title as stated in the onMessageReceived.
When I send a notification when the app is not shown but is still in recent apps and screen is unlocked I receive the notification with title and message as stated in notification payload.
When I send a notification when the app is not shown but is still in recent apps and screen is locked nothing is received.
When I send a notification when app is *closed and removed from recent apps nothing is received.
How can I change this so the app will always receive the notifications, even when closed or the phone is locked?
Ps. I read about the Doze modus with protected apps, even when I put my app with the protected ones I receive nothing. I'm testing on a Huawei P8 Lite.
AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<activity android:name=".activities.MainActivity"
android:configChanges="orientation"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".services.MyAppFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".services.FirebaseIDService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<receiver android:name=".services.NotificationReceiver" />
</application>
Gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.google.firebase:firebase-core:9.2.0'
compile 'com.google.firebase:firebase-messaging:9.2.0'
}
apply plugin: 'com.google.gms.google-services'
FirebaseMessagingService
public class MyAppFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO: Handle FCM messages here.
// If the application is in the foreground handle both data and notification messages here.
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated.
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
showNotification(getApplicationContext());
}
public static void showNotification(Context context){
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("FCM Message")
.setContentText("FCM Body")
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
FirebaseInstanceIDService
public class FirebaseIDService extends FirebaseInstanceIdService {
private static final String TAG = "FirebaseIDService";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
System.out.println("Devicetoken: " + refreshedToken);
FirebaseMessaging.getInstance().subscribeToTopic("/topics/myapp");
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(refreshedToken);
}
/**
* 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) {
// Add custom implementation, as needed.
}
}
Notification payload
{
"to": "/topics/mytopic",
"priority": "high",
"notification": {
"sound": "default",
"badge": "1",
"body": "the body text",
"title": "title text"
},
"data": {
"id": "id",
"channel": "channel"
}
}
EDIT - Add code for WakeFulBroadcastReceiver
public class NotificationReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// cancel any further alarms
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmMgr.cancel(alarmIntent);
completeWakefulIntent(intent);
// start the GcmTaskService
MyAppFirebaseMessagingService.showNotification(context);
}
}
UPDATE PAYLOAD
If I change my payload to the suggested way in the comments like this it is still not working. Maybe it has something to do with the Huawei P8 Lite that I'm testing on with Android 6.0.1 installed.
{
"to": "/topics/mytopic",
"priority": "high",
"data": {
"sound": "default",
"badge": "1",
"body": "the body text",
"title": "title text"
}
}
UPDATE 2.0
I've tested on multiple devices and versions. On devices with Android 5 it was working fine, also without app open and screen locked. Only device it wasn't working was my own Huawei P8 Lite. Still can't figure out why it's not working on that one.
When the app is closed, it shutdowns the service. You must to restart the service.
On your Application class, implements ActivityLifecycleCallbacks and on onActivityDestroyed restart the service with an alarm.
public class YourApplication extends Application implements Application.ActivityLifecycleCallbacks {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityDestroyed(Activity activity) {
Intent restartService = new Intent(getApplicationContext(), MyAppFirebaseMessagingService.class);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),1,restartService,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME,5000,pendingIntent);
}
}
I also had issues with devices not receiving the notifications when they were closed, like they would be after a restart.
Turned out, it wasn't working with a DEBUG version of the solution, so that had to be tested in RELEASE MODE. For those using Android Studio, press the Green Play Button next to the debug button.
Firebase has different types of notifications, and each has special handling.
Assuming you're using a data push, you don't need special handling or a WakefulBroadcastReceiver.
If you're using a notification push, the notification will appear automatically in the system tray. You cannot do any special handling there.
Check the official documents here: https://firebase.google.com/docs/cloud-messaging/android/receive