This is a mammoth pull request, and I know that's a pain for maintainers. So I've tried to make this as easily digestible as possible. I've elaborated on the motivation for the changes below, and although I didn't write it that way, I've gone back and split this into smaller feature commits so they can each be evaluated some-what individually.
- c967bff484f3313420429e0e3c7ab76c3669aa5b - Migrate to FCM and refactor
This is the largest commit of the lot, but mostly does what it says. The motivation for upgrading from GCM (deprecated) to FCM is pretty obvious but some of the refactoring probably needs further explanation/justification.
In particular I've completely done away with the concept of
PushNotification and split its functionality into two classes,
RemoteNotification, which are slightly more limited in scope.
This is a breaking change to the Android Java API.
PushNotificationProps has been changed to
NotificationProps to highlight its dual role and had its behaviour adjusted to more accurately represent Google/Firebase's concept of a notification. In particular, Firebase
RemoteMessage class does not bundle end-user data arguments in with UI notification properties. Notification properties and "data" are distinct concepts.
NotificationProps contains a
getData() method to return the data only, the notification properties can be accessed by their corresponding accessor methods. This flows over into JS where there is a property called
data, which should take a JS object and all user/custom data should be part of that object, not as part of the top-level notification. This is also a breaking change.
These breaking changes weren't made arbitrarily or even to keep the project neat. They're actually required to facilitate correct function. In particular we need to be able to reliably determine whether a notification is "data only" so that JS consumers know under which context a notification is being delivered to them. I believe this is something that was perhaps missed by the original author of this functionality, but there are very distinct rules under which notifications are delivered to running applications. I've actually explained these rules in a README update (later commit) but the official Firebase reference explains in detail.
The final breaking change is that
RemoteNotification does not automatically post a local notification when a push/remote notification is received (in the foreground). This is important as it gives JS consumers control over when they'd like to display notifications and also what information they include in said notifications. Firebase does not support several options (large icons, LED lighting) etc.
Android now supports
- ae36e8a3b89ebddbf31743870beeab03230f420b - Namespace globally broadcast JS events
Fairly self explanatory, this is necessitated by the fact Android's JS events are broadcast "globally", so it's best to avoid any accidental interference by name-spacing.
- 521f0c7e3bd9d4003f9361b63267987764fd1e55 - Support FCM token invalidation
A simple mechanism to invalidate push tokens. This can be used for example when a user logs out to ensure the app stops receiving notifications.
- 98424119cfb51eacaf8ee1503dab9fbed3eb2ee2 - Fixed initial intent behavior for background notifications
I've covered this pretty thoroughly in the README and it relates to the "data-only" changes mentioned above (first commit) - or in this case, when the notification isn't data-only. If the system tray receives our push notification because the app was backgrounded, at the moment there's no way to tell when the user launched the app by tapping that notification - this commit corrects that situation.
- faf442e27c5e27989e51fdd90a8fa510fc6db4d0 - Do not automatically dismiss all notifications
This is about giving control to JS consumers. At present any time the app is launched all notifications are dismissed. That's likely to be undesirable for many use cases, particularly when a user has received multiple push notifications pertaining to different components of the app. The support that was added (first commit) for
cancelAllLocalNotifications() means users can still achieve this effect if it's desirable. This is a breaking change with respect to default expected behaviour.
- 812ced326fd8cece8850dee02ed879e0558297c8 - Android large icon support (URL or drawable name)
This is actually pretty dang nifty. It's now trivial to specify
largeIcon appears in the notification (typically used in messaging apps as profile pictures). Fresco (React Native's image manager) is used to download the images if they're specified as remote URLs - it takes care of caching and what-not.
file:// URLs are supported, which is what React Native converts
require("./some_image.jpg") syntax to in JS. So React Native bundled images can seamlessly be used in addition to remote images.
- de8c172949c76531dbb2c04f96fdfde6c2bc48ea - Minor code simplification/clean-up
Just a nit. Nothing particularly important or pressing.
- f084ebd5b3cfcb55b8422d5ab7aaec01a14d24b4 - Move getInitialNotification() NotificationsAndroid (match iOS)
Got rid of
PendingNotifications, as it was an unnecessary namespace. This is a breaking change.
- 59c6237552ac4bd130d83fb9120d8576b3f86ccb - Android lights/LED support
Added support for controlling the LED notification light i.e. What Facebook and similar apps do.
Firebase (system tray) remote notifications are actually incapable of achieving this, so it's one of many very good reasons to send "data-only" notifications and generate local notifications from the content.
Expose invalidateToken() implemented in 521f0c7e3bd9d4003f9361b63267987764fd1e55 to JS.
- 3c1f7a72c43e47621f6dadd4e34c6f02ee2f4e72 - Fixed native Android test compilation
Ensure the Android native tests compile correctly with the latest changes.
- 835cd866461d72ff4663410ad927100c96faac33 - Refactored ProxyService into LocalNotificationService
General clean-up and removal of dead/unnecessary code.
- ff3ae152b3f57be9fb2ba2f29572214ad642974b - Android background queue
Fixed (or rather added) proper background notification support. Android needs a background queue, for precisely the same reasons iOS needs one. Therefore, I've added
Events won't be delivered at all unless this is called, which is a breaking change, but the same behaviour as iOS. I've updated the documentation accordingly. In doing so I've also addressed some misleading advice / sample code. In particular the (iOS) documentation showed adding and removing event listeners inside components. This is incorrect, "cold start" background notifications will not immediately be received by your listener if they're added inside a component, as the component hierarchy does not exist at all until your app is foregrounded.
- a207aa4235f6e6ed85463e81d06b889dda7ad50d - RN 0.47 support (handle Android breaking change)
Probably easiest way to explain this is just to refer to the discussion/PR for the same change merged into
react-native-maps - https://github.com/airbnb/react-native-maps/pull/1481.
- 9edcddf66e838f3d0ade945deba54e81937fde22 - Updated README installation instructions for Android.
Prior to this commit, there were issues with multiple versions of Firebase being included due to a bug in the Google Services plugin. This commit provides updated installation instructions that work-around the bug in the Google Services plugin.
If you made it all the way through that then your time was hugely appreciated. You deserve a gold star! ⭐️
I'm certainly open to feedback and happy to correct code style issues and what-not.