GCM和Parse通知冲突

mar*_*ino 5 android push-notification parse-platform

我需要我的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>
Run Code Online (Sandbox Code Playgroud)

这是用于GCM的broadcastReceiver,下面是另一个用于解析的接收器:

<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>
Run Code Online (Sandbox Code Playgroud)

我试图添加一个自定义广播接收器来处理解析通知,所以我可以避免它来处理GCM.我这样做了:

<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
        <intent-filter>
            <action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
        </intent-filter>
    </receiver>
Run Code Online (Sandbox Code Playgroud)

这是我的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的PARSE自定义BroadcastReceiver的实现,它应该避免显示GCM.从不调用解析自定义接收器,我认为因为com.parse.GcmBroadcastReceiver处理通知本身而不是传递它们.结果是,当我从我的服务器向GCM接收器发送通知时,将从两者中检索此通知,并显示双重通知.(双重已经很好,每次我卸载并重新安装我的应用程序Parse注册另一个用户..我每次发送解析的"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... 
Run Code Online (Sandbox Code Playgroud)

任何帮助都会非常受欢迎.感谢你们!

编辑 - 添加工作清单

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

编辑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
    );
Run Code Online (Sandbox Code Playgroud)

我在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);
}
Run Code Online (Sandbox Code Playgroud)

San*_*nke 4

我们这里有两个广播接收器来监听 c2dm 意图

  1. .GcmBroadcastReceiver :让我们将其称为 GCM 接收器...解析推送永远不会到达此接收器。
  2. 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());
    }
Run Code Online (Sandbox Code Playgroud)

当有 GCM 推送时,此自定义接收器将永远不会收到广播事件,因为 C2DM 广播在 GCM 接收器(“.GcmBroadcastReceiver”)中中止

希望这可以帮助!