我们正在开发一个使用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
答案 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帐户配置错误(密码已更改)。
正确设置登录名和密码后,我的应用程序运行良好。
确保它有效: