GCM 和 Parse 通知冲突
Posted
技术标签:
【中文标题】GCM 和 Parse 通知冲突【英文标题】:GCM and Parse notification conflict 【发布时间】:2014-08-20 05:17:25 【问题描述】:我需要我的 android 应用程序使用两个推送服务,GCM 和解析。 我的问题是我找不到正确注册 Parse、获取解析通知和 GCM 通知的方法。我可以单独完成所有这些事情,但永远不能在一起。 我当前的实现是这样的:
<!-- GCM BradcastReceiver & Service -->
<service android:name=".GcmIntentService"
android:enabled="true"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:priority="100"> <!-- higher priority to GCM messages -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.twentyLines.GCM_NOTIFICATION_ACTION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
这是GCM的broadcastReceiver,下面是解析的另一个receiver:
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter android:priority="0">
<!--<action android:name="com.google.android.c2dm.intent.RECEIVE" />-->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Can remove this if application is already registered for GCM -->
<receiver android:name="com.parse.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
我尝试添加一个自定义广播接收器来处理解析通知,所以我也可以避免它来处理 GCM。我是这样做的:
<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
这是我的 BroadcastReceiver for GCM 的实现,可避免显示解析通知。
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
boolean isFromParse = intent.getExtras().get("action").equals("com.twentyLines.PARSE_NOTIFICATION_ACTION");
if (isFromParse)
return;
// 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.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_CANCELED);
这是我的 PARSE 自定义 BroadcastReceiver 的实现,它应该避免显示 GCM。 解析自定义接收器永远不会被调用,我认为是因为 com.parse.GcmBroadcastReceiver 处理通知本身而不是传递它们。 结果是,当我从服务器向 GCM 接收器发送通知时,会从两者中检索到该通知,并显示双重通知。 (双倍已经很好了,每次我卸载并重新安装我的应用程序解析注册另一个用户..我每次发送解析的“UniqueId”对他们来说不是那么独特)。
我尝试了什么? 我真的快疯了,我什么都试过了。
- I've read all related questions, and no one is good for me;
- I've tried to remove the parse receiver, and this cause a parse exception (so doesn't register to parse)
- I've tried to set the intent to RESULT_CANCELED, but in some way parse get it before GCM, so isn't working when I use GCM.
- I've changed about all using cowboy-coding, and it still not work...
任何帮助都将受到真正的欢迎。谢谢各位!
编辑 - 添加工作清单
<!-- GCM BradcastReceiver & Service -->
<service android:name=".GcmIntentService"
android:enabled="true"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:priority="2"> <!-- higher priority to GCM messages -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.twentyLines.GCM_NOTIFICATION_ACTION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Parse service broacastReceiver and receiver. -->
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter android:priority="1">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Can remove this if application is already registered for GCM -->
<receiver android:name="com.parse.ParseBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
编辑 2:我如何注册 PARSE 和 GCM
我在我的应用程序类中注册 Parse:
Parse.initialize(this, PARSE_APP_KEY_VALUE, PARSE_CLIENT_KEY_VALUE);
PushService.setDefaultPushCallback(getApplicationContext(), MainActivity.class);
final ParseInstallation installation = ParseInstallation.getCurrentInstallation();
final String androidId = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
Handler handler = new Handler();
handler.postDelayed(new Runnable()
@Override
public void run()
installation.put("UniqueId", androidId);
installation.saveInBackground(new SaveCallback()
@Override
public void done(ParseException e)
Log.d("Parse installation saved in background", "If operation successfull, 'e' have to be NULL e= " + e);
);
, 5000
);
我在 MainActivity 中获得了 gcm registration_id:
// Check if there is a saved registration_id in shared_prefs,
// or if app version has changed
private String getSavedRegistrationId()
final SharedPreferences gcmShared = getGCMSharedPrefss();
String registrationId = gcmShared.getString(Constant.GCM_REGISTRATION_ID_KEY, "");
if (registrationId.isEmpty())
Log.i("GCM", "Registration not found.");
return "";
int registeredVersion = gcmShared.getInt(Constant.APP_VERSION_KEY, Integer.MIN_VALUE);
int currentVersion = getAppVersion(this);
if (registeredVersion != currentVersion)
clearSavedGCMRegistrationId();
Log.i("GCM", "App version changed.");
return "";
return registrationId;
// If there isn't, request one
private void registerInBackground()
new AsyncTask<Void, Void, String>()
@Override
protected String doInBackground(Void... params)
String msg;
try
if (_gcm == null)
_gcm = GoogleCloudMessaging.getInstance(MainActivity.this);
String regid = _gcm.register(Constant.GCM_SENDER_ID);
msg = "Device registered, registration ID=" + regid;
sendRegistrationIdToBackend(regid);
storeRegistrationId(regid); // Save reg_id to shared
catch (IOException ex)
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the startupLoggedUser to click a button again, or perform
// exponential back-off.
return msg;
@Override
protected void onPostExecute(String msg)
Log.d("GCM registration", msg);
.execute(null, null, null);
【问题讨论】:
您能告诉我正确的清单吗?真的很有帮助 查看问题中的编辑。这对我有用! 如何获得 gcm reg_id?当我单独注册 gcm 注册 ID 时,解析停止工作,当我使用解析 deviceToken 时,其他 gcm 无法正常工作!你能分享你的经验吗?谢谢 嗨,你能详细说明一下你是如何做到这一点的吗?我也面临同样的问题。 @Khawar 我通过对我的后端的服务器请求获得 reg_id,该服务器负责管理 ID。 【参考方案1】:我们这里有两个广播接收器来监听 c2dm 意图
-
.GcmBroadcastReceiver : 我们将其称为 GCM 接收器... Parse Push 永远不会到达此接收器。
com.parse.GcmBroadcastReceiver : 我们称之为 Parse 接收器
由于您为 GCM 接收器提供了更高的优先级,因此广播将首先到达 GCM 接收器,然后到达 Parse 接收器。这并不能保证 Broadcast 不会去 Parse 接收器。您需要添加 abortBroadcast();作为 onReceive 方法的最后一行,以确保在 GCM 接收器工作时不会触发 Parse 接收器。
根据 Parse Push 通知指南,Push 是通过特定的意图操作接收的。数据被发送到使用该操作注册的广播接收器。 在您的情况下,如果通过操作“com.twentyLines.PARSE_NOTIFICATION_ACTION”收到推送,您可以使用自定义广播接收器来收听此操作。在该广播接收器中,您可以通过以下代码获取数据,
try
String action = intent.getAction();
String channel = intent.getExtras().getString("com.parse.Channel");
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
Log.d(TAG, "got action " + action + " on channel " + channel + " with:");
Iterator itr = json.keys();
while (itr.hasNext())
String key = (String) itr.next();
Log.d(TAG, "..." + key + " => " + json.getString(key));
catch (JSONException e)
Log.d(TAG, "JSONException: " + e.getMessage());
当有 GCM 推送时,此自定义接收器将永远不会收到广播事件,因为 C2DM 广播在 GCM 接收器(“.GcmBroadcastReceiver”)中被中止
希望这会有所帮助!
【讨论】:
非常感谢,我错过了 abortBroadcast()!花了一天的时间来丢失方法调用真是令人沮丧……无论如何,现在它正在工作,两者都使用 GCM 解析。有一个奇怪的事情:解析 ParseBroadcastReceiver 永远不会被调用!所有传入的通知都由 GCMReceiver 处理。好吧,它可以工作,但我看不出原因! 不确定为什么不调用 ParseBroadcastReceiver。但是,文档说如果我们有支持 GCM 的设备,则不需要 ParseBroadcastReceiver。请查看parse.com/docs/push_guide#receiving/Android中的“接收推送”部分 我已经读过很多遍了 ;) 我说的是我的 ParseBroadcastReceiver (com.twentyLines.app.ParseBroadcastReceiver)。我已经删除了解析(com.parse.ParseBroadcastReceiver)。“奇怪的事情发生在那些试图整合解析的人身上……”:D 哦,知道了 :) 可能是因为,android:exported="false"。尝试使用 android:exported="true" 不是这样的!听不懂很吵,不过没关系! ;) 非常感谢老兄!以上是关于GCM 和 Parse 通知冲突的主要内容,如果未能解决你的问题,请参考以下文章
使用 3rd 方库和为同一应用程序单独 GCM 实现时 GCM 注册步骤冲突?
亚马逊、解析、pushwoosh 和 Android 的默认 GCM 推送通知之间的区别?
MathNet.Numerics 和 Parse 中的 System.Threading.Tasks 冲突
Xcode 6 中的 Parse 和 Facebook SDK 导入冲突(无法识别“ParseFacebookUtils”)