Alex Andro
Alex Andro

Reputation: 137

GCM is not working

I decided to implement Google Cloud Messaging push notifications to notify users about news. I think it is topic messaging. For implement I took the Google GCM sample. I added all needed services, permissions and receiver in manifest. When I send a post request to Google GCM server, the response is true with message ID, but device doesn't notify. What is the matter? I tested in Bluestacks.

My manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="packagename" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="packagename.permission.C2D_MESSAGE" />

    <permission android:name="packagename.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".activities.MainActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTop" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".activities.BiographyActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:label="@string/title_biography"
            android:parentActivityName=".activities.MainActivity"
            tools:ignore="UnusedAttribute" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".activities.MainActivity" />
        </activity>
        <activity
            android:name=".activities.AboutActivity"
            android:label="@string/title_about_app" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".activities.MainActivity" />
        </activity>
        <activity android:name=".activities.CrashReportDialog"
            android:theme="@style/Theme.Dialog"
            android:process=":error_report"
            android:launchMode="singleInstance"
            android:excludeFromRecents="true"
            android:finishOnTaskLaunch="true" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <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" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="packagename" />
            </intent-filter>
        </receiver>
        <service
            android:name="packagename.AppGcmListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
        <service
            android:name="packagename.AppInstanceIDListenerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID"/>
            </intent-filter>
        </service>
        <service
            android:name="packagename.RegistrationIntentService"
            android:exported="false">
        </service>
    </application>

</manifest>

Main Activity:

public class MainActivity extends AppCompatActivity {    

    private BroadcastReceiver mRegistrationBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRegistrationBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                SharedPreferences sharedPreferences =
                        PreferenceManager.getDefaultSharedPreferences(context);
                boolean sentToken = sharedPreferences
                        .getBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, false);
                if (sentToken) {
                    Log.i("GCM", "Success!");
                } else {
                    Log.i("GCM", "Error!");
                }
            }
        };

        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
}

GCM Listener Service:

public class AppGcmListenerService extends GcmListenerService {

    private static final String TAG = "GCM";

    /**
     * Called when message is received.
     *
     * @param from SenderID of the sender.
     * @param data Data bundle containing message data as key/value pairs.
     *             For Set of keys use data.keySet().
     */
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message = data.getString("message");
        Log.d(TAG, "From: " + from);
        Log.d(TAG, "Message: " + message);

        /**
         * Production applications would usually process the message here.
         * Eg: - Syncing with server.
         *     - Store message in local database.
         *     - Update UI.
         */

        /**
         * In some cases it may be useful to show a notification indicating to the user
         * that a message was received.
         */
        sendNotification(message);
    }

    /**
     * Create and show a simple notification containing the received GCM message.
     *
     * @param message GCM message received.
     */
    private void sendNotification(String message) {
        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_app)
                .setContentTitle("GCM Message")
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}

Instance ID Listener Service:

public class AppInstanceIDListenerService extends InstanceIDListenerService {

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. This call is initiated by the
     * InstanceID provider.
     */
    @Override
    public void onTokenRefresh() {
        // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
}

Registration Intent Service:

public class RegistrationIntentService extends IntentService {

private static final String TAG = "GCM";

public RegistrationIntentService() {
    super(TAG);
}

@Override
protected void onHandleIntent(Intent intent) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    try {
        // In the (unlikely) event that multiple refresh operations occur simultaneously,
        // ensure that they are processed sequentially.
        synchronized (TAG) {
            // Initially this call goes out to the network to retrieve the token, subsequent calls
            // are local.
            InstanceID instanceID = InstanceID.getInstance(this);
            String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

            Log.d(TAG, "GCM Registration Token: " + token);

            subscribeTopics(token);

            // You should store a boolean that indicates whether the generated token has been
            // sent to your server. If the boolean is false, send the token to your server,
            // otherwise your server should have already received the token.
            sharedPreferences.edit().putBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, true).apply();
        }
    } catch (Exception e) {
        Log.d(TAG, "Failed to complete token refresh", e);
        // If an exception happens while fetching the new token or updating our registration data
        // on a third-party server, this ensures that we'll attempt the update at a later time.
        sharedPreferences.edit().putBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(GcmPreferences.REGISTRATION_COMPLETE);
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}

/**
 * Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
 *
 * @param token GCM token
 * @throws IOException if unable to reach the GCM PubSub service
 */
private void subscribeTopics(String token) throws IOException {
    GcmPubSub.getInstance(this).subscribe(token, "/topics/global", null);
}

}

My PHP POST request:

<?php
$postData = array('to' => '/topics/global',
                  'notification' => array(
                      'body' => 'GCM Topic Message',
                      'title' => 'Test message'));

$curl = curl_init('https://gcm-http.googleapis.com/gcm/send');

curl_setopt_array($curl, array(CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
    'Authorization:key=AIzaSyBbUfgnuDyAmO9G8wk6_eqwZFiYX0J0PxI',
    'Content-Type:application/json'
),
CURLOPT_POSTFIELDS => json_encode($postData)));

$response = curl_exec($curl);

if($response === false){
    die(curl_error($curl));
}

$responseData = json_decode($response, true);

// Print the date from the response
print_r($responseData);
?>

I tested POST request. Android app tested on Bluestacks App Player and real phone.

Upvotes: 0

Views: 2610

Answers (2)

Saurabh Ahuja
Saurabh Ahuja

Reputation: 473

Convert notification to data .

$postData = array('to' => '/topics/global',
                  'notification' => array(
                      'body' => 'GCM Topic Message',
                      'title' => 'Test message'));

$postData = array('to' => '/topics/global',
                  'data' => array(
                      'body' => 'GCM Topic Message',
                      'title' => 'Test message'));

Then only onMessagedReceived is called then on this method generate your own notification.Don't forget on creating your own notification icon,title,text are required field

Upvotes: 0

Arthur Thompson
Arthur Thompson

Reputation: 9225

It looks like you are trying to send a notification message from your PHP server. Notification messages allow you to specify the parameters of the notification on the server side, like you are doing here.

Notification messages on Android require the icon field which you are not including, check the full list of notification message fields to be sure you are including all necessary fields different platforms.

Also the quickstart that you are using handles downstream messages via the data field. Messages sent via the notification field are handled by the library thus onMessageReceived is never called. You must send messages via the data field for onMessageReceived to be called. Consider the GCM Sender in the same quickstart for an example.

Upvotes: 1

Related Questions