Skip to content
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

Trying to recall why we didn't want a GCM static dependency #445

Closed
inlined opened this issue Apr 30, 2016 · 3 comments
Closed

Trying to recall why we didn't want a GCM static dependency #445

inlined opened this issue Apr 30, 2016 · 3 comments

Comments

@inlined
Copy link

inlined commented Apr 30, 2016

I started working on ParseServer #1369 and was trying to implement this the same way as we did v3--without any compile-time dependencies on the GMS library.

Between GCM v3 and v4, things have become much more sophisticated. Now there's the InstanceId API, which is basically OAuth for the device instead of the user. If you want to send a GCM message to that device, you get the device to issue a "GCM" scope token. If I write this all from scratch, I'm going to have to write compatibility shims for Messenger on older platforms, manage crypto keys, sign values, etc. There's a very non-zero chance I'll get some of this wrong, so I wanted to revisit our decision to not depend on the GMS libraries.

The two reasons I can recall are portability or file size, but neither of those are really valid. The GMS client libraries are themselves weakly bound to underly GMS service. It's actually totally possible for Fire Phones to implement some of the same services (though the client Android Manifest would have to explicitly trust the package name). The file size issue doesn't seem to be a big deal anymore either since we could require just com.google.android.gms:play-services-gcm:8.4.0

Side Note: With the GCM v4 upgrade, we might also want to consider using the device's Instance ID as the ParseInstallation.installationId for better record stability (since installations are already upserted by that field). I don't recall if there's still regexes anywhere that expect that to be a UUID though.

inlined added a commit to FirebasePrivate/Parse-SDK-Android that referenced this issue May 3, 2016
This change:

