Some devices does not receive GCM push eventhough all messages succeed from server

ε祈祈猫儿з 提交于 2019-12-07 19:01:17

问题


We're developing an application that uses GCM. It works fine on most phones, however, we have two phones (galaxy note 2 and galaxy s plus) which does not receive the messages. Or maybe it's just the broadcast receiver not being called.

Server side push:

$data = array(
        'data' => array('message' => $messageData),
        'delay_while_idle' => false,
        'type' => 'New',
        'flag' => 1,
        'registration_ids' => $registrationIdsArray
    );

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_URL, "https://android.googleapis.com/gcm/send");
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

    $response = curl_exec($ch);
    curl_close($ch);

Response receiver when sending push:

{
   "multicast_id":4735518740307255391,
   "success":4,
   "failure":0,
   "canonical_ids":0,
   "results":[
      {
         "message_id":"0:1390919813717906%2d15d04af9fd7ecd"
      },
      {
         "message_id":"0:1390919813717694%2d15d04af9fd7ecd"
      },
      {
         "message_id":"0:1390919813717290%2d15d04af9fd7ecd"
      },
      {
         "message_id":"0:1390919813717907%2d15d04af9fd7ecd"
      }
   ]
}

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.innocreate.app"
    android:versionCode="2"
    android:versionName="0.1.1" >

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="17" />

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

    <permission android:name="com.innocreate.app.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="com.innocreate.app.permission.C2D_MESSAGE" />
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:logo="@drawable/menu"
        android:theme="@style/Theme.Styled" >
        <meta-data
            android:name="AA_DB_VERSION"
            android:value="3" />
        <meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />

        <activity
            android:name="com.innocreate.app.NavigationParent"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.Styled"
            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="com.innocreate.app.DibsPaymentActivity" >
        </activity>

        <service
            android:name="com.octo.android.robospice.GsonSpringAndroidSpiceService"
            android:exported="false" />

        <receiver
            android:name="com.innocreate.app.gcm.GCMBroadcastReceiver"
            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="com.app.muf_appen" />
            </intent-filter>
        </receiver>
        <service android:name="com.innocreate.app.gcm.GCMIntentService" />
        <service android:name="com.innocreate.app.gcm.GCMRegistrationService" />

    </application>

</manifest>

GcmIntentService.java

public class GCMIntentService extends IntentService {

    public GCMIntentService(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;

    public GCMIntentService() {
        super("GCMIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent); 

        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
            /*
             * Filter messages based on message type. Since it is likely that GCM
             * will be extended in the future with new message types, just ignore
             * any message types you're not interested in, or that you don't
             * recognize.
             */
            if (GoogleCloudMessaging.
                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
//                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_DELETED.equals(messageType)) {
//                sendNotification("Deleted messages on server: " +
//                        extras.toString());
            // If it's a regular GCM message, do some work.
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {

//                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                // Post notification of received message.
                sendNotification(extras.getString("message"));
//                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
//        GCMBroadcastReceiver.completeWakefulIntent(intent);
    }

    // Put the message into a notification and post it.
    // This is just one simple example of what you might choose to do with
    // a GCM message.
    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, NavigationParent.class), PendingIntent.FLAG_UPDATE_CURRENT);

        Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        long[] vibration = {0, 200, 50, 200};
        Builder mBuilder =
                new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle("MUF - Nyhet")
        .setContentText(msg)
        .setVibrate(vibration);

        mBuilder.setContentIntent(contentIntent);

        Notification notification =  mBuilder.build();
        notification.flags |= Notification.FLAG_AUTO_CANCEL;


        mNotificationManager.notify(NOTIFICATION_ID, notification);
    }

}

GcmBroadcastreceiver.java

public class GCMBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // Explicitly specify that GcmIntentService will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMIntentService.class.getName());

        // Start the service, keeping the device awake while it is launching.
        SharedPreferences p = context.getSharedPreferences(
                GCMRegistrationService.class.getSimpleName(),
                Context.MODE_PRIVATE);
        if (p.getBoolean("ENABLE_GCM", true)) {
            context.startService(intent.setComponent(comp));
        }
        setResultCode(Activity.RESULT_OK);
    }

}

GcmRegistrationService.java

public class GCMRegistrationService extends Service {

    public static final String REGISTRATION_ID_EXTRA = "REGISTRATION_ID_EXTRA";
    public static final String BACKOFF_TIME_EXTRA = "BACKOFF_TIME_EXTRA";
    public static final String PROPERTY_REG_ID = "PROPERTY_REG_ID";
    public static final String PROPERTY_APP_VERSION = "PROPERTY_APP_VERSION";
    private static final String BACKEND_REGISTRATION_URL = "MY URL (REMOVED)";
    private static final String SENDER_ID = "MY SENDER ID (REMOVED)";



