有些设备从服务器获取所有消息后都不会收到GCM推送

时间:2014-01-28 15:02:35

标签: android push-notification broadcastreceiver google-cloud-messaging

我们正在开发一个使用GCM的应用程序。它适用于大多数手机,但是,我们有两部手机(Galaxy note 2和galaxy s plus)没有接收到这些信息。或者可能只是广播接收器没有被呼叫。

服务器端推送:

$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);

发送推送时的响应接收器:

{
   "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);
    }



}

我们已经尝试了很多东西,似乎什么都没有用。 Galaxy note 2运行4.3没有谷歌帐户和wifi。 Galaxy s plus在wifi上使用谷歌帐户运行Android 2.3.5。

我们读到wifi上的某些设备无法接收GCM,所以我们尝试重新启动手机但没有发生任何事情。

提前感谢任何线索或答案!

亲切的问候 约翰里施 Simon Evertsson

3 个答案:

答案 0 :(得分:3)

广播接收器中的类别错误:

<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>

应该是应用的包名称com.innocreate.app,而不是com.app.muf_appen。 这通常只会导致较旧的Android版本出现问题。

答案 1 :(得分:1)

不幸的是,根据我的经验,总会有很多用户(但只占很小的比例)不会收到GCM。

它在我们使用的其中一部手机上无法使用的原因之一是其Google Play服务应用未正确安装(并且对GCM至关重要)。

最大的问题是,我们无法通过正常手段(如普通用户)重新安装谷歌播放服务,谷歌游戏商店已经安装了它,但电话中丢失了它(去年时删除了)谷歌在没有用户通知的情况下在所有手机上安装了这个,在那个特定的手机上发生了一些错误 - &gt; Prestigio PAPADUO)....另一个副作用是没有谷歌地图里面的应用程序可以加载地图 - >谷歌地图除外应用...

它可能只是手机本身,因为它正在处理许多其他人,就像你说的那样。

答案 2 :(得分:0)

就我而言,原因是链接到设备的 Google帐户配置错误(密码已更改)。

正确设置登录名和密码后,我的应用程序运行良好。

确保它有效:

  • 在您的Android设备上重置您的Google帐户
  • 重启
  • 重新安装您的应用程序以从GCM获取另一个注册ID