The new GCM 3.0 should allow GCM to automatically display notifications sent from server if they contain the notification parameter.
As said in the docs:
The notification parameter with predefined options indicates that GCM will display the message on the client app’s behalf if the client app implements GCMListenerService on Android
However I have trouble getting that to work even though the GCMListenerService is implemented.
AndroidManifest.xml
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="cz.kubaspatny.pushservertest" />
</intent-filter>
</receiver>
<service
android:name="cz.kubaspatny.pushservertest.gcm.CustomGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
CustomGcmListenerService.java
public class CustomGcmListenerService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle extras) {
super.onMessageReceived(from, extras);
Log.d("GcmListenerService", "Received gcm from " + from + " with bundle " + extras.toString());
}
}
The notification from server is logged but not shown by GCM.
Received gcm from 333813590000 with bundle Bundle[{notification={"icon":"ic_launcher.png","body":"great match!","title":"Portugal vs. Denmark"}, collapse_key=do_not_collapse}]
The message sent from server:
{
"registration_ids":[...],
"data": {
"notification" : {
"body" : "great match!",
"icon" : "ic_launcher.png",
"title" : "Portugal vs. Denmark"
}
}
}
Is there anything else needed to be done to allow the automatic display?
Try making the notification field a sibling of the data field. The data field is passed to onMessageReceived and the notification field is used to automatically generate the notification.
{
"registration_ids":[...],
"notification" : {
"body" : "great match!",
"icon" : "ic_launcher.png",
"title" : "Portugal vs. Denmark"
}
}
Related
I use firebase messaging to send push notification. I have a small problem with my android app. In the iOS version, I can easily pass parameters after clicking on a notification when the app is in background.
In Android version I can intercept messages when the app is in the foreground, but not when the app is in the background (I use library com.google.firebase:firebase-messaging:17.3.4):
my AndroidManifest.xml
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="OPEN_NOTIFY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
....
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
My notification payload:
notification:{
title: "mytitle",
text: "MYTEXT",
"data":{
"type" : "message",
"id_message" : res
},
"click_action" : "OPEN_NOTIFY"
},to: token
When I click on the notification, it should open the MainActivity and I would like to have the id_message
my MyFirebaseMessagingService.java
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
//never enters if the app is in background
if(remoteMessage.getNotification() != null){
//I READ NOTIFY WHEN APP IS IN FOREGROUND
}
}
I try to get parameters directly from the Inten, but this solution doesn't work
my MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
....
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d(TAG, "Key: " + key + " Value: " + value);
}
}
....
}
I can't intercept my notify:
output:
Key: google.sent_time Value: 1540026384768
Key: google.ttl Value: 2419200
Key: from Value: 635549396240
Key: google.message_id Value: 0:1540026384773623%6b8fed3d6b8fed3d
Key: collapse_key Value: ....
Am I following the right path? Thank You
According to official Firebase docs, you can't handle notification{} part of notification (you can only set icon of it in manifest), BUT here's solution: send necessary data via data{} part. You can now handle it with MyFirebaseService and show notification if you want and as you want: data will appear in remoteMessage.toIntent().getExtras().
In your case, send notification like this:
// ignore notification {}
data {
"type" : "message",
"id_message" : res
}
to: key
(do not place data into notification block)
I can write working code of sending and receiving notification, if you want
I have a problem with FCM functionality. When the phone is awake everything is working (notifications are received when the app is in foreground, background or even if the app is dead).
The problem starts when the phone is entering deep sleep.
As I remember wakelocks are not mandatory with FCM.
I'm pushing "data" type notification with "priority":"high" which should wake up the device.
Problem is that notifications will be received when the phone will awake.
public class FCMCallbackService extends FirebaseMessagingService {
private static final String TAG = "FCMCallbackService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent i = new Intent(this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
public class FCMInitializationService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
...
}
}
In manifest:
<service android:name="gcmpush.FCMInitializationService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name="gcmpush.FCMCallbackService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
How can I wake application using push if the phone is sleeping? What is missing?
BDW - if I'm connected to WiFi and phone will go to sleep, but the application is not working - will it use WiFi to receive push? FCM can start the dead application. But if the app is dead, WiFi lock is not acquired. Can in such case device communicate with FCM Server?
The following message will not call your onMessageReceived() when your app is in the background or killed, and you can't customize your notification.
{
"to": "/topics/journal",
"notification": {
"title" : "title",
"text": "data!",
"icon": "ic_notification"
}
}
but instead using this will work
{
"to": "/topics/dev_journal",
"data": {
"text":"text",
"title":"",
"line1":"Journal",
"line2":"some data"
}
}
See ref link here
I'm developing an Android App that receives push notifications from Firebase.
I can get the token and send push notifications from Postman without any problem.
If the App is in foreground everything works as expected and I receive the payload in the onMessageReceived (I tested with various payloads).
But if I close the App it don't receive nothing. I tried with a lot of payloads, and I read all the documentation (diference between data and notification in payload).
Here's my classes that my project uses:
1 - The class that extends FirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "Android Push App";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
sendNotification("Received notification");
}
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.push_icon)
.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());
}
2 - The class that is responsible for get the token
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static String TAG = "Android Push App";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
Log.d(TAG, "Did obtained token");
Log.d(TAG, token);
}
3 - My Manifest:
<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" />
<action android:name="FIREBASE_ACTIVITY" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:name=".push.core.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".push.core.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/push_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
</application>
4 - The MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d("MainActivity", "Key: " + key + " Value: " + value);
}
}
}
5 - Finally I tried this payload in the Postman
POST https://fcm.googleapis.com/fcm/send
Content-Type application/json
Authorization key=AIzaSy(...)kY
JSON Body (the examples I tried):
{
"to": "dxe0RDKbP...m9Uc","notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}}
And:
{
"to": "dxe0RDKbP...m9Uc","notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}}
And:
{
"to": "d3j-9OJ6R...C6w",
"notification" : {
"title": "title",
"body": "body"
},
"data": {
"tipo": "normal"
}}
Also added the "priority" key and it doesn't work.
What I'm I doing wrong?
Thanks for all the help you can gave to me :)
UPDATE
Now it's working.
There was a conflict between the FireBaseMessagingService and a Geofence Push that is running (fired by the App).
After removed this Geofence service everything works as expected.
Also use the notification and data keys in the payload of the push.
Thanks
Try this
you must not put JSON key 'notification' in your request to firebase API but instead use 'data'.
Example
use this
{
"to": "dxe0RDKbP...m9Uc",
"data": {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}
}
EDIT
you can try with only body and title
{
"to": "dxe0RDKbP...m9Uc",
"data": {
"body" : "great match!",
"title" : "Portugal vs. Denmark"
}
}
Edit New
Add this in your manifest file android:stopWithTask="false" service property.
<service
android:name="com.yourapp.YourPushService"
android:stopWithTask="false"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
you need to remove notification payload from the json and add a data payload to it. This is because Android has an inbuilt functionality of taking care of notification when it sees notification payload, i.e., it, whenever notification payload is sent android directly sends it to system dray and onMessageReceived function, is not called.
As per the firebase documentation, Firebase notifications behave differently depending on the foreground/background state of the receiving app.
onMessageReceived is provided for most message types, with the following exceptions:
Notification messages delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default.
Messages with both notification and data payload, both background and foreground. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
So you need to remove notification payload from your json and only need to keep data payload to trigger onMessageReceived when app is in background.
Link:https://firebase.google.com/docs/cloud-messaging/android/receive
I developing an Ionic 2 app and testing on Android emulator.
When the app is in background and the notification has no title, no message and content-available=1 the notification should be sent directly to app notification handler. But its not happening.
I can receive notifications with the app in foreground.
If I have a title and a message I receive the notification in the notification area. But I need to send the notification directly to the app in silent mode, without pass by the notification area.
Here is my code to send push notifications:
{
"delay_while_idle": true,
"priority": "high",
"sound": "default",
"color": "FFFF00",
//payload
"data": {
"content-available": "1",
"some_var": "some_value",
"ohter_var": "other_value",
}
}
How could I sent silent notifications to my Android app?
Android GCM and FCM both also work when app background.
For that you need to add below service classes at manifest with intent Filter.
<!-- [START gcm_listener] -->
<service
android:name=".gcm.GcmListener"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".gcm.TokenRefreshService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".gcm.RegistrationIntentService"
android:exported="false" />
<!-- [END gcm_listener] -->
public class GcmListener extends GcmListenerService {
}
public class TokenRefreshService extends InstanceIDListenerService {
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
To get token:
public class RegistrationIntentService extends IntentService {
// TODO: Rename actions, choose action names that describe tasks that this
private String TAG = "RegistrationIntentService";
public RegistrationIntentService() {
super("RegistrationIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken("PRODUCT_ID",
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
}
}
I am trying to setup push notifications to my app containing both data and notification payloads as described in the official reference. I want both payloads so that I will get an automatic notification when my app is in the background, and the app can handle things itself while in the foreground.
The onMessageReceived() method in my GcmListenerService is not called when both payloads are included and the app is in the foreground. I have to leave out the notification payload for it to work.
When the app is in the background, it works fine. I get a notification and can open the app when the notification is clicked and do whatever I want from there.
I have looked at this question, but they were trying to get a notification when the app is in foreground. I realize I won't get a notification in that case, I just want to get the data.
Relevant portion of AndroidManifest.xml:
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="arkenterprises.garage_o_matic.gcm" />
</intent-filter>
</receiver>
<service
android:name=".MyGcmListenerService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
MyGcmListenerService.java:
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
#Override
public void onMessageReceived(String from, Bundle data) {
Log.d(TAG, "Data: " + data);
String message = data.getString("message");
String doorStatus = data.getString("DoorStatus");
String time = data.getString("time");
Bundle notification = data.getBundle("notification");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
Log.d(TAG, "DoorStatus: " + doorStatus);
Log.d(TAG, "Time: " + time);
Log.d(TAG, "Notification: " + notification);
}
Server code that sends the message:
nowString = datetime.datetime.now().strftime("%c")
gcmSendURL = 'https://gcm-http.googleapis.com/gcm/send'
gcmHeaders = {'Authorization': 'key=' + API_KEY, 'Content-Type': 'application/json'}
gcmDataPayload = {'message': 'Garage door opened', 'DoorStatus': 'Open', 'time': nowString}
gcmNotificationPayload = {'title': 'Garage Door Has Opened', 'body': 'Garage door opened at {}'.format(nowString), 'icon': 'ic_door_open_notification2'}
print('Garage door opened at {}'.format(nowString))
gcmPayload = {'to': regIDs[0].strip(), 'priority': 'high', 'delay_while_idle': False, 'time_to_live': 86400, 'data': gcmDataPayload}
# gcmPayload = {'to': regIDs[0].strip(), 'priority': 'high', 'delay_while_idle': False, 'time_to_live': 86400, 'notification': gcmNotificationPayload}
# gcmPayload = {'to': regIDs[0].strip(), 'priority': 'high', 'delay_while_idle': False, 'time_to_live': 86400, 'content_available': True, 'data': gcmDataPayload, 'notification': gcmNotificationPayload}
print("\nPayload: {}".format(gcmPayload))
r = requests.post(gcmSendURL, headers=gcmHeaders, json=gcmPayload)
print("\nRequest response: " + r.text)
Yes, you can send messages that have both notification and data payloads.
I found this Stack overflow ticket related to your inquiry, It says that Intent filters will always fire your manifested application as per standard android behavior. Make sure that your logic flow is able to handle the fact that your launch may come from places. Try to implement 'GcmMessageHandler' your application must check saved state and sees if user needs to see screen and automatically show notifications.
I had some strange behaviour with samples, but in final I resolved that by removing implementation of GcmListenerService and adding implementation of GcmReceiver.
public class MyGcmReceiver extends GcmReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
}
};
and manifest
<receiver
android:name=".MyGcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>