I need my android app to work with two push services, GCM and parse. My problem is that I can't find a way for register correctly to Parse, get parse notification and GCM notification too. I can reach all these things individually, but never together. My current implementation looks this way:
<!-- 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>
This is the broadcastReceiver for GCM, and the one below is the other receiver for parse:
<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>
I've tried to add a custom broadcast receiver to handle just parse notification, so I can avoid it to handle GCM too. I've done it like this:
<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
This is the implementation of my BroadcastReceiver for GCM, that avoid parse notification to be displayed.
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);
}
}
And this is the implementation for my PARSE custom BroadcastReceiver that SHOULD avoid GCM to be showed. The parse custom receiver is never invoked, I think because the com.parse.GcmBroadcastReceiver handle the notification itself instead of pass them. The result is that, when I send a notification from my server to GCM receiver, this is retrieved from both, and double notification is showed. (double is already good, every time I uninstall and reinstall my app Parse register another user.. the "UniqueId" I send to parse every time is not so UNIQUE for them).
What have I tried? I'm really getting crazy, I've tried about everything.
- 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...
Any help will be really welcome. Thank you guys!
EDIT - ADD WORKING MANIFEST
<!-- 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>
EDIT 2: HOW I REGISTER PARSE AND GCM
I register Parse in my application class:
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
);
And I get gcm registration_id in my MainActivity:
// 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);
}