* Moves Parse back to using public APIs [GitHub discussion](parse-community#445)
* Cleans up a lot of code in GcmRegistrar that is redundant with GCM APIs or written before Bolts
* Fixes a typo in manifest instructions that used a literal bool instead of "bool"
* Fixes a bug where ParseInstallation did not save the GcmSenderId and Parse didn't use the developer's secrets.
* Fixes a bug where Parse incorrectly blames an improperly configured manifest when GCM isn't available because Play Services aren't available.
* Add a compatibility shim when reading payloads so customers whose push provider uses the (now) standard intent structure expected by [GcmReceiver](https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmReceiver) can use the ParsePushBroadcastReceiver instead.
* Add support for GCMv4, including a new optional intent to be notified InstanceIDs are invalidated client-side.

 The new protocol has a number of benefits:

* The new GCM v4 model is more stable; it is based on a device-owned InstanceID. Push tokens are OAuth tokens to that device.
* As a result of the above, this should fix a Parse Push bug where the first GCM push after an app upgrade might be doubled.
* This API has a callback in case the InstnaceID is invalidated, which should reduce client/server inconsistencies.
* These tokens support new server-side APIs like push-to-topic, which are _dramatically_ faster than the normal ParsePush path.
* When a device upgrades to GCMv4, the device keeps GCM topics in sync with channels. This paves the way to implement push-to-channels on top of topics (or a customer to try another push provider by next Jan and retain some targeting info).

This has two possibly controversial requirements:

* The new API issues one token per sender ID rather than one token that works with all sender IDs. To avoid an invasive/breaking server-side change, we are _no longer registering for the Parse sender ID_ if the developer provided their own. We will also only support at most one custom sender ID. I've had a number of conversations about this and nobody seems concerned.
* This change introduces a dependency on the Google Mobile Services SDK. The dependency is just the GCM .jar and does _not_ limit the Parse SDK to devices with Play Services (tested on an ICS emulator w/o Google APIs). I originally tried doing this without the dependency, but the new API has a large amount of crypto and incredible care for compat shims on older API levels. I assume my hand-crafted copy would be worse quality.
inlined referenced this issue in FirebasePrivate/Parse-SDK-Android May 4, 2016
This change:
----------

* Moves Parse back to using public APIs (open [GitHub
* discussion](ParsePlatform#445))
* Cleans up a lot of code in `GcmRegistrar` that is redundant with GCM
* APIs or written before Bolts
* Fixes a typo in manifest instructions that used a literal `bool`
* instead of `"bool"`
* Fixes a bug where ParseInstallation did not save the GcmSenderId,
* causing Parse to not use the developer's secrets.
* Fixes a bug where Parse incorrectly blames a manifest error when GCM
* is unavailable because the device doesn't have Play Services.
* Add a compatibility shim that lets `ParsePushBroadcastReceiver`
* correctly handle the standard payloads expected by
* [com.android.gms.gcm.GcmReceiver](https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmReceiver).
* This lets customers who previously used another push provider use the
* `ParsePushBroadcastReceiver` instead.
* Add support for GCMv4, including a new optional intent to notify the
* app when the InstanceID is invalidated.

GCM v4 has a number of benefits:
---------------

* GCM v4 is based on a device-owned InstanceID. Push tokens are oauth
* tokens signed by the device, so this fixes double-send bugs that Parse
* Push has never been able to fix.
* If we used the InstanceID as the ParseInstallation.InstallationId, we
* would also increase stability of the Installation record, which fixes
* some cases where Installations are wiped & replaced (related to the
* above bug for senderId stability).
* This API has a callback in case the InstanceID is invalidated, which
* should reduce client/server inconsistencies.
* These tokens support new server-side APIs like push-to-topic, which
* are _dramatically_ faster than the normal ParsePush path.
* When a device upgrades to GCMv4, the device keeps GCM topics in sync
* with channels. This paves the way to implement push-to-channels on top
* of topics. It also allows the customer to keep some of their targeting
* info regardless of which push provider they choose to use.

This has two possibly controversial requirements:
----------------

* The new API issues one token per sender ID rather than one token that
* works with all sender IDs. To avoid an invasive/breaking server-side
* change, we are _no longer requesting tokens for the Parse sender ID_
* if the developer provided their own. We will also only support at most
* one custom sender ID. I've had a number of conversations about this
* and nobody seems concerned.
* This change introduces a dependency on the Google Mobile Services SDK.
* The dependency is just the GCM .jar and does _not_ limit the Parse SDK
* to devices with Play Services (tested on an ICS emulator w/o Google
* APIs). I originally tried doing this without the dependency, but the
* new API has a large amount of crypto and incredible care for compat
* shims on older API levels. I assume my hand-crafted copy would be
* worse quality.

Open questions
-----------------
* Should Parse use the GMS InstanceID over the InstallationId when
* available? This makes the server-side Installation deduplication code
* work better, but could break systems that assume InstallationId is a
* UUID.
* Google workflows provide a `google-services.json` file that GMS uses
* to auto-initialize various Google products (including GCM). Should we
* allow the Parse SDK to initialize the developer's sender ID with this
* file in addition to the Parse-specific way?
inlined referenced this issue in FirebasePrivate/Parse-SDK-Android May 5, 2016
This change:
----------

* Moves Parse back to using public APIs (open [GitHub
* discussion](ParsePlatform#445))
* Cleans up a lot of code in `GcmRegistrar` that is redundant with GCM
* APIs or written before Bolts
* Fixes a typo in manifest instructions that used a literal `bool`
* instead of `"bool"`
* Fixes a bug where ParseInstallation did not save the GcmSenderId,
* causing Parse to not use the developer's secrets.
* Fixes a bug where Parse incorrectly blames a manifest error when GCM
* is unavailable because the device doesn't have Play Services.
* Add a compatibility shim that lets `ParsePushBroadcastReceiver`
* correctly handle the standard payloads expected by
* [com.android.gms.gcm.GcmReceiver](https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmReceiver).
* This lets customers who previously used another push provider use the
* `ParsePushBroadcastReceiver` instead.
* Add support for GCMv4, including a new optional intent to notify the
* app when the InstanceID is invalidated.

GCM v4 has a number of benefits:
---------------

* GCM v4 is based on a device-owned InstanceID. Push tokens are oauth
* tokens signed by the device, so this fixes double-send bugs that Parse
* Push has never been able to fix.
* If we used the InstanceID as the ParseInstallation.InstallationId, we
* would also increase stability of the Installation record, which fixes
* some cases where Installations are wiped & replaced (related to the
* above bug for senderId stability).
* This API has a callback in case the InstanceID is invalidated, which
* should reduce client/server inconsistencies.
* These tokens support new server-side APIs like push-to-topic, which
* are _dramatically_ faster than the normal ParsePush path.
* When a device upgrades to GCMv4, the device keeps GCM topics in sync
* with channels. This paves the way to implement push-to-channels on top
* of topics. It also allows the customer to keep some of their targeting
* info regardless of which push provider they choose to use.

This has two possibly controversial requirements:
----------------

* The new API issues one token per sender ID rather than one token that
* works with all sender IDs. To avoid an invasive/breaking server-side
* change, we are _no longer requesting tokens for the Parse sender ID_
* if the developer provided their own. We will also only support at most
* one custom sender ID. I've had a number of conversations about this
* and nobody seems concerned.
* This change introduces a dependency on the Google Mobile Services SDK.
* The dependency is just the GCM .jar and does _not_ limit the Parse SDK
* to devices with Play Services (tested on an ICS emulator w/o Google
* APIs). I originally tried doing this without the dependency, but the
* new API has a large amount of crypto and incredible care for compat
* shims on older API levels. I assume my hand-crafted copy would be
* worse quality.

Open questions
-----------------
* Should Parse use the GMS InstanceID over the InstallationId when
* available? This makes the server-side Installation deduplication code
* work better, but could break systems that assume InstallationId is a
* UUID.
* Google workflows provide a `google-services.json` file that GMS uses
* to auto-initialize various Google products (including GCM). Should we
* allow the Parse SDK to initialize the developer's sender ID with this
* file in addition to the Parse-specific way?
inlined referenced this issue in FirebasePrivate/Parse-SDK-Android May 9, 2016
This change:
----------

* Moves Parse back to using public APIs (open [GitHub discussion](ParsePlatform#445))
* Cleans up a lot of code in `GcmRegistrar` that is redundant with GCM APIs or written before Bolts
* Fixes a typo in manifest instructions that used a literal `bool` instead of `"bool"`
* Fixes a bug where ParseInstallation did not save the GcmSenderId, causing Parse to not use the developer's secrets.
* Fixes a bug where Parse incorrectly blames a manifest error when GCM is unavailable because the device doesn't have Play Services.
* Add a compatibility shim that lets `ParsePushBroadcastReceiver` correctly handle the standard payloads expected by [com.android.gms.gcm.GcmReceiver](https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmReceiver). This lets customers who previously used another push provider use the `ParsePushBroadcastReceiver` instead.
* Add support for GCMv4, including a new optional intent to notify the app when the InstanceID is invalidated.

GCM v4 has a number of benefits:
---------------

* GCM v4 is based on a device-owned InstanceID. Push tokens are oauth tokens signed by the device, so this fixes double-send bugs that Parse Push has never been able to fix.
* If we used the InstanceID as the ParseInstallation.InstallationId, we would also increase stability of the Installation record, which fixes some cases where Installations are wiped & replaced (related to the above bug for senderId stability).
* This API has a callback in case the InstanceID is invalidated, which should reduce client/server inconsistencies.
* These tokens support new server-side APIs like push-to-topic, which are _dramatically_ faster than the normal ParsePush path.
* When a device upgrades to GCMv4, the device keeps GCM topics in sync with channels. This paves the way to implement push-to-channels on top of topics. It also allows the customer to keep some of their targeting info regardless of which push provider they choose to use.

This has two possibly controversial requirements:
----------------

* The new API issues one token per sender ID rather than one token that works with all sender IDs. To avoid an invasive/breaking server-side change, we are _no longer requesting tokens for the Parse sender ID_ if the developer provided their own. We will also only support at most one custom sender ID. I've had a number of conversations about this and nobody seems concerned.
* This change introduces a dependency on the Google Mobile Services SDK. The dependency is just the GCM .jar and does _not_ limit the Parse SDK to devices with Play Services (tested on an ICS emulator w/o Google APIs). I originally tried doing this without the dependency, but the new API has a large amount of crypto and incredible care for compat shims on older API levels. I assume my hand-crafted copy would be worse quality.

Open questions
-----------------
* Should Parse use the GMS InstanceID over the InstallationId when available? This makes the server-side Installation deduplication code work better, but could break systems that assume InstallationId is a UUID.
* Google workflows provide a `google-services.json` file that GMS uses to auto-initialize various Google products (including GCM). Should we allow the Parse SDK to initialize the developer's sender ID with this file in addition to the Parse-specific way?
@grantland
Copy link
Contributor

IIRC the main reason was not wanting to break backwards compatibility. Developers who aren't using Maven will have to manually add another dependency or else they'll hit compile/runtime failures.

Aside from that, we didn't want to force developers to add unnecessary dependencies if they aren't utilizing GCM. This is especially annoying if this puts a developer over the dex limit and they have to deal with implementing multi-dex or having to wait for proguard stripping on every build.

We had discussed this many times and our ideal implementation was a fully decoupled shim library, similar to how we open sourced ParseFacebookUtils and ParseTwitterUtils. This would allow us to utilize the GCM library as well as solve the problems outlined above, however it was never much of a priority since it wasn't broken.

I had many conversations about fully decoupling our SDKs with @nlutsenko, @wangmengyan95, @richardjrossiii and @bnham, and maybe they can fill in any gaps that I forgot, but here is what I remember:

  • Creating GCMUtils or something that would be shim between Parse-SDK-Android and play-services-gcm.
  • Implementing a third ProxyService and leaving GCMService untouched so that we can maintain backwards compatibility for developers who don't want to go the extra mile to add the GCM dependency.
  • Publicizing necessary ParseInstallation properties so that any push shim, including GCMUtils, can access and modify.
  • Decouple push registration from Parse#initialize() into GCMUtils.

@bnham
Copy link

bnham commented May 18, 2016

It was because we added GCM before Android Studio and Gradle usage was widespread. Our SDK was just a jar file with no dependencies (this was before Bolts was split out) and we didn't want to add a dependency or force people to declare dependencies using Gradle or another build system.

@Jawnnypoo
Copy link
Member

With the pulling out of the GCM module, it now uses the dependency

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants