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