GCM android 客户端未接收消息

GCM android client is not receiving messages

我正在尝试在我的 android 应用程序中实施 GCM,几乎所有教程都不是最新的,我遵循了 android GCM 快速入门,但不幸的是我无法收到消息(GcmListenerService.onMessageReceived 根本没有调用!)。 在服务器上,尝试发送消息时,我收到以下结果{"multicast_id":6757219588450825294,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1436444559760181%ad103adbf9fd7ecd"}]} 我的代码:
manifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qaof.mkm.endakkhabar" >

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

RegistrationIntentService:

public class RegistrationIntentService extends IntentService {

private static final String TAG = "RegIntentService";

private static final String[] TOPICS = {"mytopic"};

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) {
            // [START register_for_gcm]
            // Initially this call goes out to the network to retrieve the token, subsequent calls
            // are local.
            // [START get_token]
            InstanceID instanceID = InstanceID.getInstance(this);
            String token = instanceID.getToken(getString(R.string.sender_id),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
            // [END get_token]
            Log.i(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.
            if(sendRegistrationToServer(token))
            sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
            // [END register_for_gcm]
        }
    } 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(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}

/**
 * Persist registration to third-party servers.
 *
 * Modify this method to associate the user's GCM registration token with any server-side account
 * maintained by your application.
 *
 * @param token The new token.
 */
int tries=0;
private Boolean sendRegistrationToServer(String token) {
    String myurl="http://flowofapps.com/xx"+token;//save token
    InputStream is=null;
    try {
        try {
            URL url = new URL(myurl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(10000 /* milliseconds */);
            conn.setConnectTimeout(15000 /* milliseconds */);
            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            // Starts the query
            conn.connect();
            is = conn.getInputStream();
            String message = IOUtils.toString(is, "UTF-8");
            if(message.contains("ok")||message.contains("exist")||tries++<3){
                return true;
            }
            else
                sendRegistrationToServer(token);

        } finally {
            if (is != null) {
                is.close();
            }
        }
    } catch (IOException e) {

    }
    return false;

}

/**
 * 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
 */
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
    for (String topic : TOPICS) {
        GcmPubSub pubSub = GcmPubSub.getInstance(this);
        pubSub.subscribe(token, "/topics/" + topic, null);
    }
}
// [END subscribe_topics]
}

MyGcmListenerService:

public class MyGcmListenerService extends GcmListenerService {

private static final String TAG = "MyGcmListenerService";

/**
 * 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().
 */
// [START receive_message]


@Override
public void onMessageReceived(String from, Bundle data) {
    String message = data.getString("message");
    Log.d(TAG, "From: " + from);
    Log.d(TAG, "Message: " + message);


    sendNotification(message);
}
// [END receive_message]

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_setting_dark)
            .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());
}
}

MyInstanceIDListenerService:

public class MyInstanceIDListenerService extends InstanceIDListenerService {

private static final String TAG = "MyInstanceIDLS";

/**
 * 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.
 */
// [START refresh_token]
@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);
}
// [END refresh_token]
}

最后,在我的主 activity:

 @Override
protected void onCreate(Bundle savedInstanceState) {
...
 SharedPreferences sharedPreferences =
            PreferenceManager.getDefaultSharedPreferences(this);
    boolean sentToken = sharedPreferences
            .getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
    if(!sentToken) {
        if (checkPlayServices()) {
            // Start IntentService to register this application with GCM.
            Intent intent = new Intent(this, RegistrationIntentService.class);
            startService(intent);
        }
    }
    else{
        Intent intent_receiver = new Intent(this, MyGcmListenerService.class);
        startService(intent_receiver);
    }

}

    private boolean checkPlayServices() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    if (resultCode != ConnectionResult.SUCCESS) {
        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
        } else {
            Log.i(TAG, "This device is not supported.");
            finish();
        }
        return false;
    }
    return true;
}

@Override
protected void onResume() {
          LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
            new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
    super.onResume();
}

@Override
protected void onPause() {
    LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
    super.onPause();
}

提前致谢。

问题似乎出在您的清单中:

<!-- [START gcm_listener] -->
<service
    android:name="com.qaof.mkm.endakkhabar.RegistrationIntentService"
    android:exported="false" >
</service>
<intent-filter>
    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
<!-- [END gcm_listener] -->

意图过滤器需要在服务元素内,即

<!-- [START gcm_listener] -->
<service
    android:name="com.qaof.mkm.endakkhabar.RegistrationIntentService"
    android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>
<!-- [END gcm_listener] -->