正在使用 Google Cloud Messenger 令牌订阅主题,收到无效参数
Subscribing topics with Google Cloud Messenger token, Invalid argument received
我正在按照 google 提供的示例注册 gcm 令牌:
https://developers.google.com/cloud-messaging/android/start
我已经正确生成了 google-services.json 文件并且我能够接收推送令牌。但是当我尝试使用以下代码订阅任何主题时:
// Register the user to the global topic. This will help the device to be register on GCM
GcmPubSub pubSub = GcmPubSub.getInstance(this);
pubSub.subscribe(token, "/topics/global", null);
它抛出 INVALID_ARGUMENT 异常:
01-05 14:05:24.435 D/RegIntentService( 4330): java.io.IOException: INVALID_PARAMETERS
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.zzc.zzb(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.zzc.zza(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.InstanceID.zzc(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.InstanceID.getToken(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.gcm.GcmPubSub.subscribe(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at gcm.play.android.samples.com.gcmquickstart.RegistrationIntentService.subscribeTopics(RegistrationIntentService.java:105)
01-05 14:05:24.435 D/RegIntentService( 4330): at gcm.play.android.samples.com.gcmquickstart.RegistrationIntentService.onHandleIntent(RegistrationIntentService.java:65)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.Handler.dispatchMessage(Handler.java:99)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.Looper.loop(Looper.java:137)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.HandlerThread.run(HandlerThread.java:60)
这是我收到的推送令牌的示例:
e3r6xnFGK3E:APA91bG9oY0A7QCf86BXXh8ADzycct5QJUONTXMH3pApCkcwty0A6UXo6zLLx3Hl3ubMgBY65ldxuZzSF20nahZAq-4SiUMRS0YYStJtldK85lzrO-xM5KvM_Jigpaka-RN5TLb8D1Op
我已经查看了有关订阅主题的文档,但没有说明我收到 INVALID_PARAMETER 异常的原因:
感谢任何帮助。
P.d。有注册代币的完整源代码:
import android.annotation.SuppressLint;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
import com.google.android.gms.gcm.GcmPubSub;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.android.gms.iid.InstanceID;
/**
* Intent service used to retrieve and save the registration token needed
* Extracted from here
* https://github.com/googlesamples/google-services/blob/master/android/gcm/app/src/main/java/gcm/play/android/samples/com/gcmquickstart/RegistrationIntentService.java
*/
public class RegistrationIntentService extends IntentService {
public static final String TAG = "RegistrationIntentService";
public static final String INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK =
"services.RegistrationIntentService.INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK";
private ResultReceiver mResultReceiver;
public static final String BUNDLE_KEY_GCM_TOKEN =
"services.RegistrationIntentService.BUNDLE_KEY_GCM_TOKEN";
public RegistrationIntentService() {
super(TAG);
}
@SuppressLint("LongLogTag")
@Override
protected void onHandleIntent(Intent intent) {
// Get the result receiver
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK)) {
mResultReceiver = (ResultReceiver)extras.get(INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK);
}
try {
InstanceID instanceId = InstanceID.getInstance(this);
String token = instanceId.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Send registration token to the server
if (mResultReceiver != null) {
Bundle bundle = new Bundle();
bundle.putString(BUNDLE_KEY_GCM_TOKEN, token);
mResultReceiver.send(0, bundle);
}
// Register the user to the global topic. This will help the device to be register on GCM
GcmPubSub pubSub = GcmPubSub.getInstance(this);
pubSub.subscribe(token, "/topics/global", null);
Logger.v(TAG, "User correctly register to the global token");
} catch (Exception e) {
Log.d(TAG, "Faield to complete token refresh", e);
}
}
}
这是google-services.json
的内容
{
"project_info": {
"project_id": "NOT_SHOWN-aa10f",
"project_number": "11046079110",
"name": "NOT_SHOWN"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:11046079110:android:b918cc51ed907631",
"client_id": "android:NOT_SHOWN",
"client_type": 1,
"android_client_info": {
"package_name": "NOT_SHOWN"
}
},
"oauth_client": [],
"api_key": [],
"services": {
"analytics_service": {
"status": 1
},
"cloud_messaging_service": {
"status": 2,
"apns_config": []
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"google_signin_service": {
"status": 1
},
"ads_service": {
"status": 1
}
}
}
],
"client_info": [],
"ARTIFACT_VERSION": "1"
}
看来none到目前为止已经解决了这个问题,所以我将给出我找到的解决方案。
问题是我们有几个注册 GCM 的进程。因此,在 60% 的情况下发生的情况是,在我们注册自己的设备后,在同一个应用程序中,另一个进程在 GCM 上向其自己的发送者注册。因此,当我们尝试订阅主题时,gcm 令牌无效,因为同一设备、同一应用程序已为另一个发件人注册了 gcm。
为了解决这个问题,我们所做的是从另一个进程获取发件人 ID,然后将其附加到我们的发件人。
假设我们的发件人id是“1234567”,他的发件人id是“7654321”,所以当我们在GCM上注册我们的应用程序时,我们不是只解析“1234567”,而是使用“1234567,7654321”,分开昏迷
这允许我们获得一个对我们和另一个进程都有效的 GCM 令牌,而如果另一个进程在我们之后注册 GCM,它不会使自己的 GCM 令牌无效。 (他的 GCM 令牌仍然有效,因为我们将其发送者作为请求的一部分包含在内)。
来自迪拜的欢呼!
我正在按照 google 提供的示例注册 gcm 令牌: https://developers.google.com/cloud-messaging/android/start
我已经正确生成了 google-services.json 文件并且我能够接收推送令牌。但是当我尝试使用以下代码订阅任何主题时:
// Register the user to the global topic. This will help the device to be register on GCM
GcmPubSub pubSub = GcmPubSub.getInstance(this);
pubSub.subscribe(token, "/topics/global", null);
它抛出 INVALID_ARGUMENT 异常:
01-05 14:05:24.435 D/RegIntentService( 4330): java.io.IOException: INVALID_PARAMETERS
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.zzc.zzb(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.zzc.zza(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.InstanceID.zzc(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.iid.InstanceID.getToken(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at com.google.android.gms.gcm.GcmPubSub.subscribe(Unknown Source)
01-05 14:05:24.435 D/RegIntentService( 4330): at gcm.play.android.samples.com.gcmquickstart.RegistrationIntentService.subscribeTopics(RegistrationIntentService.java:105)
01-05 14:05:24.435 D/RegIntentService( 4330): at gcm.play.android.samples.com.gcmquickstart.RegistrationIntentService.onHandleIntent(RegistrationIntentService.java:65)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.Handler.dispatchMessage(Handler.java:99)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.Looper.loop(Looper.java:137)
01-05 14:05:24.435 D/RegIntentService( 4330): at android.os.HandlerThread.run(HandlerThread.java:60)
这是我收到的推送令牌的示例:
e3r6xnFGK3E:APA91bG9oY0A7QCf86BXXh8ADzycct5QJUONTXMH3pApCkcwty0A6UXo6zLLx3Hl3ubMgBY65ldxuZzSF20nahZAq-4SiUMRS0YYStJtldK85lzrO-xM5KvM_Jigpaka-RN5TLb8D1Op
我已经查看了有关订阅主题的文档,但没有说明我收到 INVALID_PARAMETER 异常的原因:
感谢任何帮助。
P.d。有注册代币的完整源代码:
import android.annotation.SuppressLint;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
import com.google.android.gms.gcm.GcmPubSub;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.android.gms.iid.InstanceID;
/**
* Intent service used to retrieve and save the registration token needed
* Extracted from here
* https://github.com/googlesamples/google-services/blob/master/android/gcm/app/src/main/java/gcm/play/android/samples/com/gcmquickstart/RegistrationIntentService.java
*/
public class RegistrationIntentService extends IntentService {
public static final String TAG = "RegistrationIntentService";
public static final String INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK =
"services.RegistrationIntentService.INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK";
private ResultReceiver mResultReceiver;
public static final String BUNDLE_KEY_GCM_TOKEN =
"services.RegistrationIntentService.BUNDLE_KEY_GCM_TOKEN";
public RegistrationIntentService() {
super(TAG);
}
@SuppressLint("LongLogTag")
@Override
protected void onHandleIntent(Intent intent) {
// Get the result receiver
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK)) {
mResultReceiver = (ResultReceiver)extras.get(INTENT_KEY_UPDATE_SERVER_TOKEN_CALLBACK);
}
try {
InstanceID instanceId = InstanceID.getInstance(this);
String token = instanceId.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Send registration token to the server
if (mResultReceiver != null) {
Bundle bundle = new Bundle();
bundle.putString(BUNDLE_KEY_GCM_TOKEN, token);
mResultReceiver.send(0, bundle);
}
// Register the user to the global topic. This will help the device to be register on GCM
GcmPubSub pubSub = GcmPubSub.getInstance(this);
pubSub.subscribe(token, "/topics/global", null);
Logger.v(TAG, "User correctly register to the global token");
} catch (Exception e) {
Log.d(TAG, "Faield to complete token refresh", e);
}
}
}
这是google-services.json
的内容{
"project_info": {
"project_id": "NOT_SHOWN-aa10f",
"project_number": "11046079110",
"name": "NOT_SHOWN"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:11046079110:android:b918cc51ed907631",
"client_id": "android:NOT_SHOWN",
"client_type": 1,
"android_client_info": {
"package_name": "NOT_SHOWN"
}
},
"oauth_client": [],
"api_key": [],
"services": {
"analytics_service": {
"status": 1
},
"cloud_messaging_service": {
"status": 2,
"apns_config": []
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"google_signin_service": {
"status": 1
},
"ads_service": {
"status": 1
}
}
}
],
"client_info": [],
"ARTIFACT_VERSION": "1"
}
看来none到目前为止已经解决了这个问题,所以我将给出我找到的解决方案。
问题是我们有几个注册 GCM 的进程。因此,在 60% 的情况下发生的情况是,在我们注册自己的设备后,在同一个应用程序中,另一个进程在 GCM 上向其自己的发送者注册。因此,当我们尝试订阅主题时,gcm 令牌无效,因为同一设备、同一应用程序已为另一个发件人注册了 gcm。
为了解决这个问题,我们所做的是从另一个进程获取发件人 ID,然后将其附加到我们的发件人。
假设我们的发件人id是“1234567”,他的发件人id是“7654321”,所以当我们在GCM上注册我们的应用程序时,我们不是只解析“1234567”,而是使用“1234567,7654321”,分开昏迷
这允许我们获得一个对我们和另一个进程都有效的 GCM 令牌,而如果另一个进程在我们之后注册 GCM,它不会使自己的 GCM 令牌无效。 (他的 GCM 令牌仍然有效,因为我们将其发送者作为请求的一部分包含在内)。
来自迪拜的欢呼!