GcmListenerService.onMessageReceived() not called

11,647

Solution 1

As explained in this Github issue which is exactly your problem:

From https://developers.google.com/cloud-messaging/server#notifications_and_data_messages "GCM will display the notification part on the client app’s behalf. When optional data is provided, it is sent to the client app once user clicks on the notification and opens the client app. [...] On Android, data payload can be retrieved in the Intent used to launch your activity."

So, the data is passed in the intent used to launch the activity, after the user taps on the notification. This means you need to do the following:

  • Add a click_action to the notification key you send from the server: e.g.

    send_queue.append({'to': REGISTRATION_ID,
                   'message_id': random_id(),
                   "notification" : {
                      "body" : "Hello from Server! What is going on? Seems to work!!!",
                      "title" : "Hello from Server!",
                      "icon" : "@drawable/ic_school_white_48dp",
                      "sound": "default",
                      "color": "#03A9F4",
                      "click_action": "OPEN_MAIN_ACTIVITY"
                    },
                   'data': { 'message': "Hello" }})
    

See the reference for notification payload at: https://developers.google.com/cloud-messaging/server-ref#notification-payload-support

  • In AndroidManifest.xml add an intent filter on the activity you want to be opened once the user clicks on the notification, with the same action name you used on the "click_action" key on the server side, e.g:

    <activity
        android:name=".ui.MainActivity"
        android:label="@string/title_activity_main" >
        <intent-filter>
            <action android:name="OPEN_MAIN_ACTIVITY" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
    
  • Get the data from the intent on your onCreate() method or on onNewIntent() if you've set the launchMode to singleTop for the activity you want to launch when the notification is clicked, e.g:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        Intent intent = getIntent();
    
        if (intent.hasExtra(Constants.KEY_MESSAGE_TXT)) {
            String message = intent.getStringExtra(Constants.KEY_MESSAGE_TXT);
            Log.d(TAG, message);
        } 
    }
    

I've tested this and can confirm that it works. (using XMPP connection)

Solution 2

The GcmListenerService.onMessageReceived() will not be called if the downstream message (json) contains a notification.

Solution 3

To receive the message in onMessageReceived you need to define the top level "data" field in your message object. The notification field is handled automatically and generates a notification, onMessageReceived does not get passed any of the data in the notification field.

Update your message object to include a data field and onMessageReceived should be called:

{
    "notification" : {
        "title" : "Title",
        "text" : "Message",
        "icon" : "@drawable\/ic_notification",
        "click_action" : "OPEN_MAIN_ACTIVITY"
    },
    "data": {
        "some_key": "some_value"
    },
    "registration_ids":[
        "xxxx", "xxxx", "xxxx", "etc"
    ]
}
Share:
11,647

Related videos on Youtube

Dan
Author by

Dan

Software Engineering student@Hogenschool van Amsterdam &amp; Intern Mobile App Development @53 Graden Noord

Updated on September 15, 2022

Comments

  • Dan
    Dan about 1 year

    I'm currently working on implementing GCM notifications into my app.

    The problem that I'm having is that the onMessageReceived() method from my GcmListenerService implementation isn't called. I receive the data from the GCM servers fine, since it automatically generates a notification (I wish to replace this with my own notification using the onMessageReceived() method) but after that none of my log calls are printed in the log.

    JSON that is sent from server to GCM server

    {
        "notification" : {
            "title" : "Title",
            "text" : "Message",
            "icon" : "@drawable\/ic_notification",
            "click_action" : "OPEN_MAIN_ACTIVITY"
        },
        "registration_ids":[
            "xxxx", "xxxx", "xxxx", "etc"
        ]
    }
    

    AndroidManifest.xml (GCM part only)

    <!-- GCM START -->
        <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="com.my.package" />
            </intent-filter>
        </receiver>
    
        <service
            android:name=".Services.ListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
    
        <service
            android:name=".Services.IDListenerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID"/>
            </intent-filter>
        </service>
        <!-- GCM END -->
    

    GcmListenerService (just a quick print to see if its called at all)

    public class ListenerService extends GcmListenerService {
    
        private static final String TAG = "MyGcmListenerService";
    
        @Override
        public void onMessageReceived(String from, Bundle data) {
            String message = data.getString("title");
            Log.d(TAG, "From: " + from);
            Log.d(TAG, "Message: " + message);
        }
    }
    

    Not sure if the method to request tokens is relevant, but I can post it if needed.

    If any part of the question is unclear, let me know, I'm not the best at explaining.

    • Alex Bitek
      Alex Bitek over 8 years
      @Dan The onMessageReceived isn't called when you send the "notification" key in the payload from the server, you have to get the data from an Intent. Only when you use the "data" key the onMessageReceived is called. You can use both, but you get the data from each one of the methods in different places.
  • Dan
    Dan over 8 years
    I'll give this a try when I get home tonight. Is there any way to make the notification field not auto generate a notification on Android so I can use my own implementation? Preferably without removing the whole notification field because I use it in iOS.
  • Arthur Thompson
    Arthur Thompson over 8 years
    I can't think of a good way of doing this. You could try leaving out the icon field since its required on android but not on iOS. So I assume it will be ignored on Android but you will still get the data part in onMessageReceived.
  • Dan
    Dan over 8 years
    Removing the "notification" block entirely did the trick and made the phone call onMessageReceived. It's not exactly how I want it but I'll find some way to deal with it. Do you know if it's possible to collapse multiple notifications into one so the user doesn't get spammed with notifications? See imgur.com/a/DlJV0 for image example (sortof)
  • Arthur Thompson
    Arthur Thompson over 8 years
    If by spammed you mean there are multiple notifications in the notification area, if the notifications have the same notification ID then the last one will replace the previous one. To stop subsequent notifications you will have to check if a notification has been set already via some variable.
  • Alex Bitek
    Alex Bitek over 8 years
    @Dan You don't have to remove the notification key to get the data. If you use the notification key you just get the data inside it in a different place, see my answer below.
  • Dan
    Dan over 8 years
    Fixed my issue, I came across that Github issue earlier, but didn't read it properly apparently, thanks for the clarification. Is there any way to update notifications client-side? As in not get spammed by 4 identical notifications, but just one? Sortof like this: imgur.com/a/DlJV0
  • Alex Bitek
    Alex Bitek over 8 years
    @Dan If you use the notification key, you can set the "tag" key for each notification that is the same as a previous one, and a new notification with the same tag will replace the previous one in the notification center. See the description of the "tag" key here. Also look at the "collapse_key" and delay_while_idle, which are useful to tell GCM what happens in scenarios when the notification can't be delivered right away and you retry.
  • Alex Bitek
    Alex Bitek over 8 years
    If you don't use the notification key, but the "data" key, you need to do the exclusion yourself by keeping track of the notifications previously shown.
  • Dan
    Dan over 8 years
    You're amazing, I'd give you 100 votes if I could. Thanks for your help.
  • Shiprack
    Shiprack over 7 years
    To elaborate @Zephyr's point, there are two kinds of payloads in a GCM message: Notification Messages and Data Messages. Notification messages don't invoke the onMessageReceived method if the app isn't active. They only cause the notification to be displayed in the notification tray. Data Messages will cause onMessageReceived to get called all the time, regardless of the app's state. See details here