Skip to content

Upgrade Parse Push to GCM v4 #452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ sudo: false

android:
components:
- build-tools-23.0.1
- platform-tools
- tools
- build-tools-23.0.3
- android-22
- doc-23
- extra-android-support
- extra-android-m2repository
- extra-google-m2repository
- extra-google-google_play_services
- addon-google_apis-google-28

before_install:
- pip install --user codecov
Expand Down
1 change: 1 addition & 0 deletions Parse/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ android {

dependencies {
compile 'com.parse.bolts:bolts-tasks:1.4.0'
compile 'com.google.android.gms:play-services-gcm:8.4.0'

provided 'com.squareup.okhttp:okhttp:2.4.0'
provided 'com.facebook.stetho:stetho:1.1.1'
Expand Down
67 changes: 60 additions & 7 deletions Parse/src/main/java/com/parse/GCMService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
import org.json.JSONObject;

import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

Expand All @@ -33,6 +36,15 @@
"com.google.android.c2dm.intent.REGISTRATION";
public static final String RECEIVE_PUSH_ACTION =
"com.google.android.c2dm.intent.RECEIVE";
public static final String INSTANCE_ID_ACTION =
"com.google.android.gms.iid.InstanceID";

private static final String REGISTRATION_ID_EXTRA = "registration_id";
private static final String GCM_BODY_EXTRA = "gcm.notification.body";
private static final String GCM_TITLE_EXTRA = "gcm.notification.title";
private static final String GCM_SOUND_EXTRA = "gcm.notification.sound";
private static final String GCM_COMPOSE_ID_EXTRA = "google.c.a.c_id";
private static final String GCM_COMPOSE_TIMESTAMP_EXTRA = "google.c.a.ts";

private final WeakReference<Service> parent;
private ExecutorService executor;
Expand Down Expand Up @@ -83,6 +95,8 @@ private void onHandleIntent(Intent intent) {
handleGcmRegistrationIntent(intent);
} else if (RECEIVE_PUSH_ACTION.equals(action)) {
handleGcmPushIntent(intent);
} else if (INSTANCE_ID_ACTION.equals(action)) {
handleInvalidatedInstanceId(intent);
} else {
PLog.e(TAG, "PushService got unknown intent in GCM mode: " + intent);
}
Expand All @@ -94,7 +108,13 @@ private void handleGcmRegistrationIntent(Intent intent) {
// Have to block here since GCMService is basically an IntentService, and the service is
// may exit before async handling of the registration is complete if we don't wait for it to
// complete.
GcmRegistrar.getInstance().handleRegistrationIntentAsync(intent).waitForCompletion();
PLog.d(TAG, "Got registration intent in service");
String registrationId = intent.getStringExtra(REGISTRATION_ID_EXTRA);
// Multiple IDs come back to the legacy intnet-based API with an |ID|num: prefix; cut it off.
if (registrationId.startsWith("|ID|")) {
registrationId = registrationId.substring(registrationId.indexOf(':') + 1);
}
GcmRegistrar.getInstance().setGCMRegistrationId(registrationId).waitForCompletion();
} catch (InterruptedException e) {
// do nothing
}
Expand All @@ -116,19 +136,52 @@ private void handleGcmPushIntent(Intent intent) {
String channel = intent.getStringExtra("channel");

JSONObject data = null;
if (dataString != null) {
try {
data = new JSONObject(dataString);
} catch (JSONException e) {
PLog.e(TAG, "Ignoring push because of JSON exception while processing: " + dataString, e);
return;
try {
if (dataString != null) {
data = new JSONObject(dataString);
} else if (pushId == null && timestamp == null && dataString == null && channel == null) {
// The Parse SDK is older than GCM, so it has some non-standard payload fields.
// This allows the Parse SDK to handle push providers using the now-standard GCM payloads.
pushId = intent.getStringExtra(GCM_COMPOSE_ID_EXTRA);
String millisString = intent.getStringExtra(GCM_COMPOSE_TIMESTAMP_EXTRA);
if (millisString != null) {
Long millis = Long.valueOf(millisString);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
timestamp = df.format(new Date(millis));
}
data = new JSONObject();
if (intent.hasExtra(GCM_BODY_EXTRA)) {
data.put("alert", intent.getStringExtra(GCM_BODY_EXTRA));
}
if (intent.hasExtra(GCM_TITLE_EXTRA)) {
data.put("title", intent.getStringExtra(GCM_TITLE_EXTRA));
}
if (intent.hasExtra(GCM_SOUND_EXTRA)) {
data.put("sound", intent.getStringExtra(GCM_SOUND_EXTRA));
}

String from = intent.getStringExtra("from");
if (from != null && from.startsWith("/topics/")) {
channel = from.substring("/topics/".length());
}
}
} catch (JSONException e) {
PLog.e(TAG, "Ignoring push because of JSON exception while processing: " + dataString, e);
return;
}

PushRouter.getInstance().handlePush(pushId, timestamp, channel, data);
}
}

private void handleInvalidatedInstanceId(Intent intent) {
try {
GcmRegistrar.getInstance().sendRegistrationRequestAsync().waitForCompletion();
} catch (InterruptedException e) {
// do nothing
}
}

/**
* Stop the parent Service, if we're still running.
*/
Expand Down
Loading