    private String mRegistrationId;
    private GoogleCloudMessaging mGCM;

    private Handler mHandler = new Handler();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub

        // try request
        Thread registerThread = new Thread(new Runnable() {

            @Override
            public void run() {
                long currentBackoffTime = 1000;
                int iterationCounter = 0; // maximum number of iterations 11 => 4095 seconds
                while(!tryRegistration() && iterationCounter < 11) {
                    try {
                        Thread.sleep(currentBackoffTime);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    currentBackoffTime *= 2;
                    iterationCounter++;
                }
                stopSelf();
            }
        });

        registerThread.start();

        return super.onStartCommand(intent, flags, startId);
    }



    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }


    private boolean tryRegistration() {
        try {
            if (mGCM == null) {
                mGCM = GoogleCloudMessaging.getInstance(this);
            }
            mRegistrationId = mGCM.register(SENDER_ID);

            // You should send the registration ID to your server over HTTP,
            // so it can use GCM/HTTP or CCS to send messages to your app.
            // The request to your server should be authenticated if your app
            // is using accounts.
            sendRegistrationIdToBackend();

            // For this demo: we don't need to send it because the device
            // will send upstream messages to a server that echo back the
            // message using the 'from' address in the message.

            // Persist the regID - no need to register again.
            storeRegistrationId(this, mRegistrationId);
        } catch (IOException ex) {
            // If there is an error, don't just keep trying to register.
            // Require the user to click a button again, or perform
            // exponential back-off.
            return false;
        }
        return true;
    }

    private void sendRegistrationIdToBackend() throws IOException {
        RestMethod rm = new RestMethod(BACKEND_REGISTRATION_URL);
        rm.appendQueryParameter("gcm", mRegistrationId);
        rm.appendQueryParameter("from", "1");
        rm.execute(Type.POST);
        if(rm.mResponseCode >= 299) {
            throw new IOException();
        }
    }

    /**
     * Stores the registration ID and app versionCode in the application's
     * {@code SharedPreferences}.
     *
     * @param context application's context.
     * @param regId registration ID
     */
    private void storeRegistrationId(Context context, String regId) {
        final SharedPreferences prefs = getGCMPreferences(context);
        int appVersion = getAppVersion(context);
//      Log.i(TAG, "Saving regId on app version " + appVersion);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(PROPERTY_REG_ID, regId);
        editor.putInt(PROPERTY_APP_VERSION, appVersion);
        editor.commit();
    }


     /**
     * @return Application's version code from the {@code PackageManager}.
     */
    private static int getAppVersion(Context context) {
        try {
            PackageInfo packageInfo = context.getPackageManager()
                    .getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionCode;
        } catch (NameNotFoundException e) {
            // should never happen
            throw new RuntimeException("Could not get package name: " + e);
        }
    }


    private SharedPreferences getGCMPreferences(Context context) {
        // This sample app persists the registration ID in shared preferences, but
        // how you store the regID in your app is up to you.
        return getSharedPreferences(GCMRegistrationService.class.getSimpleName(),
                Context.MODE_PRIVATE);
    }



}

We've tried pretty much anything and nothing seems to work. The galaxy note 2 runs 4.3 without google account and on wifi. The Galaxy s plus runs android 2.3.5 with an google account on wifi.

We read that some devices on wifi would not receive GCM so we tried to restart the phones but nothing happened.

Thanks in advance for any clues or answers!

Kind Regards Johan Risch Simon Evertsson


回答1:


Unfortunately from my experience there will always be a number of users(but a really small percentage) that wont receive GCM.

One of the reasons that it didnt work on one of the phones we used was that its Google Play Services app wasnt installed correctly(and its essential for GCM).

And the biggest issue was that we couldnt re-install the Google Play Services through normal means(like a regular users) the google play store said it was already installed, but it was missing from the phone(got erased last year when google installed this on all phones without user notice, some bug occured on that particular phone->Prestigio PAPADUO)....another side effect of this was that no apps with Google maps inside could load maps->except the google maps app...

It could be just the phones themselves since it is working on many others like you said.




回答2:


The category in your broadcast receiver is wrong :

<receiver
    android:name="com.innocreate.app.gcm.GCMBroadcastReceiver"
    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="com.app.muf_appen" />
    </intent-filter>
</receiver>

It should be the package name of your app,com.innocreate.app, instead of com.app.muf_appen. This usually causes problems only in older Android versions.




回答3:


In my case, it was because the Google account linked to the device was misconfigured (password had changed).

Once the login and password had been correctly set, my application was working well.

To be sure it works :

  • reset your Google Account on your Android device
  • reboot it
  • reinstall your application to get another registration ID from GCM


来源:https://stackoverflow.com/questions/21409143/some-devices-does-not-receive-gcm-push-eventhough-all-messages-succeed-from-serv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!