diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..105898580
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: [Dallas62]
+custom: ["https://www.buymeacoffee.com/Dallas62"]
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 000000000..df62fddde
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,56 @@
+---
+name: '🐛 Bug Report'
+about: Report a reproducible bug or regression in this library.
+---
+
+# Bug
+
+
+
+## Environment info
+
+
+
+`react-native info` output:
+
+```bash
+ // paste it here
+```
+
+Library version: x.x.x
+
+## Steps To Reproduce
+
+
+
+1.
+2.
+...
+
+Describe what you expected to happen:
+
+1.
+2.
+
+## Reproducible sample code
+
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 000000000..18e53748a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,28 @@
+---
+name: '💡 Feature Request'
+about: Submit your idea for a change in the codebase.
+---
+
+# Feature Request
+
+
+
+## Why it is needed
+
+
+
+## Possible implementation
+
+
+
+### Code sample
+
+
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
new file mode 100644
index 000000000..4a6267364
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -0,0 +1,13 @@
+---
+name: '🤔 Questions and Help'
+about: Use this if there is something not clear about the code or its docs.
+---
+
+# Question
+
+
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 000000000..42d412484
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,17 @@
+name: "Close stale issues"
+on:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@v4
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 30 days if no further activity occurs. Thank you for your contributions."
+ stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 30 days if no further activity occurs. Thank you for your contributions."
+ days-before-stale: 365
+ days-before-close: 30
+ operations-per-run: 10
diff --git a/.gitignore b/.gitignore
index d06fcbb96..0a2cc57b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,9 +34,17 @@ local.properties
node_modules/*
npm-debug.log
+yarn.lock
+package-lock.json
+
android/android.iml
android/gradle.properties
android/gradle/
android/gradlew
android/gradlew.bat
android/src/main/gen
+
+#Debug only
+google-services.json
+
+.vscode/
diff --git a/.npmignore b/.npmignore
index 8c497b0dd..84ba28601 100644
--- a/.npmignore
+++ b/.npmignore
@@ -62,4 +62,13 @@ local.properties
example
# Git
-.git
\ No newline at end of file
+.git
+
+# GitHub
+.github/*
+
+# Docs
+submitting-a-pull-request.md
+
+# Vscode
+.vscode/*
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bffe3a492..056851bd4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,407 @@
All notable changes to this project will be documented in this file.
-The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
-## [Unreleased]
+## Unreleased
+
+### Breaking changes
+
+### Features
+
+### Fixed
+
+## [8.1.1] 2021-10-01
+
+### Fixed
+
+- (iOS): Raise @react-native-community/push-notification-ios version [#2151](https://github.com/zo0r/react-native-push-notification/pull/2151)
+- (iOS): Fix iOS repeated notification timing [#2150](https://github.com/zo0r/react-native-push-notification/pull/2150)
+
+## [8.1.0] 2021-09-03
+
+### Features
+
+- (iOS) Upgrade `@react-native-community/push-notification-ios` to version [1.10.0](https://github.com/react-native-push-notification/ios/releases/tag/v1.10.0)
+- (iOS) Allow `month`, `week`, `day`, `hour`, `minute` as `repeatType` for iOS.
+- (Android) Allow HTML tags to be used for styling in bigText field only [#2067](https://github.com/zo0r/react-native-push-notification/pull/2067).
+
+### Fixed
+
+- (Android): Fix Android 12 PendingIntent [#2130](https://github.com/zo0r/react-native-push-notification/pull/2130)
+
+## [8.0.1] 2021-08-24
+
+### Fixed
+
+- (Android): Fix bug cancelLocalNotification() does not work on Android [#2122](https://github.com/zo0r/react-native-push-notification/issues/2122)
+
+## [8.0.0] 2021-08-19
+
+### Breaking changes
+
+- `userInfo` is no more populated with the `id` of the notification, initialy included to cancel scheduled notifications. This change will probably not impact you.
+- Rename `cancelLocalNotifications` to `cancelLocalNotification` (deprecation notice).
+
+### Features
+
+- (iOS) upgrade `@react-native-community/push-notification-ios` to version [1.9.0](https://github.com/react-native-push-notification/ios/releases/tag/v1.9.0)
+- `picture` is now support for both Android and iOS, (alias of `bigPictureUrl` for Android).
+
+### Fixed
+
+- (Android): Fix bug cancelLocalNotifications() does not work on Android [#2100](https://github.com/zo0r/react-native-push-notification/issues/2100)
+
+## [7.4.0] 2021-06-24
+
+### Features
+
+ - (Android): Allow for repeat to specify amount of the given repeat type. [#2030](https://github.com/zo0r/react-native-push-notification/pull/2030)
+ - (iOS): Add support for subtitle notification property. [#2063](https://github.com/zo0r/react-native-push-notification/pull/2063)
+
+## [7.3.2] 2021-06-19
+
+### Fixed
+
+- (Android) Fix: Foreground notifications missing small icon. [#1927](https://github.com/zo0r/react-native-push-notification/pull/1927)
+
+## [7.3.1] 2021-05-12
+
+### Fixed
+
+- (Android) Pin the firebase-messaging dependency to `21.1.0`.
+- (Android) Fix: android missing channelId warning should now show [#1995](https://github.com/zo0r/react-native-push-notification/pull/1995).
+
+## [7.3.0] 2021-05-12
+
+### Features
+- (Android) Add constants for notification importance [#1959](https://github.com/zo0r/react-native-push-notification/pull/1959)
+
+### Fixed
+
+- (Android) Fix: Task :react-native-push-notification:compileDebugJavaWithJavac FAILED [#1979](https://github.com/zo0r/react-native-push-notification/issues/1979)
+
+## [7.2.3] 2021-03-18
+
+### Fixed
+
+- (Android) Fix: Notification drawer doesn't close after click on action that navigates you to app [#1914](https://github.com/zo0r/react-native-push-notification/issues/1914)
+- (iOS) Fix: foreground notification property [#1916](https://github.com/zo0r/react-native-push-notification/pull/1916)
+
+## [7.2.2] 2021-03-04
+
+### Fixed
+
+- (Android) Fix: Could not invoke RNPushNotification.getDeliveredNotifications. [#1878](https://github.com/zo0r/react-native-push-notification/issues/1878)
+- (fix) deep clone details and notifications. [#1793](https://github.com/zo0r/react-native-push-notification/issues/1793)
+
+## [7.2.1] 2021-02-11
+
+### Fixed
+
+- (iOS) Fix `playSound` options on local notifications. [#1858](https://github.com/zo0r/react-native-push-notification/issues/1858#issuecomment-775714298)
+
+## [7.2.0] 2021-01-24
+
+### Features
+
+- (Android) Handle localization for notification title and body [#1837](https://github.com/zo0r/react-native-push-notification/pull/1837)
+
+## [7.1.1] 2021-01-20
+
+### Fixed
+
+- (Android) unsubscribeFromTopic function fix [#1831](https://github.com/zo0r/react-native-push-notification/pull/1831)
+
+## [7.1.0] 2021-01-16
+
+### Features
+
+- (Android) Add hooks to intent handling and bundle parsing [#1819](https://github.com/zo0r/react-native-push-notification/pull/1819)
+
+## [7.0.0] 2020-12-23
+
+### Breaking changes
+
+- (iOS) Replace deprecated local notification methods on iOS [#1751](https://github.com/zo0r/react-native-push-notification/pull/1751)
+- (Android) Rename the Android package from `RNPushNotification` to `ReactNativePushNotification` resolve [#893](https://github.com/zo0r/react-native-push-notification/issues/893)
+- (Android) Allow `userInfo` to be stored in scheduled notification as in iOS (mapped as `data` on press or list scheduled notifications).
+
+### Features
+
+- (Android) silent channel using playSound flag
+- (Android) implement 'bigLargeIcon' for Android notifications (must be combined with BigPicture) [#1730](https://github.com/zo0r/react-native-push-notification/pull/1730)
+- (Android) notification with inline reply [#612](https://github.com/zo0r/react-native-push-notification/pull/612)
+- (Android) Support using drawable as Android small icon [#1787](https://github.com/zo0r/react-native-push-notification/pull/1787)
+
+## [6.1.3] 2020-11-09
+
+### Fixed
+
+- (Android) Null pointer exception when trying to create channel [#1734](https://github.com/zo0r/react-native-push-notification/issues/1734)
+
+## [6.1.2] 2020-10-29
+
+### Fixed
+
+- (Android) Fix for vibration on notifs for Android API >= 26 [#1686](https://github.com/zo0r/react-native-push-notification/pull/1686)
+
+## [6.1.1] 2020-09-29
+
+### Fixed
+
+- (Android) Fix a crash when the application is in background [#1676](https://github.com/zo0r/react-native-push-notification/issues/1676)
+
+## [6.1.0] 2020-09-28
+
+### Features
+
+- (Android) Allow a default channel in the `AndroidManifest`:
+ ```xml
+
+ ```
+ If not defined, fallback to the Firebase value of:
+ ```xml
+
+ ```
+ If not defined, fallback to the default Firebase channel id `fcm_fallback_notification_channel`
+
+## [6.0.0] 2020-09-26
+
+### Breaking changes
+
+- (Android) Channel Management: In order to limit the scope of responsability of this library, developers are now responsible of the creation of the channels. You can find the documentation at https://github.com/zo0r/react-native-push-notification#channel-management-android. These changes are also made to allow improvements in the future of the library. Here the list of impacts:
+ - You must create your channels before triggering a notification.
+ - These entries in `AndroidManifest` are deprecated:
+ ```xml
+
+
+
+ ```
+ - Followings options changed on Android in `localNotification` and `localNotificationSchedule`:
+ - `channelId` becomes mandatory (warning if not provided)
+ - `channelName` is deprecated
+ - `channelDescription` is deprecated
+ - `importance` is deprecated
+ - These changes help to avoid an issue [#1649](https://github.com/zo0r/react-native-push-notification/issues/1649)
+- (Android) Remove check for the intent `BOOT_COMPLETED`, this should allow more intent action such as `QUICKBOOT_POWERON`. It's recommended to update `AndroidManifest`, the `RNPushNotificationBootEventReceiver` to:
+ ```xml
+
+
+
+
+
+
+
+ ```
+- `@react-native-community/push-notification-ios` is now a `peerDependency`, please make sure that you installed this library with NPM or YARN.
+- (Android) Fix a bug where notification data are not inside `data` property after been pressed by user. When sending notification + data and app in background.
+- (Android) Add more fields from the firebase notification part. (Thanks to @fattomhk with this PR [#1626](https://github.com/zo0r/react-native-push-notification/pull/1626))
+ - `notificationPriority`
+ - `image`
+ - `tag`
+ - `visibility`
+- (Android) `data.twi_body` is no more used to trigger a notification in notification-center. Revert of [#744](https://github.com/zo0r/react-native-push-notification/pull/744)
+
+### Fixed
+
+- (iOS) upgrade `@react-native-community/push-notification-ios`, fixe the value of `userInteraction` [@react-native-community/push-notification-ios#122](https://github.com/react-native-community/push-notification-ios/pull/122).
+
+## [5.1.1] 2020-09-15
+
+### Fixed
+
+- (Android) Fatal Exception: java.lang.NullPointerException [#1641](https://github.com/zo0r/react-native-push-notification/issues/1641)
+
+## [5.1.0] 2020-08-31
+
+### Features
+
+- (Android) Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589)
+- (Android) Add support of `when`, `usesChronometer` and `timeoutAfter`.
+
+### Fixed
+
+- (Android) Fix a bug where `userInteraction` is not set, notification when app in background pressed by user.
+
+
+## [5.0.1] 2020-08-04
+
+### Fixed
+
+- (Android) Fix change that make gradle build fail [#1578](https://github.com/zo0r/react-native-push-notification/pull/1578).
+
+## [5.0.0] 2020-08-03
+
+### Breaking changes
+
+- (Android/iOS) Unify returned values between iOS and Android [#1516](https://github.com/zo0r/react-native-push-notification/pull/1516).
+- (Android/iOS) `.popInitialNotification(callback)` now return the same format as `onNotification()`.
+- (Android) `popInitialNotification` in `configure()` now trigger only once on app startup, same as iOS.
+- (Android) `notification.foreground` now return the good value, before the value was `false` most of the time.
+
+### Features
+
+- (Android) Add function `createChannel` for custom Android channel support [#1509](https://github.com/zo0r/react-native-push-notification/pull/1509)
+- (Android) Add Android `messageId` to enable integration with `react-native-firebase/messaging` [#1510](https://github.com/zo0r/react-native-push-notification/pull/1510)
+- (Android) Add support for `onlyAlertOnce` property [#1519](https://github.com/zo0r/react-native-push-notification/pull/1519)
+- (Android) Allow to change default notification channel name after it's creation [#1549](https://github.com/zo0r/react-native-push-notification/pull/1549)
+
+### Fixed
+
+- (Android) `popInitialNotification` in `configure()` now trigger only once and do not trigger twice `onNotification()` when user press the notification, more details: [#1516](https://github.com/zo0r/react-native-push-notification/pull/1516).
+- (Android) `notification.foreground` now return the good value, before the value was `false` most of the time.
+
+## [4.0.0] 2020-07-06
+
+### Breaking changes
+
+- `RNPushNotificationRegistrationService` has been removed, old reference in AndroidManifest must be removed.
+- `Notifications.registerNotificationActions()` has been removed and is not required for `actions`.
+- `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`.
+- Extra receiver must be added to manage actions.
+ ```xml
+
+ ```
+- (iOS) `userInfo` is now populated with id by default to allow operation based on `id`.
+
+### Features
+
+- (Android) `actions` accept an array of strings.
+- (Android) `invokeApp` allow you to handle actions in background without invoking the application.
+- (Android) `onAction` has been added to `.configure()` to handle action in background.
+- (Android) `PushNotification.invokeApp(notification)` allow you to invoke the application when in background (notification for initial notification).
+- (Android) `PushNotification.getChannels(callback)` allow you to get the list of channels.
+- (Android) `PushNotification.channelExists(channel_id, callback)` allow you to check of a channel exists.
+- (Android) `PushNotification.channelBlocked(channel_id, callback)` allow you to check of a channel is blocked. Based on [#1249](https://github.com/zo0r/react-native-push-notification/pull/1249)
+- (Android) `PushNotification.deleteChannel(channel_id)` allow you to delete a channel.
+- (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444)
+- (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444)
+- (Android) Add `shortcutId` for better badges management.
+- (Android) Add `showWhen` to display "when" it was published, default: true.
+- (Android) Add `groupSummary` to allow grouping notifications. Based on [#1253](https://github.com/zo0r/react-native-push-notification/pull/1253)
+- (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159)
+- (Android) Add `channelName`, custom channel_name in android.
+- (Android) Add `channelDescription`, custom channel_description in android.
+- (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345)
+- (iOS) `onRegistrationError` has been added to `.configure()` to handle `registrationError` events.
+- (Android/iOS) Add method getScheduledLocalNotifications()[#1466](https://github.com/zo0r/react-native-push-notification/pull/1466)
+
+### Fixed
+
+- (Android) Replace java.util.Random with java.security.SecureRandom [#1497](https://github.com/zo0r/react-native-push-notification/pull/1497)
+- (Android) WAKE_LOCK permission removed from documentation. [#1494](https://github.com/zo0r/react-native-push-notification/issues/1494)
+- (Android) Some options were ignored on scheduled/repeating notifications (allowWhileIdle, ignoreInForeground).
+- (Android/iOS) popInitialInotification might be ignored in `.configure()`
+
+## [3.5.2] - 2020-05-25
+
+### Fixed
+
+- (Android) Sounds are playing even in Do Not Disturb [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432#issuecomment-633367111)
+- (Android) onNotification fires every time when the app goes from background to foreground [#1455](https://github.com/zo0r/react-native-push-notification/issues/1455)
+- (Android) java.lang.NullPointerException: Attempt to invoke virtual method 'void com.dieam.reactnativepushnotification.modules.d.c(android.os.Bundle)' on a null object reference [#1431](https://github.com/zo0r/react-native-push-notification/issues/1431#issuecomment-633315150)
+
+## [3.5.1] - 2020-05-20
+
+### Fixed
+
+- (Android) When updating 3.4 to 3.5, unable to compile Android [#1449](https://github.com/zo0r/react-native-push-notification/pull/1449)
+
+## [3.5.0] - 2020-05-20
+
+### Features
+
+- (Android) Enables the ability to support multiple push providers [#1445](https://github.com/zo0r/react-native-push-notification/pull/1445)
+
+### Fixed
+
+- (Android) No sound on notifications [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432)
+- (Android) onNotification is not calling when app is in background [#1446](https://github.com/zo0r/react-native-push-notification/pull/1446)
+- (Android) `number` and `id` do not crash if NaN is passed in Android.
+
+## [3.4.0] - 2020-05-08
+
+### Features
+
+- (Android) Call `onRegister` when [Firebase renew token]().
+- (Android) Added Abandon Permissions method to Android [#1425](https://github.com/zo0r/react-native-push-notification/pull/1425)
+- (Android) Add a new key in `AndroidManifest.xml` to allow/remove notification in foreground.
+
+```xml
+
+```
+
+### Fixed
+
+- (Android) `number` and `id` are now correctly handled as number in Android.
+- (iOS) Update push-notification-ios to 1.2.0 [#1410](https://github.com/zo0r/react-native-push-notification/pull/1410)
+- Make sure to import PushNotificationIOS from react-native first [#617](https://github.com/zo0r/react-native-push-notification/pull/617)
+
+## [3.3.1] - 2020-05-01
+
+### Fixed
+
+- (Android) Fix regression with the importance of the notification.
+
+## [3.3.0] - 2020-04-29
+
+### Features
+
+- (Android) Keep interface parity with PushNotificationIOS [#909](https://github.com/zo0r/react-native-push-notification/pull/909)
+- (Android) Unsubscribe from topic [#917](https://github.com/zo0r/react-native-push-notification/pull/917)
+- (Android) Add notification data in onNotification [#1212](https://github.com/zo0r/react-native-push-notification/pull/1212)
+
+### Fixed
+
+- (Android) Create default channel to receive notification when background / killed.
+- (Android) Fix vibrate: false is ignored [#878](https://github.com/zo0r/react-native-push-notification/issues/1140)
+- `package.json` fix suffic in main, `index` => `index.js` [#878](https://github.com/zo0r/react-native-push-notification/pull/878)
+
+### Breaking changes
+
+- (Android) Remove specific code for GCM [#1322](https://github.com/zo0r/react-native-push-notification/issues/1322)
+- `` must be removed.
+
+## [3.2.1] - 2020-04-20
+
+### Fixed
+
+- Invalid type `Strint` wrong typo
+- Missing import
+
+## [3.2.0] - 2020-04-20
+
+### Features
+
+- (Android) Allow to silence Android foreground notifications [#1183](https://github.com/zo0r/react-native-push-notification/pull/1183)
+- (Android) Allow to set the notification to executes on idle [#959](https://github.com/zo0r/react-native-push-notification/pull/959)
+- (iOS) Add missing "category" parameter when scheduling local notifications. [#457](https://github.com/zo0r/react-native-push-notification/pull/457)
+
+### Fixed
+
+- Fix: Breaking android x compatibility regression
+- Fix: Use FirebaseInstanceId for deviceToken, not from Intent [#1355](https://github.com/zo0r/react-native-push-notification/pull/1355)
+- Fix: security issue `limit the components that Intent will resolve to` [#687](https://github.com/zo0r/react-native-push-notification/pull/687)
+- Fix: remove fishy reference from android project files [#1226](https://github.com/zo0r/react-native-push-notification/pull/1226)
+- Fix: `JSON value '' of type NSNull cannot be converted to NSDictionary` [#1030](https://github.com/zo0r/react-native-push-notification/pull/1030)
+- Fix: Fixed foreground FCM banner notifications and notification sound [#1042](https://github.com/zo0r/react-native-push-notification/pull/1042)
+- Upgrade ShortCutBadger to 1.1.22 [#646](https://github.com/zo0r/react-native-push-notification/pull/646)
+- Upgrade exemple to React-Native 0.62.2
+- Remove Types from the code use [@types/react-native-push-notification](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-native-push-notification) instead.
+- Remove GCM and C2DM references in README.md
+
+### Possible Breaking change
+
+- Rename firebaseVersion to firebaseMessagingVersion [#1191](https://github.com/zo0r/react-native-push-notification/pull/1191) in gradle.build
+
+### Documentation
+
+- Abandon permissions unregisters remote only [#1282](https://github.com/zo0r/react-native-push-notification/pull/1282)
+- Use full path for manifest [#567](https://github.com/zo0r/react-native-push-notification/pull/567)
+- Update broken link to docs [#995](https://github.com/zo0r/react-native-push-notification/pull/995)
+- Missing step for android manual installation [#1363](https://github.com/zo0r/react-native-push-notification/pull/1363)
## [3.1.3] - 2019-05-25
@@ -52,3 +449,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
[unreleased]: https://github.com/zo0r/react-native-push-notification/compare/v3.1.2...HEAD
[3.1.2]: https://github.com/zo0r/react-native-push-notification/compare/v3.1.1...v3.1.2
[3.1.1]: https://github.com/zo0r/react-native-push-notification/compare/...v3.1.1
+
+
+## Supported React Native Versions
+
+| Component Version | RN Versions | README |
+| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------- |
+| **1.0.7** | **<= 0.27** | [Open](https://github.com/zo0r/react-native-push-notification/blob/f42723817f1687e0da23e6753eb8a9f0385b6ac5/README.md) |
+| **1.0.8** | **0.28** | [Open](https://github.com/zo0r/react-native-push-notification/blob/2eafd1961273ca6a82ad4dd6514fbf1d1a829089/README.md) |
+| **2.0.1** | **0.29** | [Open](https://github.com/zo0r/react-native-push-notification/blob/c7ab7cd84ea19e42047379aefaf568bb16a81936/README.md) |
+| **2.0.2** | **0.30, 0.31, 0.32** | [Open](https://github.com/zo0r/react-native-push-notification/blob/a0f7d44e904ba0b92933518e5bf6b444f1c90abb/README.md) |
+| **>= 2.1.0** | **>= 0.33** | [Open](https://github.com/zo0r/react-native-push-notification/blob/a359e5c00954aa324136eaa9808333d6ca246171/README.md) |
diff --git a/README.md b/README.md
index b83be78fb..8bc773e9f 100644
--- a/README.md
+++ b/README.md
@@ -5,15 +5,22 @@
React Native Local and Remote Notifications for iOS and Android
-## Supported React Native Versions
+## State of the repository
-| Component Version | RN Versions | README |
-| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------- |
-| **1.0.7** | **<= 0.27** | [Open](https://github.com/zo0r/react-native-push-notification/blob/f42723817f1687e0da23e6753eb8a9f0385b6ac5/README.md) |
-| **1.0.8** | **0.28** | [Open](https://github.com/zo0r/react-native-push-notification/blob/2eafd1961273ca6a82ad4dd6514fbf1d1a829089/README.md) |
-| **2.0.1** | **0.29** | [Open](https://github.com/zo0r/react-native-push-notification/blob/c7ab7cd84ea19e42047379aefaf568bb16a81936/README.md) |
-| **2.0.2** | **0.30, 0.31, 0.32** | [Open](https://github.com/zo0r/react-native-push-notification/blob/a0f7d44e904ba0b92933518e5bf6b444f1c90abb/README.md) |
-| **>= 2.1.0** | **>= 0.33** | [Open](https://github.com/zo0r/react-native-push-notification/blob/a359e5c00954aa324136eaa9808333d6ca246171/README.md) |
+This repository is not actively maintained. The main reason is time. The second one is probably the complexity of notifications on both iOS and Android.
+Since this project probably need a huge refactor to fix some issue or to implement new features. I think you should probably consider these alternatives: [Notifee](https://notifee.app) free since september or [react-native-notifications](https://github.com/wix/react-native-notifications).
+
+If you are interested in being a maintainer of this project, feel free to ask in issues.
+
+## 🎉 Version 7.x is live ! 🎉
+
+Check out for changes and migration in the CHANGELOG:
+
+[Changelog](https://github.com/zo0r/react-native-push-notification/blob/master/CHANGELOG.md)
+
+# Supporting the project
+
+Maintainers are welcome ! Feel free to contact me :wink:
## Changelog
@@ -21,9 +28,19 @@ Changelog is available from version 3.1.3 here: [Changelog](https://github.com/z
## Installation
-`npm install --save react-native-push-notification` or `yarn add react-native-push-notification`
+### NPM
+
+```
+npm install --save react-native-push-notification
+```
-`react-native link react-native-push-notification`
+### Yarn
+
+```
+yarn add react-native-push-notification
+```
+
+**NOTE: If you target iOS you also need to follow the [installation instructions for PushNotificationIOS](https://github.com/react-native-community/react-native-push-notification-ios) since this package depends on it.**
**NOTE: For Android, you will still have to manually update the AndroidManifest.xml (as below) in order to use Scheduled Notifications.**
@@ -37,20 +54,18 @@ Having a problem? Read the [troubleshooting](./trouble-shooting.md) guide before
## iOS manual Installation
-The component uses PushNotificationIOS for the iOS part.
-
-[Please see: PushNotificationIOS](https://github.com/react-native-community/react-native-push-notification-ios)
+The component uses PushNotificationIOS for the iOS part. You should follow their [installation instructions](https://github.com/react-native-community/react-native-push-notification-ios).
## Android manual Installation
-**NOTE: `play-service-gcm` and `firebase-messaging`, prior to version 15 requires to have the same version number in order to work correctly at build time and at run time. To use a specific version:**
+**NOTE: `firebase-messaging`, prior to version 15 requires to have the same version number in order to work correctly at build time and at run time. To use a specific version:**
In your `android/build.gradle`
```gradle
ext {
googlePlayServicesVersion = "" // default: "+"
- firebaseVersion = "" // default: "+"
+ firebaseMessagingVersion = "" // default: "21.1.0"
// Other settings
compileSdkVersion = // default: 23
@@ -62,61 +77,31 @@ ext {
**NOTE: localNotification() works without changes in the application part, while localNotificationSchedule() only works with these changes:**
-In your `AndroidManifest.xml`
+In your `android/app/src/main/AndroidManifest.xml`
```xml
.....
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+ android:resource="@color/white"/>
+
+
+
-
-
-
-
-
-
-
-
-
-
@@ -124,10 +109,70 @@ In your `AndroidManifest.xml`
-
.....
```
+If not using a built in Android color (`@android:color/{name}`) for the `notification_color` `meta-data` item.
+In `android/app/src/main/res/values/colors.xml` (Create the file if it doesn't exist).
+
+```xml
+
+ #FFF
+
+```
+
+If your app has an @Override on onNewIntent in `MainActivity.java` ensure that function includes a super call on onNewIntent (if your `MainActivity.java` does not have an @Override for onNewIntent skip this):
+
+```java
+ @Override
+ public void onNewIntent(Intent intent) {
+ ...
+ super.onNewIntent(intent);
+ ...
+ }
+```
+
+### If you use remote notifications
+
+Make sure you have installed setup Firebase correctly.
+
+In `android/build.gradle`
+
+```gradle
+
+buildscript {
+ ...
+ dependencies {
+ ...
+ classpath('com.google.gms:google-services:4.3.3')
+ ...
+ }
+}
+```
+
+In `android/app/build.gradle`
+
+```gradle
+dependencies {
+ ...
+ implementation 'com.google.firebase:firebase-analytics:17.3.0'
+ ...
+}
+
+apply plugin: 'com.google.gms.google-services'
+
+```
+
+Then put your `google-services.json` in `android/app/`.
+
+**Note: [firebase/release-notes](https://firebase.google.com/support/release-notes/android)**
+
+> The Firebase Android library `firebase-core` is no longer needed. This SDK included the Firebase SDK for Google Analytics.
+>
+> Now, to use Analytics or any Firebase product that recommends the use of Analytics (see table below), you need to explicitly add the Analytics dependency: `com.google.firebase:firebase-analytics:17.3.0`.
+
+### If you don't use autolink
+
In `android/settings.gradle`
```gradle
@@ -136,12 +181,14 @@ include ':react-native-push-notification'
project(':react-native-push-notification').projectDir = file('../node_modules/react-native-push-notification/android')
```
-In `android/app/src/res/values/colors.xml` (Create the file if it doesn't exist).
+In your `android/app/build.gradle`
-```xml
-
- #FFF
-
+```gradle
+ dependencies {
+ ...
+ implementation project(':react-native-push-notification')
+ ...
+ }
```
Manually register module in `MainApplication.java` (if you did not use `react-native link`):
@@ -160,10 +207,10 @@ public class MainApplication extends Application implements ReactApplication {
@Override
protected List getPackages() {
- return Arrays.asList(
- new MainReactPackage(),
- new ReactNativePushNotificationPackage() // <---- Add the Package
- );
+ return Arrays.asList(
+ new MainReactPackage(),
+ new ReactNativePushNotificationPackage() // <---- Add the Package
+ );
}
};
@@ -173,33 +220,49 @@ public class MainApplication extends Application implements ReactApplication {
## Usage
+**DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App`**
+> If you do, notification handlers will not fire, because they are not loaded. Instead, use `.configure()` in the app's first file, usually `index.js`.
+
+
```javascript
-var PushNotification = require("react-native-push-notification");
+import PushNotificationIOS from "@react-native-community/push-notification-ios";
+import PushNotification from "react-native-push-notification";
+// Must be outside of any component LifeCycle (such as `componentDidMount`).
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
- onRegister: function(token) {
+ onRegister: function (token) {
console.log("TOKEN:", token);
},
- // (required) Called when a remote or local notification is opened or received
- onNotification: function(notification) {
+ // (required) Called when a remote is received or opened, or local notification is opened
+ onNotification: function (notification) {
console.log("NOTIFICATION:", notification);
// process the notification
- // required on iOS only (see fetchCompletionHandler docs: https://github.com/react-native-community/react-native-push-notification-ios)
+ // (required) Called when a remote is received or opened, or local notification is opened
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
- // ANDROID ONLY: GCM or FCM Sender ID (product_number) (optional - not required for local notifications, but is need to receive remote push notifications)
- senderID: "YOUR GCM (OR FCM) SENDER ID",
+ // (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
+ onAction: function (notification) {
+ console.log("ACTION:", notification.action);
+ console.log("NOTIFICATION:", notification);
+
+ // process the action
+ },
+
+ // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
+ onRegistrationError: function(err) {
+ console.error(err.message, err);
+ },
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
- sound: true
+ sound: true,
},
// Should the initial notification be popped automatically
@@ -210,15 +273,16 @@ PushNotification.configure({
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
+ * - if you are not using remote notification or do not have Firebase installed, use this:
+ * requestPermissions: Platform.OS === 'ios'
*/
- requestPermissions: true
+ requestPermissions: true,
});
```
## Example app
-Example folder contains an example app to demonstrate how to use this package. The notification Handling is done in `NotifService.js`. For Remote notifications, configure your SenderId in `app.json`. You can also edit it directly in the app.
-To send Push notifications, you can use the online tool [PushWatch](https://www.pushwatch.com/gcm/).
+Example folder contains an example app to demonstrate how to use this package. The notification Handling is done in `NotifService.js`.
Please test your PRs with this example app before submitting them. It'll help maintaining this repo.
@@ -233,55 +297,77 @@ Notification object example:
foreground: false, // BOOLEAN: If the notification was received in foreground or not
userInteraction: false, // BOOLEAN: If the notification was opened by the user from the notification area or not
message: 'My Notification Message', // STRING: The notification message
- data: {}, // OBJECT: The push data
+ data: {}, // OBJECT: The push data or the defined userInfo in local notifications
}
```
## Local Notifications
-`PushNotification.localNotification(details: Object)`
+```js
+PushNotification.localNotification(details: Object)
+```
EXAMPLE:
```javascript
PushNotification.localNotification({
- /* Android Only Properties */
- id: '0', // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
- ticker: "My Notification Ticker", // (optional)
- autoCancel: true, // (optional) default: true
- largeIcon: "ic_launcher", // (optional) default: "ic_launcher"
- smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher"
- bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop
- subText: "This is a subText", // (optional) default: none
- color: "red", // (optional) default: system default
- vibrate: true, // (optional) default: true
- vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
- tag: 'some_tag', // (optional) add tag to message
- group: "group", // (optional) add group to message
- ongoing: false, // (optional) set whether this is an "ongoing" notification
- priority: "high", // (optional) set notification priority, default: high
- visibility: "private", // (optional) set notification visibility, default: private
- importance: "high", // (optional) set notification importance, default: high
-
- /* iOS only properties */
- alertAction: // (optional) default: view
- category: // (optional) default: null
- userInfo: // (optional) default: null (object containing additional notification data)
-
- /* iOS and Android properties */
- title: "My Notification Title", // (optional)
- message: "My Notification Message", // (required)
- playSound: false, // (optional) default: true
- soundName: 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
- number: '10', // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
- repeatType: 'day', // (optional) Repeating interval. Check 'Repeating Notifications' section for more info.
- actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more
+ /* Android Only Properties */
+ channelId: "your-channel-id", // (required) channelId, if the channel doesn't exist, notification will not trigger.
+ ticker: "My Notification Ticker", // (optional)
+ showWhen: true, // (optional) default: true
+ autoCancel: true, // (optional) default: true
+ largeIcon: "ic_launcher", // (optional) default: "ic_launcher". Use "" for no large icon.
+ largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
+ smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher". Use "" for default small icon.
+ bigText: "My big text that will be shown when notification is expanded. Styling can be done using HTML tags(see android docs for details)", // (optional) default: "message" prop
+ subText: "This is a subText", // (optional) default: none
+ bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
+ bigLargeIcon: "ic_launcher", // (optional) default: undefined
+ bigLargeIconUrl: "https://www.example.tld/bigicon.jpg", // (optional) default: undefined
+ color: "red", // (optional) default: system default
+ vibrate: true, // (optional) default: true
+ vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
+ tag: "some_tag", // (optional) add tag to message
+ group: "group", // (optional) add group to message
+ groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false
+ ongoing: false, // (optional) set whether this is an "ongoing" notification
+ priority: "high", // (optional) set notification priority, default: high
+ visibility: "private", // (optional) set notification visibility, default: private
+ ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear). should be used in combine with `com.dieam.reactnativepushnotification.notification_foreground` setting
+ shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined
+ onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false
+
+ when: null, // (optional) Add a timestamp (Unix timestamp value in milliseconds) pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null.
+ usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false.
+ timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null
+
+ messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module.
+
+ actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more
+ invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true
+
+ /* iOS only properties */
+ category: "", // (optional) default: empty string
+ subtitle: "My Notification Subtitle", // (optional) smaller title below notification title
+
+ /* iOS and Android properties */
+ id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
+ title: "My Notification Title", // (optional)
+ message: "My Notification Message", // (required)
+ picture: "https://www.example.tld/picture.jpg", // (optional) Display an picture with the notification, alias of `bigPictureUrl` for Android. default: undefined
+ userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error)
+ playSound: false, // (optional) default: true
+ soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
+ number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
+ repeatType: "day", // (optional) Repeating interval. Check 'Repeating Notifications' section for more info.
});
```
## Scheduled Notifications
-`PushNotification.localNotificationSchedule(details: Object)`
+```js
+PushNotification.localNotificationSchedule(details: Object)
+```
EXAMPLE:
@@ -289,7 +375,25 @@ EXAMPLE:
PushNotification.localNotificationSchedule({
//... You can use all the options from localNotifications
message: "My Notification Message", // (required)
- date: new Date(Date.now() + 60 * 1000) // in 60 secs
+ date: new Date(Date.now() + 60 * 1000), // in 60 secs
+ allowWhileIdle: false, // (optional) set notification to work while on doze, default: false
+
+ /* Android Only Properties */
+ repeatTime: 1, // (optional) Increment of configured repeatType. Check 'Repeating Notifications' section for more info.
+});
+```
+
+## Get the initial notification
+
+```js
+PushNotification.popInitialNotification(callback)
+```
+
+EXAMPLE:
+
+```javascript
+PushNotification.popInitialNotification((notification) => {
+ console.log('Initial Notification', notification);
});
```
@@ -303,23 +407,196 @@ In the location notification json specify the full file name:
soundName: 'my_sound.mp3'
-## Cancelling notifications
+## Channel Management (Android)
+
+To use channels, create them at startup and pass the matching `channelId` through to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`.
+
+```javascript
+import PushNotification, {Importance} from 'react-native-push-notification';
+...
+ PushNotification.createChannel(
+ {
+ channelId: "channel-id", // (required)
+ channelName: "My channel", // (required)
+ channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
+ playSound: false, // (optional) default: true
+ soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
+ importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
+ vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
+ },
+ (created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
+ );
+```
+
+**NOTE: Without channel, notifications don't work**
+
+In the notifications options, you must provide a channel id with `channelId: "your-channel-id"`, if the channel doesn't exist the notification might not be triggered. Once the channel is created, the channel cannot be updated. Make sure your `channelId` is different if you change these options. If you have created a channel in another way, it will apply options of the channel.
+
+If you want to use a different default channel for remote notification, refer to the documentation of Firebase:
+
+[Set up a Firebase Cloud Messaging client app on Android](https://firebase.google.com/docs/cloud-messaging/android/client?hl=fr)
+
+```xml
+
+```
-### 1) cancelLocalNotifications
+For local notifications, the same kind of option is available:
+
+- you can use:
+ ```xml
+
+ ```
+- If not defined, fallback to the Firebase value defined in the `AndroidManifest`:
+ ```xml
+
+ ```
+- If not defined, fallback to the default Firebase channel id `fcm_fallback_notification_channel`
+
+### List channels
+
+You can list available channels with:
+
+```js
+PushNotification.getChannels(function (channel_ids) {
+ console.log(channel_ids); // ['channel_id_1']
+});
+```
+
+### Channel exists
+
+You can check if a channel exists with:
+
+```js
+PushNotification.channelExists(channel_id, function (exists) {
+ console.log(exists); // true/false
+});
+```
-#### Android
+### Channel blocked
+
+You can check if a channel blocked with:
+
+```js
+PushNotification.channelBlocked(channel_id, function (blocked) {
+ console.log(blocked); // true/false
+});
+```
+
+### Delete channel
+
+You can delete a channel with:
+
+```js
+PushNotification.deleteChannel(channel_id);
+```
+
+## Cancelling notifications
+
+### 1) cancelLocalNotification
The `id` parameter for `PushNotification.localNotification` is required for this operation. The id supplied will then be used for the cancel operation.
```javascript
-// Android
PushNotification.localNotification({
...
id: '123'
...
});
-PushNotification.cancelLocalNotifications({id: '123'});
+PushNotification.cancelLocalNotification('123');
+```
+
+### 2) cancelAllLocalNotifications
+
+```javascript
+PushNotification.cancelAllLocalNotifications()
+```
+
+Cancels all scheduled notifications AND clears the notifications alerts that are in the notification centre.
+
+### 3) removeAllDeliveredNotifications
+
+```javascript
+PushNotification.removeAllDeliveredNotifications();
+```
+
+Remove all delivered notifications from Notification Center
+
+### 4) getDeliveredNotifications
+
+```javascript
+PushNotification.getDeliveredNotifications(callback);
+```
+
+Provides you with a list of the app’s notifications that are still displayed in Notification Center
+
+**Parameters:**
+
+| Name | Type | Required | Description |
+| -------- | -------- | -------- | ----------------------------------------------------------- |
+| callback | function | Yes | Function which receive an array of delivered notifications. |
+
+A delivered notification is an object containing:
+
+- `identifier` : The identifier of this notification.
+- `title` : The title of this notification.
+- `body` : The body of this notification.
+- `category` : The category of this notification (optional).
+- `userInfo` : An object containing additional notification data (optional).
+- `thread-id` : The thread identifier of this notification, if has one.
+
+### 5) removeDeliveredNotifications
+
+```javascript
+PushNotification.removeDeliveredNotifications(identifiers);
+```
+
+Removes the specified notifications from Notification Center
+
+**Parameters:**
+
+| Name | Type | Required | Description |
+| ----------- | ----- | -------- | ---------------------------------- |
+| identifiers | array | Yes | Array of notification identifiers. |
+
+### 6) getScheduledLocalNotifications
+
+```javascript
+PushNotification.getScheduledLocalNotifications(callback);
+```
+
+Provides you with a list of the app’s scheduled local notifications that are yet to be displayed
+
+**Parameters:**
+
+| Name | Type | Required | Description |
+| -------- | -------- | -------- | ----------------------------------------------------------- |
+| callback | function | Yes | Function which receive an array of delivered notifications. |
+
+Returns an array of local scheduled notification objects containing:
+
+| Name | Type | Description |
+| -------------- | ------ | -------------------------------------------------------- |
+| id | number | The identifier of this notification. |
+| date | Date | The fire date of this notification. |
+| title | string | The title of this notification. |
+| message | string | The message body of this notification. |
+| soundName | string | The sound name of this notification. |
+| repeatInterval | number | (Android only) The repeat interval of this notification. |
+| number | number | App notification badge count number. |
+| data | any | The user info of this notification. |
+
+## Abandon Permissions
+
+```js
+PushNotification.abandonPermissions()
```
+Revokes the current token and unregister for all remote notifications received via APNS or FCM.
## Notification priority
@@ -327,11 +604,13 @@ PushNotification.cancelLocalNotifications({id: '123'});
Available options:
-"max" = NotficationCompat.PRIORITY_MAX
-"high" = NotficationCompat.PRIORITY_HIGH
-"low" = NotficationCompat.PRIORITY_LOW
-"min" = NotficationCompat.PRIORITY_MIN
+```
+"max" = NotficationCompat.PRIORITY_MAX\
+"high" = NotficationCompat.PRIORITY_HIGH\
+"low" = NotficationCompat.PRIORITY_LOW\
+"min" = NotficationCompat.PRIORITY_MIN\
"default" = NotficationCompat.PRIORITY_DEFAULT
+```
More information: https://developer.android.com/reference/android/app/Notification.html#PRIORITY_DEFAULT
@@ -341,114 +620,192 @@ More information: https://developer.android.com/reference/android/app/Notificati
Available options:
-"private" = NotficationCompat.VISIBILITY_PRIVATE
-"public" = NotficationCompat.VISIBILITY_PUBLIC
-"secret" = NotficationCompat.VISIBILITY_SECRET
-
+```
+"private" = NotficationCompat.VISIBILITY_PRIVATE\
+"public" = NotficationCompat.VISIBILITY_PUBLIC\
+"secret" = NotficationCompat.VISIBILITY_SECRET
+```
More information: https://developer.android.com/reference/android/app/Notification.html#VISIBILITY_PRIVATE
## Notification importance
-(optional) Specify `importance` to set importance of notification. Default value: "high"
+(optional) Specify `importance` to set importance of notification. Default value: Importance.HIGH
+Constants available on the `Importance` object. `import PushNotification, {Importance} from 'react-native-push-notification';`
Available options:
-
-"default" = NotificationManager.IMPORTANCE_DEFAULT
-"max" = NotificationManager.IMPORTANCE_MAX
-"high" = NotificationManager.IMPORTANCE_HIGH
-"low" = NotificationManager.IMPORTANCE_LOW
-"min" = NotificationManager.IMPORTANCE_MIN
-"none" = NotificationManager.IMPORTANCE_NONE
-"unspecified" = NotificationManager.IMPORTANCE_UNSPECIFIED
+```
+Importance.DEFAULT = NotificationManager.IMPORTANCE_DEFAULT\
+Importance.HIGH = NotificationManager.IMPORTANCE_HIGH\
+Importance.LOW = NotificationManager.IMPORTANCE_LOW\
+Importance.MIN = NotificationManager.IMPORTANCE_MIN\
+Importance.NONE= NotificationManager.IMPORTANCE_NONE\
+Importance.UNSPECIFIED = NotificationManager.IMPORTANCE_UNSPECIFIED
+```
More information: https://developer.android.com/reference/android/app/NotificationManager#IMPORTANCE_DEFAULT
-#### IOS
+## Show notifications while the app is in foreground
-The `userInfo` parameter for `PushNotification.localNotification` is required for this operation and must contain an `id` parameter. The id supplied will then be used for the cancel operation.
+If you want a consistent results in Android & iOS with the most flexibility, it is best to handle it manually by prompting a local notification when `onNotification` is triggered by a remote push notification on foreground (check `notification.foreground` prop).
-```javascript
-// IOS
-PushNotification.localNotification({
- ...
- userInfo: { id: '123' }
- ...
-});
-PushNotification.cancelLocalNotifications({id: '123'});
-```
+Watch out for an infinite loop triggering `onNotification` - remote & local notification will trigger it. You can overcome this by marking local notifications' data.
-### 2) cancelAllLocalNotifications
+## Notification while idle
-`PushNotification.cancelAllLocalNotifications()`
+(optional) Specify `allowWhileIdle` to set if the notification should be allowed to execute even when the system is on low-power idle modes.
-Cancels all scheduled notifications AND clears the notifications alerts that are in the notification centre.
+On Android 6.0 (API level 23) and forward, the Doze was introduced to reduce battery consumption when the device is unused for long periods of time. But while on Doze the AlarmManager alarms (used to show scheduled notifications) are deferred to the next maintenance window. This may cause the notification to be delayed while on Doze.
-_NOTE: there is currently no api for removing specific notification alerts from the notification centre._
+This can significantly impact the power use of the device when idle. So it must only be used when the notification is required to go off on a exact time, for example on a calendar notification.
+
+More information:
+https://developer.android.com/training/monitoring-device-state/doze-standby
## Repeating Notifications
-(optional) Specify `repeatType` and optionally `repeatTime` while scheduling the local notification. Check the local notification example above.
+(optional) Specify `repeatType` and optionally `repeatTime` (Android-only) while scheduling the local notification. Check the local notification example above.
-Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, `time`. If specified as time, it should be accompanied by one more parameter `repeatTime` which should the number of milliseconds between each interval.
+### iOS
+Property `repeatType` can only be `month`, `week`, `day`, `hour`, `minute`.
-## Notification Actions
+NOTE: `repeatTime` do not work with iOS.
+
+### Android
+Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, `time`.
-(Android only) [Refer](https://github.com/zo0r/react-native-push-notification/issues/151) to this issue to see an example of a notification action.
+The interval used can be configured to a different interval using `repeatTime`. If `repeatType` is `time`, `repeatTime` must be specified as the number of milliseconds between each interval.
+For example, to configure a notification every other day
+
+```javascript
+PushNotification.localNotificationSchedule({
+ ...
+ repeatType: 'day',
+ repeatTime: 2,
+ ...
+});
+```
-Two things are required to setup notification actions.
+## Notification Actions
-### 1) Specify notification actions for a notification
+(Android Only)
This is done by specifying an `actions` parameters while configuring the local notification. This is an array of strings where each string is a notification action that will be presented with the notification.
-For e.g. `actions: '["Accept", "Reject"]' // Must be in string format`
+For e.g. `actions: ['Accept', 'Reject']`
+
+When you handle actions in background (`invokeApp: false`), you can open the application and pass the initial notification by using use `PushNotification.invokeApp(notification)`.
-The array itself is specified in string format to circumvent some problems because of the way JSON arrays are handled by react-native android bridge.
+Make sure you have the receiver in `AndroidManifest.xml`:
-### 2) Specify handlers for the notification actions
+```xml
+
+```
-For each action specified in the `actions` field, we need to add a handler that is called when the user clicks on the action. This can be done in the `componentWillMount` of your main app file or in a separate file which is imported in your main app file. Notification actions handlers can be configured as below:
+Notifications with inline reply:
+You must register an action as "ReplyInput", this will show in the notifications an input to write in.
+
+EXAMPLE:
+```javascript
+PushNotification.localNotificationSchedule({
+ message: "My Notification Message", // (required)
+ date: new Date(Date.now() + (60 * 1000)), // in 60 secs
+ actions: ["ReplyInput"],
+ reply_placeholder_text: "Write your response...", // (required)
+ reply_button_text: "Reply" // (required)
+});
```
-import PushNotificationAndroid from 'react-native-push-notification'
-(function() {
- // Register all the valid actions for notifications here and add the action handler for each action
- PushNotificationAndroid.registerNotificationActions(['Accept','Reject','Yes','No']);
- DeviceEventEmitter.addListener('notificationActionReceived', function(action){
- console.log ('Notification action received: ' + action);
- const info = JSON.parse(action.dataJSON);
- if (info.action == 'Accept') {
- // Do work pertaining to Accept action here
- } else if (info.action == 'Reject') {
- // Do work pertaining to Reject action here
- }
- // Add all the required actions handlers
- });
-})();
+To get the text from the notification:
+
+```javascript
+...
+if(notification.action === "ReplyInput"){
+ console.log("texto", notification.reply_text)// this will contain the inline reply text.
+}
+...
```
-For iOS, you can use this [package](https://github.com/holmesal/react-native-ios-notification-actions) to add notification actions.
+For iOS, you can use:
+
+```javascript
+PushNotification.setNotificationCategories(categories);
+```
+
+And use the `category` field in the notification.
+
+Documentation [here](https://github.com/react-native-push-notification-ios/push-notification-ios#how-to-perform-different-action-based-on-user-selected-action) to add notification actions.
## Set application badge icon
-`PushNotification.setApplicationIconBadgeNumber(number: number)`
+```js
+PushNotification.setApplicationIconBadgeNumber(number: number)
+```
Works natively in iOS.
Uses the [ShortcutBadger](https://github.com/leolin310148/ShortcutBadger) on Android, and as such will not work on all Android devices.
-## Sending Notification Data From Server
+## Android Only Methods
-Same parameters as `PushNotification.localNotification()`
+```js
+PushNotification.subscribeToTopic(topic: string)
+```
+Subscribe to a topic (works only with Firebase)
-## Android Only Methods
+```js
+PushNotification.unsubscribeFromTopic(topic: string)
+```
+Unsubscribe from a topic (works only with Firebase)
+
+## Android Custom Notification Handling
+
+Unlike iOS, Android apps handle the creation of their own notifications. React Native Push Notifications does a "best guess" to create and handle incoming notifications. However, when using 3rd party notification platforms and tools, the initial notification creation process may need to be customized.
-`PushNotification.subscribeToTopic(topic: string)` Subscribe to a topic (works only with Firebase)
+### Customizing Notification Creation
+
+If your notification service uses a custom data payload format, React Native Push Notifications will not be able to parse the data correctly to create an initial notification.
+
+For these cases, you should:
+
+1. Remove the intent handler configuration for React Native Push Notifications from your `android/app/src/main/AndroidManifest.xml`.
+2. Implement initial notification creation as per the instructions from your Provider.
+
+### Handling Custom Payloads
+
+Data payloads of notifications from 3rd party services may not match the format expected by React Native Push Notification. When tapped, these notifications will not pass the details and data to the `onNotification()` event handler. Custom `IntentHandlers` allow you to fix this so that correct `notification` objects are sent to your `onNotification()` method.
+
+Custom handlers are added in Application init or `MainActivity.onCreate()` methods:
+
+```java
+RNPushNotification.IntentHandlers.add(new RNPushNotification.RNIntentHandler() {
+ @Override
+ public void onNewIntent(Intent intent) {
+ // If your provider requires some parsing on the intent before the data can be
+ // used, add that code here. Otherwise leave empty.
+ }
+
+ @Nullable
+ @Override
+ public Bundle getBundleFromIntent(Intent intent) {
+ // This should return the bundle data that will be serialized to the `notification.data`
+ // property sent to the `onNotification()` handler. Return `null` if there is no data
+ // or this is not an intent from your provider.
+
+ // Example:
+ if (intent.hasExtra("MY_NOTIFICATION_PROVIDER_DATA_KEY")) {
+ return intent.getBundleExtra("MY_NOTIFICATION_PROVIDER_DATA_KEY");
+ }
+ return null;
+ }
+});
+```
## Checking Notification Permissions
-`PushNotification.checkPermissions(callback: Function)` Check permissions
+```js
+PushNotification.checkPermissions(callback: Function) //Check permissions
+```
`callback` will be invoked with a `permissions` object:
@@ -458,6 +815,7 @@ Same parameters as `PushNotification.localNotification()`
## iOS Only Methods
-`PushNotification.getApplicationIconBadgeNumber(callback: Function)` Get badge number
+```js
+PushNotification.getApplicationIconBadgeNumber(callback: Function) //Get badge number
+```
-`PushNotification.abandonPermissions()` Abandon permissions
diff --git a/android/.classpath b/android/.classpath
new file mode 100644
index 000000000..eb19361b5
--- /dev/null
+++ b/android/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/android/.project b/android/.project
new file mode 100644
index 000000000..3865e0fa4
--- /dev/null
+++ b/android/.project
@@ -0,0 +1,23 @@
+
+
+ android
+ Project android created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 000000000..342e81ef5
--- /dev/null
+++ b/android/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/android/build.gradle b/android/build.gradle
index 2d3f07536..d6019f61c 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,6 @@
buildscript {
repositories {
+ mavenCentral()
google()
jcenter()
}
@@ -10,6 +11,7 @@ buildscript {
allprojects {
repositories {
+ mavenCentral()
google()
jcenter()
}
@@ -25,6 +27,11 @@ android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
@@ -43,15 +50,15 @@ android {
}
dependencies {
+ // Use either AndroidX library names or old/support library names based on major version of support lib
def supportLibVersion = safeExtGet('supportLibVersion', '27.1.1')
- def googlePlayServicesVersion = safeExtGet('googlePlayServicesVersion', '+')
- def firebaseVersion = safeExtGet('firebaseVersion', '+')
+ def supportLibMajorVersion = supportLibVersion.split('\\.')[0] as int
+ def appCompatLibName = (supportLibMajorVersion < 20) ? "androidx.appcompat:appcompat" : "com.android.support:appcompat-v7"
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
- implementation "com.android.support:appcompat-v7:$supportLibVersion"
+ implementation "$appCompatLibName:$supportLibVersion"
implementation 'com.facebook.react:react-native:+'
- implementation "com.google.android.gms:play-services-gcm:$googlePlayServicesVersion"
- implementation 'me.leolin:ShortcutBadger:1.1.8@aar'
- implementation "com.google.firebase:firebase-messaging:$firebaseVersion"
+ implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
+ implementation "com.google.firebase:firebase-messaging:${safeExtGet('firebaseMessagingVersion', '21.1.0')}"
}
diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro
deleted file mode 100644
index f7e855c93..000000000
--- a/android/proguard-rules.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /usr/local/Cellar/android-sdk/24.4.1/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/android/react-native-notifications.iml b/android/react-native-notifications.iml
deleted file mode 100644
index 0851c6ed0..000000000
--- a/android/react-native-notifications.iml
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugAndroidTestSources
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/react-native-push-notification.iml b/android/react-native-push-notification.iml
deleted file mode 100644
index 4c1e6c240..000000000
--- a/android/react-native-push-notification.iml
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/helpers/ApplicationBadgeHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/helpers/ApplicationBadgeHelper.java
index ad7538761..e97ebae5a 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/helpers/ApplicationBadgeHelper.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/helpers/ApplicationBadgeHelper.java
@@ -10,26 +10,18 @@
import me.leolin.shortcutbadger.Badger;
import me.leolin.shortcutbadger.ShortcutBadger;
-import me.leolin.shortcutbadger.impl.SamsungHomeBadger;
/**
* Helper for setting application launcher icon badge counts.
- *
- * This is a wrapper around {@link ShortcutBadger}, with a couple enhancements:
- *
- * - If the first attempt fails, don't retry. This keeps logs clean, as failed attempts are noisy.
- * - Test and apply a separate method for older Samsung devices, which ShortcutBadger has
- * (perhaps over-aggressively) deprecated. ref: https://github.com/leolin310148/ShortcutBadger/issues/40
+ * This is a wrapper around {@link ShortcutBadger}:
*/
public class ApplicationBadgeHelper {
public static final ApplicationBadgeHelper INSTANCE = new ApplicationBadgeHelper();
private static final String LOG_TAG = "ApplicationBadgeHelper";
- private static final Badger LEGACY_SAMSUNG_BADGER = new SamsungHomeBadger();
private Boolean applyAutomaticBadger;
- private Boolean applySamsungBadger;
private ComponentName componentName;
private ApplicationBadgeHelper() {
@@ -40,7 +32,6 @@ public void setApplicationIconBadgeNumber(Context context, int number) {
componentName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent();
}
tryAutomaticBadge(context, number);
- tryLegacySamsungBadge(context, number);
}
private void tryAutomaticBadge(Context context, int number) {
@@ -57,43 +48,4 @@ private void tryAutomaticBadge(Context context, int number) {
}
ShortcutBadger.applyCount(context, number);
}
-
- private void tryLegacySamsungBadge(Context context, int number) {
- // First attempt to apply legacy samsung badge. Check if eligible, then attempt it.
- if (null == applySamsungBadger) {
- applySamsungBadger = isLegacySamsungLauncher(context) && applyLegacySamsungBadge(context, number);
- if (applySamsungBadger) {
- FLog.i(LOG_TAG, "First attempt to use legacy Samsung badger succeeded; permanently enabling method.");
- } else {
- FLog.w(LOG_TAG, "First attempt to use legacy Samsung badger failed; permanently disabling method.");
- }
- return;
- } else if (!applySamsungBadger) {
- return;
- }
- applyLegacySamsungBadge(context, number);
- }
-
- private boolean isLegacySamsungLauncher(Context context) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
-
- if (resolveInfo == null || resolveInfo.activityInfo.name.toLowerCase().contains("resolver")) {
- return false;
- }
-
- String currentHomePackage = resolveInfo.activityInfo.packageName;
- return LEGACY_SAMSUNG_BADGER.getSupportLaunchers().contains(currentHomePackage);
- }
-
- private boolean applyLegacySamsungBadge(Context context, int number) {
- try {
- LEGACY_SAMSUNG_BADGER.executeBadge(context, componentName, number);
- return true;
- } catch (Exception e) {
- FLog.w(LOG_TAG, "Legacy Samsung badger failed", e);
- return false;
- }
- }
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java
index 88b4cc719..d16268059 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java
@@ -8,33 +8,51 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
-import java.util.Random;
import android.util.Log;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
import com.google.firebase.messaging.FirebaseMessaging;
public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener {
public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag
+ public static final String KEY_TEXT_REPLY = "key_text_reply";
+
+ public interface RNIntentHandler {
+ void onNewIntent(Intent intent);
+
+ @Nullable
+ Bundle getBundleFromIntent(Intent intent);
+ }
+
+ public static ArrayList IntentHandlers = new ArrayList();
private RNPushNotificationHelper mRNPushNotificationHelper;
- private final Random mRandomNumberGenerator = new Random(System.currentTimeMillis());
+ private final SecureRandom mRandomNumberGenerator = new SecureRandom();
private RNPushNotificationJsDelivery mJsDelivery;
public RNPushNotification(ReactApplicationContext reactContext) {
@@ -48,13 +66,11 @@ public RNPushNotification(ReactApplicationContext reactContext) {
mRNPushNotificationHelper = new RNPushNotificationHelper(applicationContext);
// This is used to delivery callbacks to JS
mJsDelivery = new RNPushNotificationJsDelivery(reactContext);
-
- registerNotificationsRegistration();
}
@Override
public String getName() {
- return "RNPushNotification";
+ return "ReactNativePushNotification";
}
@Override
@@ -69,55 +85,45 @@ private Bundle getBundleFromIntent(Intent intent) {
if (intent.hasExtra("notification")) {
bundle = intent.getBundleExtra("notification");
} else if (intent.hasExtra("google.message_id")) {
- bundle = intent.getExtras();
+ bundle = new Bundle();
+
+ bundle.putBundle("data", intent.getExtras());
+ }
+
+ if (bundle == null) {
+ for (RNIntentHandler handler : IntentHandlers) {
+ bundle = handler.getBundleFromIntent(intent);
+ }
}
+
+ if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("userInteraction")) {
+ bundle.putBoolean("userInteraction", true);
+ }
+
return bundle;
}
+
+ @Override
public void onNewIntent(Intent intent) {
+ for (RNIntentHandler handler : IntentHandlers) {
+ handler.onNewIntent(intent);
+ }
+
Bundle bundle = this.getBundleFromIntent(intent);
if (bundle != null) {
- bundle.putBoolean("foreground", false);
- intent.putExtra("notification", bundle);
mJsDelivery.notifyNotification(bundle);
}
}
- private void registerNotificationsRegistration() {
- IntentFilter intentFilter = new IntentFilter(getReactApplicationContext().getPackageName() + ".RNPushNotificationRegisteredToken");
-
- getReactApplicationContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String token = intent.getStringExtra("token");
- WritableMap params = Arguments.createMap();
- params.putString("deviceToken", token);
-
- mJsDelivery.sendEvent("remoteNotificationsRegistered", params);
- }
- }, intentFilter);
- }
+ @ReactMethod
+ public void invokeApp(ReadableMap data) {
+ Bundle bundle = null;
- private void registerNotificationsReceiveNotificationActions(ReadableArray actions) {
- IntentFilter intentFilter = new IntentFilter();
- // Add filter for each actions.
- for (int i = 0; i < actions.size(); i++) {
- String action = actions.getString(i);
- intentFilter.addAction(getReactApplicationContext().getPackageName() + "." + action);
+ if (data != null) {
+ bundle = Arguments.toBundle(data);
}
- getReactApplicationContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Bundle bundle = intent.getBundleExtra("notification");
-
- // Notify the action.
- mJsDelivery.notifyNotificationAction(bundle);
-
- // Dismiss the notification popup.
- NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
- int notificationID = Integer.parseInt(bundle.getString("id"));
- manager.cancel(notificationID);
- }
- }, intentFilter);
+
+ mRNPushNotificationHelper.invokeApp(bundle);
}
@ReactMethod
@@ -128,23 +134,34 @@ public void checkPermissions(Promise promise) {
}
@ReactMethod
- public void requestPermissions(String senderID) {
- ReactContext reactContext = getReactApplicationContext();
-
- Intent GCMService = new Intent(reactContext, RNPushNotificationRegistrationService.class);
-
- try {
- GCMService.putExtra("senderID", senderID);
- reactContext.startService(GCMService);
- } catch (Exception e) {
- Log.d("EXCEPTION SERVICE::::::", "requestPermissions: " + e);
- }
+ public void requestPermissions() {
+ final RNPushNotificationJsDelivery fMjsDelivery = mJsDelivery;
+
+ FirebaseMessaging.getInstance().getToken()
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (!task.isSuccessful()) {
+ Log.e(LOG_TAG, "exception", task.getException());
+ return;
+ }
+
+ WritableMap params = Arguments.createMap();
+ params.putString("deviceToken", task.getResult());
+ fMjsDelivery.sendEvent("remoteNotificationsRegistered", params);
+ }
+ });
}
@ReactMethod
public void subscribeToTopic(String topic) {
FirebaseMessaging.getInstance().subscribeToTopic(topic);
}
+
+ @ReactMethod
+ public void unsubscribeFromTopic(String topic) {
+ FirebaseMessaging.getInstance().unsubscribeFromTopic(topic);
+ }
@ReactMethod
public void presentLocalNotification(ReadableMap details) {
@@ -209,23 +226,117 @@ public void cancelAllLocalNotifications() {
@ReactMethod
/**
- * Cancel scheduled notifications, and removes notifications from the notification centre.
+ * Cancel scheduled notification, and remove notification from the notification centre.
*
*/
- public void cancelLocalNotifications(ReadableMap userInfo) {
- mRNPushNotificationHelper.cancelScheduledNotification(userInfo);
+ public void cancelLocalNotification(String notification_id) {
+ mRNPushNotificationHelper.cancelScheduledNotification(notification_id);
}
@ReactMethod
/**
* Clear notification from the notification centre.
*/
- public void clearLocalNotification(int notificationID) {
- mRNPushNotificationHelper.clearNotification(notificationID);
+ public void clearLocalNotification(String tag, int notificationID) {
+ mRNPushNotificationHelper.clearNotification(tag, notificationID);
+ }
+
+ @ReactMethod
+ /**
+ * Clears all notifications from the notification center
+ *
+ */
+ public void removeAllDeliveredNotifications() {
+ mRNPushNotificationHelper.clearNotifications();
+ }
+
+ @ReactMethod
+ /**
+ * Returns a list of all notifications currently in the Notification Center
+ */
+ public void getDeliveredNotifications(Callback callback) {
+ callback.invoke(mRNPushNotificationHelper.getDeliveredNotifications());
+ }
+
+ @ReactMethod
+ /**
+ * Returns a list of all currently scheduled notifications
+ */
+ public void getScheduledLocalNotifications(Callback callback) {
+ callback.invoke(mRNPushNotificationHelper.getScheduledLocalNotifications());
+ }
+
+ @ReactMethod
+ /**
+ * Removes notifications from the Notification Center, whose id matches
+ * an element in the provided array
+ */
+ public void removeDeliveredNotifications(ReadableArray identifiers) {
+ mRNPushNotificationHelper.clearDeliveredNotifications(identifiers);
+ }
+
+ @ReactMethod
+ /**
+ * Unregister for all remote notifications received
+ */
+ public void abandonPermissions() {
+ FirebaseMessaging.getInstance().deleteToken();
+ Log.i(LOG_TAG, "InstanceID deleted");
+ }
+
+ @ReactMethod
+ /**
+ * List all channels id
+ */
+ public void getChannels(Callback callback) {
+ WritableArray array = Arguments.fromList(mRNPushNotificationHelper.listChannels());
+
+ if(callback != null) {
+ callback.invoke(array);
+ }
}
@ReactMethod
- public void registerNotificationActions(ReadableArray actions) {
- registerNotificationsReceiveNotificationActions(actions);
+ /**
+ * Check if channel exists with a given id
+ */
+ public void channelExists(String channel_id, Callback callback) {
+ boolean exists = mRNPushNotificationHelper.channelExists(channel_id);
+
+ if(callback != null) {
+ callback.invoke(exists);
+ }
+ }
+
+ @ReactMethod
+ /**
+ * Creates a channel if it does not already exist. Returns whether the channel was created.
+ */
+ public void createChannel(ReadableMap channelInfo, Callback callback) {
+ boolean created = mRNPushNotificationHelper.createChannel(channelInfo);
+
+ if(callback != null) {
+ callback.invoke(created);
+ }
+ }
+
+ @ReactMethod
+ /**
+ * Check if channel is blocked with a given id
+ */
+ public void channelBlocked(String channel_id, Callback callback) {
+ boolean blocked = mRNPushNotificationHelper.channelBlocked(channel_id);
+
+ if(callback != null) {
+ callback.invoke(blocked);
+ }
+ }
+
+ @ReactMethod
+ /**
+ * Delete channel with a given id
+ */
+ public void deleteChannel(String channel_id) {
+ mRNPushNotificationHelper.deleteChannel(channel_id);
}
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java
new file mode 100644
index 000000000..ada960388
--- /dev/null
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java
@@ -0,0 +1,102 @@
+package com.dieam.reactnativepushnotification.modules;
+
+import android.app.Application;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import com.facebook.react.ReactApplication;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.bridge.ReactContext;
+import androidx.core.app.RemoteInput;
+
+import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
+import static com.dieam.reactnativepushnotification.modules.RNPushNotification.KEY_TEXT_REPLY;
+
+public class RNPushNotificationActions extends BroadcastReceiver {
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ String intentActionPrefix = context.getPackageName() + ".ACTION_";
+
+ Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver loading scheduled notifications");
+
+ if (null == intent.getAction() || !intent.getAction().startsWith(intentActionPrefix)) {
+ return;
+ }
+
+ final Bundle bundle = intent.getBundleExtra("notification");
+ Bundle remoteInput = null;
+
+ if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH){
+ remoteInput = RemoteInput.getResultsFromIntent(intent);
+ }
+ if (remoteInput != null) {
+ // Add to reply_text the text written by the user in the notification
+ bundle.putCharSequence("reply_text", remoteInput.getCharSequence(KEY_TEXT_REPLY));
+ }
+ // Dismiss the notification popup.
+ NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ int notificationID = Integer.parseInt(bundle.getString("id"));
+
+ boolean autoCancel = bundle.getBoolean("autoCancel", true);
+
+ if(autoCancel) {
+ if (bundle.containsKey("tag")) {
+ String tag = bundle.getString("tag");
+ manager.cancel(tag, notificationID);
+ } else {
+ manager.cancel(notificationID);
+ }
+ }
+
+ boolean invokeApp = bundle.getBoolean("invokeApp", true);
+
+ // Notify the action.
+ if(invokeApp) {
+ RNPushNotificationHelper helper = new RNPushNotificationHelper((Application) context.getApplicationContext());
+
+ helper.invokeApp(bundle);
+
+ context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ } else {
+
+ // We need to run this on the main thread, as the React code assumes that is true.
+ // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers:
+ // "Can't create handler inside thread that has not called Looper.prepare()"
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ public void run() {
+ // Construct and load our normal React JS code bundle
+ final ReactInstanceManager mReactInstanceManager = ((ReactApplication) context.getApplicationContext()).getReactNativeHost().getReactInstanceManager();
+ ReactContext context = mReactInstanceManager.getCurrentReactContext();
+ // If it's constructed, send a notification
+ if (context != null) {
+ RNPushNotificationJsDelivery mJsDelivery = new RNPushNotificationJsDelivery(context);
+
+ mJsDelivery.notifyNotificationAction(bundle);
+ } else {
+ // Otherwise wait for construction, then send the notification
+ mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
+ public void onReactContextInitialized(ReactContext context) {
+ RNPushNotificationJsDelivery mJsDelivery = new RNPushNotificationJsDelivery(context);
+
+ mJsDelivery.notifyNotificationAction(bundle);
+
+ mReactInstanceManager.removeReactInstanceEventListener(this);
+ }
+ });
+ if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
+ // Construct it in the background
+ mReactInstanceManager.createReactContextInBackground();
+ }
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java
index 0d2099ab7..1602daa0d 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java
@@ -10,6 +10,8 @@
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Iterator;
+
import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
public class RNPushNotificationAttributes {
@@ -18,48 +20,80 @@ public class RNPushNotificationAttributes {
private static final String FIRE_DATE = "fireDate";
private static final String TITLE = "title";
private static final String TICKER = "ticker";
+ private static final String SHOW_WHEN = "showWhen";
private static final String AUTO_CANCEL = "autoCancel";
private static final String LARGE_ICON = "largeIcon";
+ private static final String LARGE_ICON_URL = "largeIconUrl";
private static final String SMALL_ICON = "smallIcon";
private static final String BIG_TEXT = "bigText";
private static final String SUB_TEXT = "subText";
+ private static final String BIG_PICTURE_URL = "bigPictureUrl";
+ private static final String SHORTCUT_ID = "shortcutId";
+ private static final String CHANNEL_ID = "channelId";
private static final String NUMBER = "number";
private static final String SOUND = "sound";
private static final String COLOR = "color";
private static final String GROUP = "group";
- private static final String USER_INTERACTION = "userInteraction";
+ private static final String GROUP_SUMMARY = "groupSummary";
+ private static final String MESSAGE_ID = "messageId";
private static final String PLAY_SOUND = "playSound";
private static final String VIBRATE = "vibrate";
private static final String VIBRATION = "vibration";
private static final String ACTIONS = "actions";
+ private static final String INVOKE_APP = "invokeApp";
private static final String TAG = "tag";
private static final String REPEAT_TYPE = "repeatType";
private static final String REPEAT_TIME = "repeatTime";
+ private static final String WHEN = "when";
+ private static final String USES_CHRONOMETER = "usesChronometer";
+ private static final String TIMEOUT_AFTER = "timeoutAfter";
+ private static final String ONLY_ALERT_ONCE = "onlyAlertOnce";
private static final String ONGOING = "ongoing";
+ private static final String REPLY_BUTTON_TEXT = "reply_button_text";
+ private static final String REPLAY_PLACEHOLDER_TEXT = "reply_placeholder_text";
+ private static final String ALLOW_WHILE_IDLE = "allowWhileIdle";
+ private static final String IGNORE_IN_FOREGROUND = "ignoreInForeground";
+ private static final String USER_INFO = "userInfo";
private final String id;
private final String message;
private final double fireDate;
private final String title;
private final String ticker;
+ private final boolean showWhen;
private final boolean autoCancel;
private final String largeIcon;
+ private final String largeIconUrl;
private final String smallIcon;
private final String bigText;
private final String subText;
+ private final String bigPictureUrl;
+ private final String shortcutId;
private final String number;
+ private final String channelId;
private final String sound;
private final String color;
private final String group;
- private final boolean userInteraction;
+ private final boolean groupSummary;
+ private final String messageId;
private final boolean playSound;
private final boolean vibrate;
private final double vibration;
private final String actions;
+ private final boolean invokeApp;
private final String tag;
private final String repeatType;
private final double repeatTime;
+ private final double when;
+ private final boolean usesChronometer;
+ private final double timeoutAfter;
+ private final boolean onlyAlertOnce;
private final boolean ongoing;
+ private final String reply_button_text;
+ private final String reply_placeholder_text;
+ private final boolean allowWhileIdle;
+ private final boolean ignoreInForeground;
+ private final String userInfo;
public RNPushNotificationAttributes(Bundle bundle) {
id = bundle.getString(ID);
@@ -67,24 +101,40 @@ public RNPushNotificationAttributes(Bundle bundle) {
fireDate = bundle.getDouble(FIRE_DATE);
title = bundle.getString(TITLE);
ticker = bundle.getString(TICKER);
+ showWhen = bundle.getBoolean(SHOW_WHEN);
autoCancel = bundle.getBoolean(AUTO_CANCEL);
largeIcon = bundle.getString(LARGE_ICON);
+ largeIconUrl = bundle.getString(LARGE_ICON_URL);
smallIcon = bundle.getString(SMALL_ICON);
bigText = bundle.getString(BIG_TEXT);
subText = bundle.getString(SUB_TEXT);
+ bigPictureUrl= bundle.getString(BIG_PICTURE_URL);
+ shortcutId = bundle.getString(SHORTCUT_ID);
number = bundle.getString(NUMBER);
+ channelId = bundle.getString(CHANNEL_ID);
sound = bundle.getString(SOUND);
color = bundle.getString(COLOR);
group = bundle.getString(GROUP);
- userInteraction = bundle.getBoolean(USER_INTERACTION);
+ groupSummary = bundle.getBoolean(GROUP_SUMMARY);
+ messageId = bundle.getString(MESSAGE_ID);
playSound = bundle.getBoolean(PLAY_SOUND);
vibrate = bundle.getBoolean(VIBRATE);
vibration = bundle.getDouble(VIBRATION);
actions = bundle.getString(ACTIONS);
+ invokeApp = bundle.getBoolean(INVOKE_APP);
tag = bundle.getString(TAG);
repeatType = bundle.getString(REPEAT_TYPE);
repeatTime = bundle.getDouble(REPEAT_TIME);
+ when = bundle.getDouble(WHEN);
+ usesChronometer = bundle.getBoolean(USES_CHRONOMETER);
+ timeoutAfter = bundle.getDouble(TIMEOUT_AFTER);
+ onlyAlertOnce = bundle.getBoolean(ONLY_ALERT_ONCE);
ongoing = bundle.getBoolean(ONGOING);
+ reply_button_text = bundle.getString(REPLY_BUTTON_TEXT);
+ reply_placeholder_text = bundle.getString(REPLAY_PLACEHOLDER_TEXT);
+ allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE);
+ ignoreInForeground = bundle.getBoolean(IGNORE_IN_FOREGROUND);
+ userInfo = bundle.getString(USER_INFO);
}
private RNPushNotificationAttributes(JSONObject jsonObject) {
@@ -94,24 +144,40 @@ private RNPushNotificationAttributes(JSONObject jsonObject) {
fireDate = jsonObject.has(FIRE_DATE) ? jsonObject.getDouble(FIRE_DATE) : 0.0;
title = jsonObject.has(TITLE) ? jsonObject.getString(TITLE) : null;
ticker = jsonObject.has(TICKER) ? jsonObject.getString(TICKER) : null;
+ showWhen = jsonObject.has(SHOW_WHEN) ? jsonObject.getBoolean(SHOW_WHEN) : true;
autoCancel = jsonObject.has(AUTO_CANCEL) ? jsonObject.getBoolean(AUTO_CANCEL) : true;
largeIcon = jsonObject.has(LARGE_ICON) ? jsonObject.getString(LARGE_ICON) : null;
+ largeIconUrl = jsonObject.has(LARGE_ICON_URL) ? jsonObject.getString(LARGE_ICON_URL) : null;
smallIcon = jsonObject.has(SMALL_ICON) ? jsonObject.getString(SMALL_ICON) : null;
bigText = jsonObject.has(BIG_TEXT) ? jsonObject.getString(BIG_TEXT) : null;
subText = jsonObject.has(SUB_TEXT) ? jsonObject.getString(SUB_TEXT) : null;
+ bigPictureUrl = jsonObject.has(BIG_PICTURE_URL) ? jsonObject.getString(BIG_PICTURE_URL) : null;
+ shortcutId = jsonObject.has(SHORTCUT_ID) ? jsonObject.getString(SHORTCUT_ID) : null;
number = jsonObject.has(NUMBER) ? jsonObject.getString(NUMBER) : null;
+ channelId = jsonObject.has(CHANNEL_ID) ? jsonObject.getString(CHANNEL_ID) : null;
sound = jsonObject.has(SOUND) ? jsonObject.getString(SOUND) : null;
color = jsonObject.has(COLOR) ? jsonObject.getString(COLOR) : null;
group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null;
- userInteraction = jsonObject.has(USER_INTERACTION) ? jsonObject.getBoolean(USER_INTERACTION) : false;
+ groupSummary = jsonObject.has(GROUP_SUMMARY) ? jsonObject.getBoolean(GROUP_SUMMARY) : false;
+ messageId = jsonObject.has(MESSAGE_ID) ? jsonObject.getString(MESSAGE_ID) : null;
playSound = jsonObject.has(PLAY_SOUND) ? jsonObject.getBoolean(PLAY_SOUND) : true;
vibrate = jsonObject.has(VIBRATE) ? jsonObject.getBoolean(VIBRATE) : true;
vibration = jsonObject.has(VIBRATION) ? jsonObject.getDouble(VIBRATION) : 1000;
actions = jsonObject.has(ACTIONS) ? jsonObject.getString(ACTIONS) : null;
+ invokeApp = jsonObject.has(INVOKE_APP) ? jsonObject.getBoolean(INVOKE_APP) : true;
tag = jsonObject.has(TAG) ? jsonObject.getString(TAG) : null;
repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null;
repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0;
+ when = jsonObject.has(WHEN) ? jsonObject.getDouble(WHEN) : -1;
+ usesChronometer = jsonObject.has(USES_CHRONOMETER) ? jsonObject.getBoolean(USES_CHRONOMETER) : false;
+ timeoutAfter = jsonObject.has(TIMEOUT_AFTER) ? jsonObject.getDouble(TIMEOUT_AFTER) : -1;
+ onlyAlertOnce = jsonObject.has(ONLY_ALERT_ONCE) ? jsonObject.getBoolean(ONLY_ALERT_ONCE) : false;
ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false;
+ reply_button_text = jsonObject.has(REPLY_BUTTON_TEXT) ? jsonObject.getString(REPLY_BUTTON_TEXT) : null;
+ reply_placeholder_text = jsonObject.has(REPLAY_PLACEHOLDER_TEXT) ? jsonObject.getString(REPLAY_PLACEHOLDER_TEXT) : null;
+ allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false;
+ ignoreInForeground = jsonObject.has(IGNORE_IN_FOREGROUND) ? jsonObject.getBoolean(IGNORE_IN_FOREGROUND) : false;
+ userInfo = jsonObject.has(USER_INFO) ? jsonObject.getString(USER_INFO) : null;
} catch (JSONException e) {
throw new IllegalStateException("Exception while initializing RNPushNotificationAttributes from JSON", e);
}
@@ -120,57 +186,10 @@ private RNPushNotificationAttributes(JSONObject jsonObject) {
@NonNull
public static RNPushNotificationAttributes fromJson(String notificationAttributesJson) throws JSONException {
JSONObject jsonObject = new JSONObject(notificationAttributesJson);
+
return new RNPushNotificationAttributes(jsonObject);
}
- /**
- * User to find notifications:
- *
- *
- * @param userInfo map of fields to match
- * @return true all fields in userInfo object match, false otherwise
- */
- public boolean matches(ReadableMap userInfo) {
- Bundle bundle = toBundle();
-
- ReadableMapKeySetIterator iterator = userInfo.keySetIterator();
- while (iterator.hasNextKey()) {
- String key = iterator.nextKey();
-
- if (!bundle.containsKey(key))
- return false;
-
- switch (userInfo.getType(key)) {
- case Null: {
- if (bundle.get(key) != null)
- return false;
- break;
- }
- case Boolean: {
- if (userInfo.getBoolean(key) != bundle.getBoolean(key))
- return false;
- break;
- }
- case Number: {
- if ((userInfo.getDouble(key) != bundle.getDouble(key)) && (userInfo.getInt(key) != bundle.getInt(key)))
- return false;
- break;
- }
- case String: {
- if (!userInfo.getString(key).equals(bundle.getString(key)))
- return false;
- break;
- }
- case Map:
- return false;//there are no maps in the bundle
- case Array:
- return false;//there are no arrays in the bundle
- }
- }
-
- return true;
- }
-
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putString(ID, id);
@@ -178,24 +197,40 @@ public Bundle toBundle() {
bundle.putDouble(FIRE_DATE, fireDate);
bundle.putString(TITLE, title);
bundle.putString(TICKER, ticker);
+ bundle.putBoolean(SHOW_WHEN, showWhen);
bundle.putBoolean(AUTO_CANCEL, autoCancel);
bundle.putString(LARGE_ICON, largeIcon);
+ bundle.putString(LARGE_ICON_URL, largeIconUrl);
bundle.putString(SMALL_ICON, smallIcon);
bundle.putString(BIG_TEXT, bigText);
bundle.putString(SUB_TEXT, subText);
+ bundle.putString(BIG_PICTURE_URL, bigPictureUrl);
+ bundle.putString(SHORTCUT_ID, shortcutId);
bundle.putString(NUMBER, number);
+ bundle.putString(CHANNEL_ID, channelId);
bundle.putString(SOUND, sound);
bundle.putString(COLOR, color);
bundle.putString(GROUP, group);
- bundle.putBoolean(USER_INTERACTION, userInteraction);
+ bundle.putBoolean(GROUP_SUMMARY, groupSummary);
+ bundle.putString(MESSAGE_ID, messageId);
bundle.putBoolean(PLAY_SOUND, playSound);
bundle.putBoolean(VIBRATE, vibrate);
bundle.putDouble(VIBRATION, vibration);
bundle.putString(ACTIONS, actions);
+ bundle.putBoolean(INVOKE_APP, invokeApp);
bundle.putString(TAG, tag);
bundle.putString(REPEAT_TYPE, repeatType);
bundle.putDouble(REPEAT_TIME, repeatTime);
+ bundle.putDouble(WHEN, when);
+ bundle.putBoolean(USES_CHRONOMETER, usesChronometer);
+ bundle.putDouble(TIMEOUT_AFTER, timeoutAfter);
+ bundle.putBoolean(ONLY_ALERT_ONCE, onlyAlertOnce);
bundle.putBoolean(ONGOING, ongoing);
+ bundle.putString(REPLY_BUTTON_TEXT, reply_button_text);
+ bundle.putString(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text);
+ bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle);
+ bundle.putBoolean(IGNORE_IN_FOREGROUND, ignoreInForeground);
+ bundle.putString(USER_INFO, userInfo);
return bundle;
}
@@ -207,24 +242,40 @@ public JSONObject toJson() {
jsonObject.put(FIRE_DATE, fireDate);
jsonObject.put(TITLE, title);
jsonObject.put(TICKER, ticker);
+ jsonObject.put(SHOW_WHEN, showWhen);
jsonObject.put(AUTO_CANCEL, autoCancel);
jsonObject.put(LARGE_ICON, largeIcon);
+ jsonObject.put(LARGE_ICON_URL, largeIconUrl);
jsonObject.put(SMALL_ICON, smallIcon);
jsonObject.put(BIG_TEXT, bigText);
+ jsonObject.put(BIG_PICTURE_URL, bigPictureUrl);
jsonObject.put(SUB_TEXT, subText);
+ jsonObject.put(SHORTCUT_ID, shortcutId);
jsonObject.put(NUMBER, number);
+ jsonObject.put(CHANNEL_ID, channelId);
jsonObject.put(SOUND, sound);
jsonObject.put(COLOR, color);
jsonObject.put(GROUP, group);
- jsonObject.put(USER_INTERACTION, userInteraction);
+ jsonObject.put(GROUP_SUMMARY, groupSummary);
+ jsonObject.put(MESSAGE_ID, messageId);
jsonObject.put(PLAY_SOUND, playSound);
jsonObject.put(VIBRATE, vibrate);
jsonObject.put(VIBRATION, vibration);
jsonObject.put(ACTIONS, actions);
+ jsonObject.put(INVOKE_APP, invokeApp);
jsonObject.put(TAG, tag);
jsonObject.put(REPEAT_TYPE, repeatType);
jsonObject.put(REPEAT_TIME, repeatTime);
+ jsonObject.put(WHEN, when);
+ jsonObject.put(USES_CHRONOMETER, usesChronometer);
+ jsonObject.put(TIMEOUT_AFTER, timeoutAfter);
+ jsonObject.put(ONLY_ALERT_ONCE, onlyAlertOnce);
jsonObject.put(ONGOING, ongoing);
+ jsonObject.put(REPLY_BUTTON_TEXT, reply_button_text);
+ jsonObject.put(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text);
+ jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle);
+ jsonObject.put(IGNORE_IN_FOREGROUND, ignoreInForeground);
+ jsonObject.put(USER_INFO, userInfo);
} catch (JSONException e) {
Log.e(LOG_TAG, "Exception while converting RNPushNotificationAttributes to " +
"JSON. Returning an empty object", e);
@@ -242,24 +293,40 @@ public String toString() {
", fireDate=" + fireDate +
", title='" + title + '\'' +
", ticker='" + ticker + '\'' +
+ ", showWhen=" + showWhen +
", autoCancel=" + autoCancel +
", largeIcon='" + largeIcon + '\'' +
+ ", largeIconUrl='" + largeIconUrl + '\'' +
", smallIcon='" + smallIcon + '\'' +
", bigText='" + bigText + '\'' +
", subText='" + subText + '\'' +
+ ", bigPictureUrl='" + bigPictureUrl + '\'' +
+ ", shortcutId='" + shortcutId + '\'' +
", number='" + number + '\'' +
+ ", channelId='" + channelId + '\'' +
", sound='" + sound + '\'' +
", color='" + color + '\'' +
", group='" + group + '\'' +
- ", userInteraction=" + userInteraction +
+ ", groupSummary='" + groupSummary + '\'' +
+ ", messageId='" + messageId + '\'' +
", playSound=" + playSound +
", vibrate=" + vibrate +
", vibration=" + vibration +
", actions='" + actions + '\'' +
+ ", invokeApp=" + invokeApp +
", tag='" + tag + '\'' +
", repeatType='" + repeatType + '\'' +
", repeatTime=" + repeatTime +
+ ", when=" + when +
+ ", usesChronometer=" + usesChronometer +
+ ", timeoutAfter=" + timeoutAfter +
+ ", onlyAlertOnce=" + onlyAlertOnce +
", ongoing=" + ongoing +
+ ", reply_button_text=" + reply_button_text +
+ ", reply_placeholder_text=" + reply_placeholder_text +
+ ", allowWhileIdle=" + allowWhileIdle +
+ ", ignoreInForeground=" + ignoreInForeground +
+ ", userInfo=" + userInfo +
'}';
}
@@ -267,8 +334,31 @@ public String getId() {
return id;
}
+ public String getSound() {
+ return sound;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ public String getUserInfo() {
+ return userInfo;
+ }
+
+ public String getRepeatType() {
+ return repeatType;
+ }
+
public double getFireDate() {
return fireDate;
}
-
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java
index 82a575883..6552a87ec 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java
@@ -20,32 +20,30 @@ public class RNPushNotificationBootEventReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver loading scheduled notifications");
- if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
- SharedPreferences sharedPreferences = context.getSharedPreferences(RNPushNotificationHelper.PREFERENCES_KEY, Context.MODE_PRIVATE);
- Set ids = sharedPreferences.getAll().keySet();
-
- Application applicationContext = (Application) context.getApplicationContext();
- RNPushNotificationHelper rnPushNotificationHelper = new RNPushNotificationHelper(applicationContext);
-
- for (String id : ids) {
- try {
- String notificationAttributesJson = sharedPreferences.getString(id, null);
- if (notificationAttributesJson != null) {
- RNPushNotificationAttributes notificationAttributes = RNPushNotificationAttributes.fromJson(notificationAttributesJson);
-
- if (notificationAttributes.getFireDate() < System.currentTimeMillis()) {
- Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Showing notification for " +
- notificationAttributes.getId());
- rnPushNotificationHelper.sendToNotificationCentre(notificationAttributes.toBundle());
- } else {
- Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Scheduling notification for " +
- notificationAttributes.getId());
- rnPushNotificationHelper.sendNotificationScheduledCore(notificationAttributes.toBundle());
- }
+ SharedPreferences sharedPreferences = context.getSharedPreferences(RNPushNotificationHelper.PREFERENCES_KEY, Context.MODE_PRIVATE);
+ Set ids = sharedPreferences.getAll().keySet();
+
+ Application applicationContext = (Application) context.getApplicationContext();
+ RNPushNotificationHelper rnPushNotificationHelper = new RNPushNotificationHelper(applicationContext);
+
+ for (String id : ids) {
+ try {
+ String notificationAttributesJson = sharedPreferences.getString(id, null);
+ if (notificationAttributesJson != null) {
+ RNPushNotificationAttributes notificationAttributes = RNPushNotificationAttributes.fromJson(notificationAttributesJson);
+
+ if (notificationAttributes.getFireDate() < System.currentTimeMillis()) {
+ Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Showing notification for " +
+ notificationAttributes.getId());
+ rnPushNotificationHelper.sendToNotificationCentre(notificationAttributes.toBundle());
+ } else {
+ Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Scheduling notification for " +
+ notificationAttributes.getId());
+ rnPushNotificationHelper.sendNotificationScheduledCore(notificationAttributes.toBundle());
}
- } catch (Exception e) {
- Log.e(LOG_TAG, "Problem with boot receiver loading notification " + id, e);
}
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Problem with boot receiver loading notification " + id, e);
}
}
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java
index edba739ef..e17927753 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java
@@ -8,8 +8,9 @@
import android.util.Log;
class RNPushNotificationConfig {
- private static final String KEY_CHANNEL_NAME = "com.dieam.reactnativepushnotification.notification_channel_name";
- private static final String KEY_CHANNEL_DESCRIPTION = "com.dieam.reactnativepushnotification.notification_channel_description";
+ private static final String KEY_NOTIFICATION_FIREBASE_DEFAULT_CHANNEL_ID = "com.google.firebase.messaging.default_notification_channel_id";
+ private static final String KEY_NOTIFICATION_DEFAULT_CHANNEL_ID = "com.dieam.reactnativepushnotification.default_notification_channel_id";
+ private static final String KEY_NOTIFICATION_FOREGROUND = "com.dieam.reactnativepushnotification.notification_foreground";
private static final String KEY_NOTIFICATION_COLOR = "com.dieam.reactnativepushnotification.notification_color";
private static Bundle metadata;
@@ -29,24 +30,21 @@ public RNPushNotificationConfig(Context context) {
}
}
- public String getChannelName() {
+ private String getStringValue(String key, String defaultValue) {
try {
- return metadata.getString(KEY_CHANNEL_NAME);
- } catch (Exception e) {
- Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_NAME + " in manifest. Falling back to default");
- }
- // Default
- return "rn-push-notification-channel";
- }
- public String getChannelDescription() {
- try {
- return metadata.getString(KEY_CHANNEL_DESCRIPTION);
+ final String value = metadata.getString(key);
+
+ if (value != null && value.length() > 0) {
+ return value;
+ }
} catch (Exception e) {
- Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_DESCRIPTION + " in manifest. Falling back to default");
+ Log.w(RNPushNotification.LOG_TAG, "Unable to find " + key + " in manifest. Falling back to default");
}
+
// Default
- return "";
+ return defaultValue;
}
+
public int getNotificationColor() {
try {
int resourceId = metadata.getInt(KEY_NOTIFICATION_COLOR);
@@ -57,4 +55,26 @@ public int getNotificationColor() {
// Default
return -1;
}
+
+ public boolean getNotificationForeground() {
+ try {
+ return metadata.getBoolean(KEY_NOTIFICATION_FOREGROUND, false);
+ } catch (Exception e) {
+ Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_NOTIFICATION_FOREGROUND + " in manifest. Falling back to default");
+ }
+ // Default
+ return false;
+ }
+
+ public String getNotificationDefaultChannelId() {
+ try {
+ return getStringValue(KEY_NOTIFICATION_DEFAULT_CHANNEL_ID,
+ getStringValue(KEY_NOTIFICATION_FIREBASE_DEFAULT_CHANNEL_ID, "fcm_fallback_notification_channel")
+ );
+ } catch (Exception e) {
+ Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_NOTIFICATION_DEFAULT_CHANNEL_ID + " in manifest. Falling back to default");
+ }
+ // Default
+ return "fcm_fallback_notification_channel";
+ }
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java
index be6e85046..248ff0825 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java
@@ -1,6 +1,7 @@
package com.dieam.reactnativepushnotification.modules;
-
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.AlarmManager;
import android.app.Application;
import android.app.Notification;
@@ -15,37 +16,46 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
+import android.media.AudioAttributes;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import androidx.core.app.NotificationCompat;
+import android.service.notification.StatusBarNotification;
+import android.text.Spanned;
import android.util.Log;
+import androidx.core.app.RemoteInput;
+
+import androidx.annotation.RequiresApi;
+import androidx.core.app.NotificationCompat;
+import androidx.core.text.HtmlCompat;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
import org.json.JSONArray;
import org.json.JSONException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Map;
import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
import static com.dieam.reactnativepushnotification.modules.RNPushNotificationAttributes.fromJson;
+import static com.dieam.reactnativepushnotification.modules.RNPushNotification.KEY_TEXT_REPLY;
public class RNPushNotificationHelper {
public static final String PREFERENCES_KEY = "rn_push_notification";
private static final long DEFAULT_VIBRATION = 300L;
- private static final String NOTIFICATION_CHANNEL_ID = "rn-push-notification-channel-id";
private Context context;
private RNPushNotificationConfig config;
private final SharedPreferences scheduledNotificationsPersistence;
- private static final int ONE_MINUTE = 60 * 1000;
- private static final long ONE_HOUR = 60 * ONE_MINUTE;
- private static final long ONE_DAY = 24 * ONE_HOUR;
public RNPushNotificationHelper(Application context) {
this.context = context;
@@ -69,14 +79,44 @@ private AlarmManager getAlarmManager() {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
+ public void invokeApp(Bundle bundle) {
+ String packageName = context.getPackageName();
+ Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
+ String className = launchIntent.getComponent().getClassName();
+
+ try {
+ Class> activityClass = Class.forName(className);
+ Intent activityIntent = new Intent(context, activityClass);
+
+ if(bundle != null) {
+ activityIntent.putExtra("notification", bundle);
+ }
+
+ activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ context.startActivity(activityIntent);
+ } catch(Exception e) {
+ Log.e(LOG_TAG, "Class not found", e);
+ return;
+ }
+ }
+
private PendingIntent toScheduleNotificationIntent(Bundle bundle) {
- int notificationID = Integer.parseInt(bundle.getString("id"));
+ try {
+ int notificationID = Integer.parseInt(bundle.getString("id"));
- Intent notificationIntent = new Intent(context, RNPushNotificationPublisher.class);
- notificationIntent.putExtra(RNPushNotificationPublisher.NOTIFICATION_ID, notificationID);
- notificationIntent.putExtras(bundle);
+ Intent notificationIntent = new Intent(context, RNPushNotificationPublisher.class);
+ notificationIntent.putExtra(RNPushNotificationPublisher.NOTIFICATION_ID, notificationID);
+ notificationIntent.putExtras(bundle);
- return PendingIntent.getBroadcast(context, notificationID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT;
+
+ return PendingIntent.getBroadcast(context, notificationID, notificationIntent, flags);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Unable to parse Notification ID", e);
+ }
+
+ return null;
}
public void sendNotificationScheduled(Bundle bundle) {
@@ -109,7 +149,7 @@ public void sendNotificationScheduled(Bundle bundle) {
SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit();
editor.putString(id, notificationAttributes.toJson().toString());
- commit(editor);
+ editor.apply();
boolean isSaved = scheduledNotificationsPersistence.contains(id);
if (!isSaved) {
@@ -121,21 +161,43 @@ public void sendNotificationScheduled(Bundle bundle) {
public void sendNotificationScheduledCore(Bundle bundle) {
long fireDate = (long) bundle.getDouble("fireDate");
+ boolean allowWhileIdle = bundle.getBoolean("allowWhileIdle");
// If the fireDate is in past, this will fire immediately and show the
// notification to the user
PendingIntent pendingIntent = toScheduleNotificationIntent(bundle);
+ if (pendingIntent == null) {
+ return;
+ }
+
Log.d(LOG_TAG, String.format("Setting a notification with id %s at time %s",
bundle.getString("id"), Long.toString(fireDate)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- getAlarmManager().setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
+ if (allowWhileIdle && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ getAlarmManager().setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
+ } else {
+ getAlarmManager().setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
+ }
} else {
getAlarmManager().set(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
}
}
- public void sendToNotificationCentre(Bundle bundle) {
+
+ public void sendToNotificationCentre(final Bundle bundle) {
+ RNPushNotificationPicturesAggregator aggregator = new RNPushNotificationPicturesAggregator(new RNPushNotificationPicturesAggregator.Callback() {
+ public void call(Bitmap largeIconImage, Bitmap bigPictureImage, Bitmap bigLargeIconImage) {
+ sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage, bigLargeIconImage);
+ }
+ });
+
+ aggregator.setLargeIconUrl(context, bundle.getString("largeIconUrl"));
+ aggregator.setBigLargeIconUrl(context, bundle.getString("bigLargeIconUrl"));
+ aggregator.setBigPictureUrl(context, bundle.getString("bigPictureUrl"));
+ }
+
+ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconBitmap, Bitmap bigPictureBitmap, Bitmap bigLargeIconBitmap) {
try {
Class intentClass = getMainActivityClass();
if (intentClass == null) {
@@ -145,7 +207,7 @@ public void sendToNotificationCentre(Bundle bundle) {
if (bundle.getString("message") == null) {
// this happens when a 'data' notification is received - we do not synthesize a local notification in this case
- Log.d(LOG_TAG, "Cannot send to notification centre because there is no 'message' field in: " + bundle);
+ Log.d(LOG_TAG, "Ignore this message if you sent data-only notification. Cannot send to notification centre because there is no 'message' field in: " + bundle);
return;
}
@@ -168,7 +230,7 @@ public void sendToNotificationCentre(Bundle bundle) {
final String priorityString = bundle.getString("priority");
if (priorityString != null) {
- switch(priorityString.toLowerCase()) {
+ switch (priorityString.toLowerCase()) {
case "max":
priority = NotificationCompat.PRIORITY_MAX;
break;
@@ -193,7 +255,7 @@ public void sendToNotificationCentre(Bundle bundle) {
final String visibilityString = bundle.getString("visibility");
if (visibilityString != null) {
- switch(visibilityString.toLowerCase()) {
+ switch (visibilityString.toLowerCase()) {
case "private":
visibility = NotificationCompat.VISIBILITY_PRIVATE;
break;
@@ -207,42 +269,63 @@ public void sendToNotificationCentre(Bundle bundle) {
visibility = NotificationCompat.VISIBILITY_PRIVATE;
}
}
+
+ String channel_id = bundle.getString("channelId");
- NotificationCompat.Builder notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
+ if(channel_id == null) {
+ channel_id = this.config.getNotificationDefaultChannelId();
+ }
+
+ NotificationCompat.Builder notification = new NotificationCompat.Builder(context, channel_id)
.setContentTitle(title)
.setTicker(bundle.getString("ticker"))
.setVisibility(visibility)
.setPriority(priority)
- .setAutoCancel(bundle.getBoolean("autoCancel", true));
-
- String group = bundle.getString("group");
- if (group != null) {
- notification.setGroup(group);
+ .setAutoCancel(bundle.getBoolean("autoCancel", true))
+ .setOnlyAlertOnce(bundle.getBoolean("onlyAlertOnce", false));
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24 and higher
+ // Restore showing timestamp on Android 7+
+ // Source: https://developer.android.com/reference/android/app/Notification.Builder.html#setShowWhen(boolean)
+ boolean showWhen = bundle.getBoolean("showWhen", true);
+
+ notification.setShowWhen(showWhen);
}
- notification.setContentText(bundle.getString("message"));
-
- String largeIcon = bundle.getString("largeIcon");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher
+ // Changing Default mode of notification
+ notification.setDefaults(Notification.DEFAULT_LIGHTS);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { // API 20 and higher
+ String group = bundle.getString("group");
- String subText = bundle.getString("subText");
+ if (group != null) {
+ notification.setGroup(group);
+ }
- if (subText != null) {
- notification.setSubText(subText);
+ if (bundle.containsKey("groupSummary") || bundle.getBoolean("groupSummary")) {
+ notification.setGroupSummary(bundle.getBoolean("groupSummary"));
+ }
}
String numberString = bundle.getString("number");
+
if (numberString != null) {
notification.setNumber(Integer.parseInt(numberString));
}
- int smallIconResId;
- int largeIconResId;
+ // Small icon
+ int smallIconResId = 0;
String smallIcon = bundle.getString("smallIcon");
- if (smallIcon != null) {
- smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName);
- } else {
+ if (smallIcon != null && !smallIcon.isEmpty()) {
+ smallIconResId = res.getIdentifier(smallIcon, "drawable", packageName);
+ if (smallIconResId == 0) {
+ smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName);
+ }
+ } else if(smallIcon == null) {
smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
}
@@ -254,56 +337,106 @@ public void sendToNotificationCentre(Bundle bundle) {
}
}
- if (largeIcon != null) {
- largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName);
- } else {
- largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName);
+ notification.setSmallIcon(smallIconResId);
+
+ // Large icon
+ if(largeIconBitmap == null) {
+ int largeIconResId = 0;
+
+ String largeIcon = bundle.getString("largeIcon");
+
+ if (largeIcon != null && !largeIcon.isEmpty()) {
+ largeIconResId = res.getIdentifier(largeIcon, "drawable", packageName);
+ if (largeIconResId == 0) {
+ largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName);
+ }
+ } else if(largeIcon == null) {
+ largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName);
+ }
+
+ // Before Lolipop there was no large icon for notifications.
+ if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) {
+ largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId);
+ }
+ }
+
+ if (largeIconBitmap != null){
+ notification.setLargeIcon(largeIconBitmap);
}
- Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId);
+ String message = bundle.getString("message");
+
+ notification.setContentText(message);
+
+ String subText = bundle.getString("subText");
- if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) {
- notification.setLargeIcon(largeIconBitmap);
+ if (subText != null) {
+ notification.setSubText(subText);
}
- notification.setSmallIcon(smallIconResId);
- String bigText = bundle.getString("bigText");
+ NotificationCompat.Style style;
+
+ if(bigPictureBitmap != null) {
+
+ // Big large icon
+ if(bigLargeIconBitmap == null) {
+ int bigLargeIconResId = 0;
+
+ String bigLargeIcon = bundle.getString("bigLargeIcon");
- if (bigText == null) {
- bigText = bundle.getString("message");
+ if (bigLargeIcon != null && !bigLargeIcon.isEmpty()) {
+ bigLargeIconResId = res.getIdentifier(bigLargeIcon, "mipmap", packageName);
+ if (bigLargeIconResId != 0) {
+ bigLargeIconBitmap = BitmapFactory.decodeResource(res, bigLargeIconResId);
+ }
+ }
+ }
+
+ style = new NotificationCompat.BigPictureStyle()
+ .bigPicture(bigPictureBitmap)
+ .setBigContentTitle(title)
+ .setSummaryText(message)
+ .bigLargeIcon(bigLargeIconBitmap);
+ }
+ else {
+ String bigText = bundle.getString("bigText");
+
+ if (bigText == null) {
+ style = new NotificationCompat.BigTextStyle().bigText(message);
+ } else {
+ Spanned styledText = HtmlCompat.fromHtml(bigText, HtmlCompat.FROM_HTML_MODE_LEGACY);
+ style = new NotificationCompat.BigTextStyle().bigText(styledText);
+ }
}
- notification.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText));
+ notification.setStyle(style);
Intent intent = new Intent(context, intentClass);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ bundle.putBoolean("foreground", this.isApplicationInForeground());
bundle.putBoolean("userInteraction", true);
intent.putExtra("notification", bundle);
+ // Add message_id to intent so react-native-firebase/messaging can identify it
+ String messageId = bundle.getString("messageId");
+ if (messageId != null) {
+ intent.putExtra("message_id", messageId);
+ }
+
+ Uri soundUri = null;
+
if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) {
- Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
String soundName = bundle.getString("soundName");
- if (soundName != null) {
- if (!"default".equalsIgnoreCase(soundName)) {
- // sound name can be full filename, or just the resource name.
- // So the strings 'my_sound.mp3' AND 'my_sound' are accepted
- // The reason is to make the iOS and android javascript interfaces compatible
+ soundUri = getSoundUri(soundName);
- int resId;
- if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) {
- resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName());
- } else {
- soundName = soundName.substring(0, soundName.lastIndexOf('.'));
- resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName());
- }
-
- soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + resId);
- }
- }
notification.setSound(soundUri);
}
+ if (soundUri == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ notification.setSound(null);
+ }
+
if (bundle.containsKey("ongoing") || bundle.getBoolean("ongoing")) {
notification.setOngoing(bundle.getBoolean("ongoing"));
}
@@ -323,20 +456,48 @@ public void sendToNotificationCentre(Bundle bundle) {
int notificationID = Integer.parseInt(notificationIdString);
PendingIntent pendingIntent = PendingIntent.getActivity(context, notificationID, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager notificationManager = notificationManager();
- checkOrCreateChannel(notificationManager);
- notification.setContentIntent(pendingIntent);
+ long[] vibratePattern = new long[]{0};
if (!bundle.containsKey("vibrate") || bundle.getBoolean("vibrate")) {
long vibration = bundle.containsKey("vibration") ? (long) bundle.getDouble("vibration") : DEFAULT_VIBRATION;
if (vibration == 0)
vibration = DEFAULT_VIBRATION;
- notification.setVibrate(new long[]{0, vibration});
+
+ vibratePattern = new long[]{0, vibration};
+
+ notification.setVibrate(vibratePattern);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // Define the shortcutId
+ String shortcutId = bundle.getString("shortcutId");
+
+ if (shortcutId != null) {
+ notification.setShortcutId(shortcutId);
+ }
+
+ Long timeoutAfter = (long) bundle.getDouble("timeoutAfter");
+
+ if (timeoutAfter != null && timeoutAfter >= 0) {
+ notification.setTimeoutAfter(timeoutAfter);
+ }
+ }
+
+ Long when = (long) bundle.getDouble("when");
+
+ if (when != null && when >= 0) {
+ notification.setWhen(when);
}
+ notification.setUsesChronometer(bundle.getBoolean("usesChronometer", false));
+
+ notification.setChannelId(channel_id);
+ notification.setContentIntent(pendingIntent);
+
JSONArray actionsArray = null;
try {
actionsArray = bundle.getString("actions") != null ? new JSONArray(bundle.getString("actions")) : null;
@@ -358,18 +519,53 @@ public void sendToNotificationCentre(Bundle bundle) {
continue;
}
- Intent actionIntent = new Intent(context, intentClass);
+
+ Intent actionIntent = new Intent(context, RNPushNotificationActions.class);
+ actionIntent.setAction(packageName + ".ACTION_" + i);
+
actionIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- actionIntent.setAction(context.getPackageName() + "." + action);
// Add "action" for later identifying which button gets pressed.
bundle.putString("action", action);
actionIntent.putExtra("notification", bundle);
+ actionIntent.setPackage(packageName);
+ if (messageId != null) {
+ intent.putExtra("message_id", messageId);
+ }
+
+ int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT;
+
+ PendingIntent pendingActionIntent = PendingIntent.getBroadcast(context, notificationID, actionIntent, flags);
+
+ if(action.equals("ReplyInput")){
+ //Action with inline reply
+ if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH){
+ RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
+ .setLabel(bundle.getString("reply_placeholder_text"))
+ .build();
+ NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(
+ icon, bundle.getString("reply_button_text"), pendingActionIntent)
+ .addRemoteInput(remoteInput)
+ .setAllowGeneratedReplies(true)
+ .build();
- PendingIntent pendingActionIntent = PendingIntent.getActivity(context, notificationID, actionIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- notification.addAction(icon, action, pendingActionIntent);
+ notification.addAction(replyAction);
+ }
+ else{
+ // The notification will not have action
+ break;
+ }
+ }
+ else{
+ // Add "action" for later identifying which button gets pressed
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ notification.addAction(new NotificationCompat.Action.Builder(icon, action, pendingActionIntent).build());
+ } else {
+ notification.addAction(icon, action, pendingActionIntent);
+ }
+ }
}
+
}
// Remove the notification from the shared preferences once it has been shown
@@ -383,17 +579,19 @@ public void sendToNotificationCentre(Bundle bundle) {
if (scheduledNotificationsPersistence.getString(notificationIdString, null) != null) {
SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit();
editor.remove(notificationIdString);
- commit(editor);
+ editor.apply();
}
- Notification info = notification.build();
- info.defaults |= Notification.DEFAULT_LIGHTS;
+ if (!(this.isApplicationInForeground() && bundle.getBoolean("ignoreInForeground"))) {
+ Notification info = notification.build();
+ info.defaults |= Notification.DEFAULT_LIGHTS;
- if (bundle.containsKey("tag")) {
- String tag = bundle.getString("tag");
- notificationManager.notify(tag, notificationID, info);
- } else {
- notificationManager.notify(notificationID, info);
+ if (bundle.containsKey("tag")) {
+ String tag = bundle.getString("tag");
+ notificationManager.notify(tag, notificationID, info);
+ } else {
+ notificationManager.notify(notificationID, info);
+ }
}
// Can't use setRepeating for recurring notifications because setRepeating
@@ -427,44 +625,19 @@ private void scheduleNextNotificationIfRepeating(Bundle bundle) {
return;
}
- long newFireDate = 0;
-
- switch (repeatType) {
- case "time":
- newFireDate = fireDate + repeatTime;
- break;
- case "month":
- final Calendar fireDateCalendar = new GregorianCalendar();
- fireDateCalendar.setTime(new Date(fireDate));
- final int fireDay = fireDateCalendar.get(Calendar.DAY_OF_MONTH);
- final int fireMinute = fireDateCalendar.get(Calendar.MINUTE);
- final int fireHour = fireDateCalendar.get(Calendar.HOUR_OF_DAY);
-
- final Calendar nextEvent = new GregorianCalendar();
- nextEvent.setTime(new Date());
- final int currentMonth = nextEvent.get(Calendar.MONTH);
- int nextMonth = currentMonth < 11 ? (currentMonth + 1) : 0;
- nextEvent.set(Calendar.YEAR, nextEvent.get(Calendar.YEAR) + (nextMonth == 0 ? 1 : 0));
- nextEvent.set(Calendar.MONTH, nextMonth);
- final int maxDay = nextEvent.getActualMaximum(Calendar.DAY_OF_MONTH);
- nextEvent.set(Calendar.DAY_OF_MONTH, fireDay <= maxDay ? fireDay : maxDay);
- nextEvent.set(Calendar.HOUR_OF_DAY, fireHour);
- nextEvent.set(Calendar.MINUTE, fireMinute);
- nextEvent.set(Calendar.SECOND, 0);
- newFireDate = nextEvent.getTimeInMillis();
- break;
- case "week":
- newFireDate = fireDate + 7 * ONE_DAY;
- break;
- case "day":
- newFireDate = fireDate + ONE_DAY;
- break;
- case "hour":
- newFireDate = fireDate + ONE_HOUR;
- break;
- case "minute":
- newFireDate = fireDate + ONE_MINUTE;
- break;
+ long newFireDate;
+ if ("time".equals(repeatType)) {
+ newFireDate = fireDate + repeatTime;
+ } else {
+ int repeatField = getRepeatField(repeatType);
+
+ final Calendar nextEvent = Calendar.getInstance();
+ nextEvent.setTimeInMillis(fireDate);
+ // Limits repeat time increment to int instead of long
+ int increment = repeatTime > 0 ? (int) repeatTime : 1;
+ nextEvent.add(repeatField, increment);
+
+ newFireDate = nextEvent.getTimeInMillis();
}
// Sanity check, should never happen
@@ -477,6 +650,43 @@ private void scheduleNextNotificationIfRepeating(Bundle bundle) {
}
}
+ private int getRepeatField(String repeatType) {
+ switch (repeatType) {
+ case "month":
+ return Calendar.MONTH;
+ case "week":
+ return Calendar.WEEK_OF_YEAR;
+ case "hour":
+ return Calendar.HOUR;
+ case "minute":
+ return Calendar.MINUTE;
+ case "day":
+ default:
+ return Calendar.DATE;
+ }
+ }
+
+ private Uri getSoundUri(String soundName) {
+ if (soundName == null || "default".equalsIgnoreCase(soundName)) {
+ return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+ } else {
+
+ // sound name can be full filename, or just the resource name.
+ // So the strings 'my_sound.mp3' AND 'my_sound' are accepted
+ // The reason is to make the iOS and android javascript interfaces compatible
+
+ int resId;
+ if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) {
+ resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName());
+ } else {
+ soundName = soundName.substring(0, soundName.lastIndexOf('.'));
+ resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName());
+ }
+
+ return Uri.parse("android.resource://" + context.getPackageName() + "/" + resId);
+ }
+ }
+
public void clearNotifications() {
Log.i(LOG_TAG, "Clearing alerts from the notification centre");
@@ -484,50 +694,111 @@ public void clearNotifications() {
notificationManager.cancelAll();
}
- public void clearNotification(int notificationID) {
+ public void clearNotification(String tag, int notificationID) {
Log.i(LOG_TAG, "Clearing notification: " + notificationID);
NotificationManager notificationManager = notificationManager();
- notificationManager.cancel(notificationID);
+ if(tag != null) {
+ notificationManager.cancel(tag, notificationID);
+ } else {
+ notificationManager.cancel(notificationID);
+ }
}
- public void cancelAllScheduledNotifications() {
- Log.i(LOG_TAG, "Cancelling all notifications");
+ public void clearDeliveredNotifications(ReadableArray identifiers) {
+ NotificationManager notificationManager = notificationManager();
+ for (int index = 0; index < identifiers.size(); index++) {
+ String id = identifiers.getString(index);
+ Log.i(LOG_TAG, "Removing notification with id " + id);
+ notificationManager.cancel(Integer.parseInt(id));
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ public WritableArray getDeliveredNotifications() {
+ WritableArray result = Arguments.createArray();
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return result;
+ }
+
+ NotificationManager notificationManager = notificationManager();
+ StatusBarNotification delivered[] = notificationManager.getActiveNotifications();
+ Log.i(LOG_TAG, "Found " + delivered.length + " delivered notifications");
+ /*
+ * stay consistent to the return structure in
+ * https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications
+ * but there is no such thing as a 'userInfo'
+ */
+ for (StatusBarNotification notification : delivered) {
+ Notification original = notification.getNotification();
+ Bundle extras = original.extras;
+ WritableMap notif = Arguments.createMap();
+ notif.putString("identifier", "" + notification.getId());
+ notif.putString("title", extras.getString(Notification.EXTRA_TITLE));
+ notif.putString("body", extras.getString(Notification.EXTRA_TEXT));
+ notif.putString("tag", notification.getTag());
+ notif.putString("group", original.getGroup());
+ result.pushMap(notif);
+ }
+
+ return result;
- for (String id : scheduledNotificationsPersistence.getAll().keySet()) {
- cancelScheduledNotification(id);
- }
}
- public void cancelScheduledNotification(ReadableMap userInfo) {
- for (String id : scheduledNotificationsPersistence.getAll().keySet()) {
+ public WritableArray getScheduledLocalNotifications() {
+ WritableArray scheduled = Arguments.createArray();
+
+ Map scheduledNotifications = scheduledNotificationsPersistence.getAll();
+
+ for (Map.Entry entry : scheduledNotifications.entrySet()) {
try {
- String notificationAttributesJson = scheduledNotificationsPersistence.getString(id, null);
- if (notificationAttributesJson != null) {
- RNPushNotificationAttributes notificationAttributes = fromJson(notificationAttributesJson);
- if (notificationAttributes.matches(userInfo)) {
- cancelScheduledNotification(id);
- }
- }
+ RNPushNotificationAttributes notification = fromJson(entry.getValue().toString());
+ WritableMap notificationMap = Arguments.createMap();
+
+ notificationMap.putString("title", notification.getTitle());
+ notificationMap.putString("message", notification.getMessage());
+ notificationMap.putString("number", notification.getNumber());
+ notificationMap.putDouble("date", notification.getFireDate());
+ notificationMap.putString("id", notification.getId());
+ notificationMap.putString("repeatInterval", notification.getRepeatType());
+ notificationMap.putString("soundName", notification.getSound());
+ notificationMap.putString("data", notification.getUserInfo());
+
+ scheduled.pushMap(notificationMap);
} catch (JSONException e) {
- Log.w(LOG_TAG, "Problem dealing with scheduled notification " + id, e);
+ Log.e(LOG_TAG, e.getMessage());
}
}
+
+ return scheduled;
}
- private void cancelScheduledNotification(String notificationIDString) {
+ public void cancelAllScheduledNotifications() {
+ Log.i(LOG_TAG, "Cancelling all notifications");
+
+ for (String id : scheduledNotificationsPersistence.getAll().keySet()) {
+ cancelScheduledNotification(id);
+ }
+ }
+
+ public void cancelScheduledNotification(String notificationIDString) {
Log.i(LOG_TAG, "Cancelling notification: " + notificationIDString);
// remove it from the alarm manger schedule
Bundle b = new Bundle();
b.putString("id", notificationIDString);
- getAlarmManager().cancel(toScheduleNotificationIntent(b));
+ PendingIntent pendingIntent = toScheduleNotificationIntent(b);
+
+ if (pendingIntent != null) {
+ getAlarmManager().cancel(pendingIntent);
+ }
if (scheduledNotificationsPersistence.contains(notificationIDString)) {
// remove it from local storage
SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit();
editor.remove(notificationIDString);
- commit(editor);
+ editor.apply();
} else {
Log.w(LOG_TAG, "Unable to find notification " + notificationIDString);
}
@@ -535,70 +806,156 @@ private void cancelScheduledNotification(String notificationIDString) {
// removed it from the notification center
NotificationManager notificationManager = notificationManager();
- notificationManager.cancel(Integer.parseInt(notificationIDString));
+ try {
+ notificationManager.cancel(Integer.parseInt(notificationIDString));
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Unable to parse Notification ID " + notificationIDString, e);
+ }
}
private NotificationManager notificationManager() {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
- private static void commit(SharedPreferences.Editor editor) {
- if (Build.VERSION.SDK_INT < 9) {
- editor.commit();
- } else {
- editor.apply();
- }
+ public List listChannels() {
+ List channels = new ArrayList<>();
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ return channels;
+
+ NotificationManager manager = notificationManager();
+
+ if (manager == null)
+ return channels;
+
+ List listChannels = manager.getNotificationChannels();
+
+ for(NotificationChannel channel : listChannels) {
+ channels.add(channel.getId());
+ }
+
+ return channels;
+ }
+
+ public boolean channelBlocked(String channel_id) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ return false;
+
+ NotificationManager manager = notificationManager();
+
+ if (manager == null)
+ return false;
+
+ NotificationChannel channel = manager.getNotificationChannel(channel_id);
+
+ if(channel == null)
+ return false;
+
+ return NotificationManager.IMPORTANCE_NONE == channel.getImportance();
+ }
+
+ public boolean channelExists(String channel_id) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ return false;
+
+ NotificationManager manager = notificationManager();
+
+ if (manager == null)
+ return false;
+
+ NotificationChannel channel = manager.getNotificationChannel(channel_id);
+
+ return channel != null;
}
- private static boolean channelCreated = false;
- private void checkOrCreateChannel(NotificationManager manager) {
+ public void deleteChannel(String channel_id) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
return;
- if (channelCreated)
- return;
+
+ NotificationManager manager = notificationManager();
+
if (manager == null)
return;
- Bundle bundle = new Bundle();
-
- int importance = NotificationManager.IMPORTANCE_HIGH;
- final String importanceString = bundle.getString("importance");
-
- if (importanceString != null) {
- switch(importanceString.toLowerCase()) {
- case "default":
- importance = NotificationManager.IMPORTANCE_DEFAULT;
- break;
- case "max":
- importance = NotificationManager.IMPORTANCE_MAX;
- break;
- case "high":
- importance = NotificationManager.IMPORTANCE_HIGH;
- break;
- case "low":
- importance = NotificationManager.IMPORTANCE_LOW;
- break;
- case "min":
- importance = NotificationManager.IMPORTANCE_MIN;
- break;
- case "none":
- importance = NotificationManager.IMPORTANCE_NONE;
- break;
- case "unspecified":
- importance = NotificationManager.IMPORTANCE_UNSPECIFIED;
- break;
- default:
- importance = NotificationManager.IMPORTANCE_HIGH;
+ manager.deleteNotificationChannel(channel_id);
+ }
+
+ private boolean checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ return false;
+ if (manager == null)
+ return false;
+
+ NotificationChannel channel = manager.getNotificationChannel(channel_id);
+
+ if (
+ channel == null && channel_name != null && channel_description != null ||
+ channel != null &&
+ (
+ channel_name != null && !channel_name.equals(channel.getName()) ||
+ channel_description != null && !channel_description.equals(channel.getDescription())
+ )
+ ) {
+ // If channel doesn't exist create a new one.
+ // If channel name or description is updated then update the existing channel.
+ channel = new NotificationChannel(channel_id, channel_name, importance);
+
+ channel.setDescription(channel_description);
+ channel.enableLights(true);
+ channel.enableVibration(vibratePattern != null);
+ channel.setVibrationPattern(vibratePattern);
+
+ if (soundUri != null) {
+ AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .build();
+
+ channel.setSound(soundUri, audioAttributes);
+ } else {
+ channel.setSound(null, null);
}
+
+ manager.createNotificationChannel(channel);
+
+ return true;
}
- NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, this.config.getChannelName() != null ? this.config.getChannelName() : "rn-push-notification-channel", importance);
+ return false;
+ }
+
+ public boolean createChannel(ReadableMap channelInfo) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ return false;
+
+ String channelId = channelInfo.getString("channelId");
+ String channelName = channelInfo.getString("channelName");
+ String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : "";
+ boolean playSound = !channelInfo.hasKey("playSound") || channelInfo.getBoolean("playSound");
+ String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default";
+ int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4;
+ boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate");
+ long[] vibratePattern = vibrate ? new long[] { 0, DEFAULT_VIBRATION } : null;
- channel.setDescription(this.config.getChannelDescription());
- channel.enableLights(true);
- channel.enableVibration(true);
+ NotificationManager manager = notificationManager();
- manager.createNotificationChannel(channel);
- channelCreated = true;
+ Uri soundUri = playSound ? getSoundUri(soundName) : null;
+
+ return checkOrCreateChannel(manager, channelId, channelName, channelDescription, soundUri, importance, vibratePattern);
+ }
+
+ public boolean isApplicationInForeground() {
+ ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List processInfos = activityManager.getRunningAppProcesses();
+ if (processInfos != null) {
+ for (RunningAppProcessInfo processInfo : processInfos) {
+ if (processInfo.processName.equals(context.getPackageName())
+ && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+ && processInfo.pkgList.length > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
}
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java
index c6721d7fc..350758e57 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java
@@ -4,7 +4,7 @@
import android.os.Bundle;
import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -18,9 +18,9 @@
*/
public class RNPushNotificationJsDelivery {
- private ReactApplicationContext mReactContext;
+ private ReactContext mReactContext;
- public RNPushNotificationJsDelivery(ReactApplicationContext reactContext) {
+ public RNPushNotificationJsDelivery(ReactContext reactContext) {
mReactContext = reactContext;
}
@@ -67,7 +67,7 @@ String convertJSON(Bundle bundle) {
}
// a Bundle is not a map, so we have to convert it explicitly
- JSONObject convertJSONObject(Bundle bundle) throws JSONException {
+ private JSONObject convertJSONObject(Bundle bundle) throws JSONException {
JSONObject json = new JSONObject();
Set keys = bundle.keySet();
for (String key : keys) {
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java
index 40fec92d9..ca78c0363 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java
@@ -1,94 +1,58 @@
package com.dieam.reactnativepushnotification.modules;
-import java.util.Map;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.Application;
-import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
-import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
-
-import org.json.JSONObject;
-
-import java.util.List;
-import java.util.Random;
+import com.facebook.react.bridge.WritableMap;
import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
public class RNPushNotificationListenerService extends FirebaseMessagingService {
- @Override
- public void onMessageReceived(RemoteMessage message) {
- String from = message.getFrom();
- RemoteMessage.Notification remoteNotification = message.getNotification();
+ private RNReceivedMessageHandler mMessageReceivedHandler;
+ private FirebaseMessagingService mFirebaseServiceDelegate;
- final Bundle bundle = new Bundle();
- // Putting it from remoteNotification first so it can be overriden if message
- // data has it
- if (remoteNotification != null) {
- // ^ It's null when message is from GCM
- bundle.putString("title", remoteNotification.getTitle());
- bundle.putString("message", remoteNotification.getBody());
- }
-
- for(Map.Entry entry : message.getData().entrySet()) {
- bundle.putString(entry.getKey(), entry.getValue());
- }
- JSONObject data = getPushData(bundle.getString("data"));
- // Copy `twi_body` to `message` to support Twilio
- if (bundle.containsKey("twi_body")) {
- bundle.putString("message", bundle.getString("twi_body"));
- }
-
- if (data != null) {
- if (!bundle.containsKey("message")) {
- bundle.putString("message", data.optString("alert", null));
- }
- if (!bundle.containsKey("title")) {
- bundle.putString("title", data.optString("title", null));
- }
- if (!bundle.containsKey("sound")) {
- bundle.putString("soundName", data.optString("sound", null));
- }
- if (!bundle.containsKey("color")) {
- bundle.putString("color", data.optString("color", null));
- }
+ public RNPushNotificationListenerService() {
+ super();
+ this.mMessageReceivedHandler = new RNReceivedMessageHandler(this);
+ }
- final int badge = data.optInt("badge", -1);
- if (badge >= 0) {
- ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(this, badge);
- }
- }
+ public RNPushNotificationListenerService(FirebaseMessagingService delegate) {
+ super();
+ this.mFirebaseServiceDelegate = delegate;
+ this.mMessageReceivedHandler = new RNReceivedMessageHandler(delegate);
+ }
- Log.v(LOG_TAG, "onMessageReceived: " + bundle);
+ @Override
+ public void onNewToken(String token) {
+ final String deviceToken = token;
+ final FirebaseMessagingService serviceRef = (this.mFirebaseServiceDelegate == null) ? this : this.mFirebaseServiceDelegate;
+ Log.d(LOG_TAG, "Refreshed token: " + deviceToken);
- // We need to run this on the main thread, as the React code assumes that is true.
- // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers:
- // "Can't create handler inside thread that has not called Looper.prepare()"
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
// Construct and load our normal React JS code bundle
- ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager();
+ final ReactInstanceManager mReactInstanceManager = ((ReactApplication)serviceRef.getApplication()).getReactNativeHost().getReactInstanceManager();
ReactContext context = mReactInstanceManager.getCurrentReactContext();
// If it's constructed, send a notification
if (context != null) {
- handleRemotePushNotification((ReactApplicationContext) context, bundle);
+ handleNewToken((ReactApplicationContext) context, deviceToken);
} else {
// Otherwise wait for construction, then send the notification
mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
public void onReactContextInitialized(ReactContext context) {
- handleRemotePushNotification((ReactApplicationContext) context, bundle);
+ handleNewToken((ReactApplicationContext) context, deviceToken);
+ mReactInstanceManager.removeReactInstanceEventListener(this);
}
});
if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
@@ -100,55 +64,16 @@ public void onReactContextInitialized(ReactContext context) {
});
}
- private JSONObject getPushData(String dataString) {
- try {
- return new JSONObject(dataString);
- } catch (Exception e) {
- return null;
- }
- }
-
- private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) {
-
- // If notification ID is not provided by the user for push notification, generate one at random
- if (bundle.getString("id") == null) {
- Random randomNumberGenerator = new Random(System.currentTimeMillis());
- bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt()));
- }
-
- Boolean isForeground = isApplicationInForeground();
-
+ private void handleNewToken(ReactApplicationContext context, String token) {
RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context);
- bundle.putBoolean("foreground", isForeground);
- bundle.putBoolean("userInteraction", false);
- jsDelivery.notifyNotification(bundle);
-
- // If contentAvailable is set to true, then send out a remote fetch event
- if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) {
- jsDelivery.notifyRemoteFetch(bundle);
- }
-
- Log.v(LOG_TAG, "sendNotification: " + bundle);
- Application applicationContext = (Application) context.getApplicationContext();
- RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext);
- pushNotificationHelper.sendToNotificationCentre(bundle);
+ WritableMap params = Arguments.createMap();
+ params.putString("deviceToken", token);
+ jsDelivery.sendEvent("remoteNotificationsRegistered", params);
}
- private boolean isApplicationInForeground() {
- ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
- List processInfos = activityManager.getRunningAppProcesses();
- if (processInfos != null) {
- for (RunningAppProcessInfo processInfo : processInfos) {
- if (processInfo.processName.equals(getApplication().getPackageName())) {
- if (processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
- for (String d : processInfo.pkgList) {
- return true;
- }
- }
- }
- }
- }
- return false;
+ @Override
+ public void onMessageReceived(RemoteMessage message) {
+ mMessageReceivedHandler.handleReceivedMessage(message);
}
}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerServiceGcm.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerServiceGcm.java
deleted file mode 100644
index 37bb0f45f..000000000
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerServiceGcm.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.dieam.reactnativepushnotification.modules;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.Application;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-
-import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper;
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
-import com.google.android.gms.gcm.GcmListenerService;
-
-import org.json.JSONObject;
-
-import java.util.List;
-import java.util.Random;
-
-import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
-
-public class RNPushNotificationListenerServiceGcm extends GcmListenerService {
-
- @Override
- public void onMessageReceived(String from, final Bundle bundle) {
- JSONObject data = getPushData(bundle.getString("data"));
- // Copy `twi_body` to `message` to support Twilio
- if (bundle.containsKey("twi_body")) {
- bundle.putString("message", bundle.getString("twi_body"));
- }
-
- if (data != null) {
- if (!bundle.containsKey("message")) {
- bundle.putString("message", data.optString("alert", null));
- }
- if (!bundle.containsKey("title")) {
- bundle.putString("title", data.optString("title", null));
- }
- if (!bundle.containsKey("sound")) {
- bundle.putString("soundName", data.optString("sound", null));
- }
- if (!bundle.containsKey("color")) {
- bundle.putString("color", data.optString("color", null));
- }
-
- final int badge = data.optInt("badge", -1);
- if (badge >= 0) {
- ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(this, badge);
- }
- }
-
- Log.v(LOG_TAG, "onMessageReceived: " + bundle);
-
- // We need to run this on the main thread, as the React code assumes that is true.
- // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers:
- // "Can't create handler inside thread that has not called Looper.prepare()"
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- public void run() {
- // Construct and load our normal React JS code bundle
- ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager();
- ReactContext context = mReactInstanceManager.getCurrentReactContext();
- // If it's constructed, send a notification
- if (context != null) {
- handleRemotePushNotification((ReactApplicationContext) context, bundle);
- } else {
- // Otherwise wait for construction, then send the notification
- mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
- public void onReactContextInitialized(ReactContext context) {
- handleRemotePushNotification((ReactApplicationContext) context, bundle);
- }
- });
- if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
- // Construct it in the background
- mReactInstanceManager.createReactContextInBackground();
- }
- }
- }
- });
- }
-
- private JSONObject getPushData(String dataString) {
- try {
- return new JSONObject(dataString);
- } catch (Exception e) {
- return null;
- }
- }
-
- private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) {
-
- // If notification ID is not provided by the user for push notification, generate one at random
- if (bundle.getString("id") == null) {
- Random randomNumberGenerator = new Random(System.currentTimeMillis());
- bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt()));
- }
-
- Boolean isForeground = isApplicationInForeground();
-
- RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context);
- bundle.putBoolean("foreground", isForeground);
- bundle.putBoolean("userInteraction", false);
- jsDelivery.notifyNotification(bundle);
-
- // If contentAvailable is set to true, then send out a remote fetch event
- if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) {
- jsDelivery.notifyRemoteFetch(bundle);
- }
-
- Log.v(LOG_TAG, "sendNotification: " + bundle);
-
- if (!isForeground) {
- Application applicationContext = (Application) context.getApplicationContext();
- RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext);
- pushNotificationHelper.sendToNotificationCentre(bundle);
- }
- }
-
- private boolean isApplicationInForeground() {
- ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
- List processInfos = activityManager.getRunningAppProcesses();
- if (processInfos != null) {
- for (RunningAppProcessInfo processInfo : processInfos) {
- if (processInfo.processName.equals(getApplication().getPackageName())) {
- if (processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
- for (String d : processInfo.pkgList) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java
new file mode 100644
index 000000000..733bcbe44
--- /dev/null
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java
@@ -0,0 +1,173 @@
+package com.dieam.reactnativepushnotification.modules;
+
+import androidx.annotation.Nullable;
+import com.facebook.common.executors.CallerThreadExecutor;
+import com.facebook.common.references.CloseableReference;
+import com.facebook.datasource.DataSource;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.imagepipeline.common.Priority;
+import com.facebook.imagepipeline.core.ImagePipeline;
+import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
+import com.facebook.imagepipeline.image.CloseableImage;
+import com.facebook.imagepipeline.request.ImageRequest;
+import com.facebook.imagepipeline.request.ImageRequestBuilder;
+
+import android.util.Log;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
+
+public class RNPushNotificationPicturesAggregator {
+ interface Callback {
+ public void call(Bitmap largeIconImage, Bitmap bigPictureImage, Bitmap bigLargeIconImage);
+ }
+
+ private AtomicInteger count = new AtomicInteger(0);
+
+ private Bitmap largeIconImage;
+ private Bitmap bigPictureImage;
+ private Bitmap bigLargeIconImage;
+
+ private Callback callback;
+
+ public RNPushNotificationPicturesAggregator(Callback callback) {
+ this.callback = callback;
+ }
+
+ public void setBigPicture(Bitmap bitmap) {
+ this.bigPictureImage = bitmap;
+ this.finished();
+ }
+
+ public void setBigPictureUrl(Context context, String url) {
+ if(null == url) {
+ this.setBigPicture(null);
+ return;
+ }
+
+ Uri uri = null;
+
+ try {
+ uri = Uri.parse(url);
+ } catch(Exception ex) {
+ Log.e(LOG_TAG, "Failed to parse bigPictureUrl", ex);
+ this.setBigPicture(null);
+ return;
+ }
+
+ final RNPushNotificationPicturesAggregator aggregator = this;
+
+ this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() {
+ @Override
+ public void onNewResultImpl(@Nullable Bitmap bitmap) {
+ aggregator.setBigPicture(bitmap);
+ }
+
+ @Override
+ public void onFailureImpl(DataSource dataSource) {
+ aggregator.setBigPicture(null);
+ }
+ });
+ }
+
+ public void setLargeIcon(Bitmap bitmap) {
+ this.largeIconImage = bitmap;
+ this.finished();
+ }
+
+ public void setLargeIconUrl(Context context, String url) {
+ if(null == url) {
+ this.setLargeIcon(null);
+ return;
+ }
+
+ Uri uri = null;
+
+ try {
+ uri = Uri.parse(url);
+ } catch(Exception ex) {
+ Log.e(LOG_TAG, "Failed to parse largeIconUrl", ex);
+ this.setLargeIcon(null);
+ return;
+ }
+
+ final RNPushNotificationPicturesAggregator aggregator = this;
+
+ this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() {
+ @Override
+ public void onNewResultImpl(@Nullable Bitmap bitmap) {
+ aggregator.setLargeIcon(bitmap);
+ }
+
+ @Override
+ public void onFailureImpl(DataSource dataSource) {
+ aggregator.setLargeIcon(null);
+ }
+ });
+ }
+
+ public void setBigLargeIcon(Bitmap bitmap) {
+ this.bigLargeIconImage = bitmap;
+ this.finished();
+ }
+
+ public void setBigLargeIconUrl(Context context, String url) {
+ if(null == url) {
+ this.setBigLargeIcon(null);
+ return;
+ }
+
+ Uri uri = null;
+
+ try {
+ uri = Uri.parse(url);
+ } catch(Exception ex) {
+ Log.e(LOG_TAG, "Failed to parse bigLargeIconUrl", ex);
+ this.setBigLargeIcon(null);
+ return;
+ }
+
+ final RNPushNotificationPicturesAggregator aggregator = this;
+
+ this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() {
+ @Override
+ public void onNewResultImpl(@Nullable Bitmap bitmap) {
+ aggregator.setBigLargeIcon(bitmap);
+ }
+
+ @Override
+ public void onFailureImpl(DataSource dataSource) {
+ aggregator.setBigLargeIcon(null);
+ }
+ });
+ }
+
+ private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber subscriber) {
+ ImageRequest imageRequest = ImageRequestBuilder
+ .newBuilderWithSource(uri)
+ .setRequestPriority(Priority.HIGH)
+ .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
+ .build();
+
+ if(!Fresco.hasBeenInitialized()) {
+ Fresco.initialize(context);
+ }
+
+ DataSource> dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context);
+
+ dataSource.subscribe(subscriber, CallerThreadExecutor.getInstance());
+ }
+
+ private void finished() {
+ synchronized(this.count) {
+ int val = this.count.incrementAndGet();
+
+ if(val >= 3 && this.callback != null) {
+ this.callback.call(this.largeIconImage, this.bigPictureImage, this.bigLargeIconImage);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java
index 8f75f91ba..c779f5fb2 100644
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java
@@ -4,23 +4,44 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.util.Log;
+import java.util.List;
+import java.security.SecureRandom;
+
import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
public class RNPushNotificationPublisher extends BroadcastReceiver {
final static String NOTIFICATION_ID = "notificationId";
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(final Context context, Intent intent) {
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
long currentTime = System.currentTimeMillis();
Log.i(LOG_TAG, "NotificationPublisher: Prepare To Publish: " + id + ", Now Time: " + currentTime);
+ final Bundle bundle = intent.getExtras();
+
+ Log.v(LOG_TAG, "onMessageReceived: " + bundle);
+
+ handleLocalNotification(context, bundle);
+ }
+
+ private void handleLocalNotification(Context context, Bundle bundle) {
+
+ // If notification ID is not provided by the user for push notification, generate one at random
+ if (bundle.getString("id") == null) {
+ SecureRandom randomNumberGenerator = new SecureRandom();
+ bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt()));
+ }
+
Application applicationContext = (Application) context.getApplicationContext();
+ RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext);
+
+ Log.v(LOG_TAG, "sendNotification: " + bundle);
- new RNPushNotificationHelper(applicationContext)
- .sendToNotificationCentre(intent.getExtras());
+ pushNotificationHelper.sendToNotificationCentre(bundle);
}
-}
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java
deleted file mode 100644
index b962f5438..000000000
--- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.dieam.reactnativepushnotification.modules;
-
-import android.app.IntentService;
-import android.content.Intent;
-import android.util.Log;
-
-import com.google.android.gms.gcm.GoogleCloudMessaging;
-import com.google.android.gms.iid.InstanceID;
-
-import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
-
-public class RNPushNotificationRegistrationService extends IntentService {
-
- private static final String TAG = "RNPushNotification";
-
- public RNPushNotificationRegistrationService() {
- super(TAG);
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- try {
- String SenderID = intent.getStringExtra("senderID");
- InstanceID instanceID = InstanceID.getInstance(this);
- String token = instanceID.getToken(SenderID,
- GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
- sendRegistrationToken(token);
- } catch (Exception e) {
- Log.e(LOG_TAG, TAG + " failed to process intent " + intent, e);
- }
- }
-
- private void sendRegistrationToken(String token) {
- Intent intent = new Intent(this.getPackageName() + ".RNPushNotificationRegisteredToken");
- intent.putExtra("token", token);
- sendBroadcast(intent);
- }
-}
diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java
new file mode 100644
index 000000000..721ca40cc
--- /dev/null
+++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java
@@ -0,0 +1,215 @@
+package com.dieam.reactnativepushnotification.modules;
+
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.Application;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.content.Context;
+import android.util.Log;
+import android.net.Uri;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+
+import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper;
+import com.facebook.react.ReactApplication;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+
+import org.json.JSONObject;
+
+import java.util.Map;
+import java.util.List;
+import java.security.SecureRandom;
+
+import static android.content.Context.ACTIVITY_SERVICE;
+import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG;
+
+public class RNReceivedMessageHandler {
+ private FirebaseMessagingService mFirebaseMessagingService;
+
+ public RNReceivedMessageHandler(@NonNull FirebaseMessagingService service) {
+ this.mFirebaseMessagingService = service;
+ }
+
+ public void handleReceivedMessage(RemoteMessage message) {
+ String from = message.getFrom();
+ RemoteMessage.Notification remoteNotification = message.getNotification();
+ final Bundle bundle = new Bundle();
+ // Putting it from remoteNotification first so it can be overriden if message
+ // data has it
+ if (remoteNotification != null) {
+ // ^ It's null when message is from GCM
+ RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication());
+
+ String title = getLocalizedString(remoteNotification.getTitle(), remoteNotification.getTitleLocalizationKey(), remoteNotification.getTitleLocalizationArgs());
+ String body = getLocalizedString(remoteNotification.getBody(), remoteNotification.getBodyLocalizationKey(), remoteNotification.getBodyLocalizationArgs());
+
+ bundle.putString("title", title);
+ bundle.putString("message", body);
+ bundle.putString("sound", remoteNotification.getSound());
+ bundle.putString("color", remoteNotification.getColor());
+ bundle.putString("tag", remoteNotification.getTag());
+
+ if(remoteNotification.getIcon() != null) {
+ bundle.putString("smallIcon", remoteNotification.getIcon());
+ } else {
+ bundle.putString("smallIcon", "ic_notification");
+ }
+
+ if(remoteNotification.getChannelId() != null) {
+ bundle.putString("channelId", remoteNotification.getChannelId());
+ }
+ else {
+ bundle.putString("channelId", config.getNotificationDefaultChannelId());
+ }
+
+ Integer visibilty = remoteNotification.getVisibility();
+ String visibilityString = "private";
+
+ if (visibilty != null) {
+ switch (visibilty) {
+ case NotificationCompat.VISIBILITY_PUBLIC:
+ visibilityString = "public";
+ break;
+ case NotificationCompat.VISIBILITY_SECRET:
+ visibilityString = "secret";
+ break;
+ }
+ }
+
+ bundle.putString("visibility", visibilityString);
+
+ Integer priority = remoteNotification.getNotificationPriority();
+ String priorityString = "high";
+
+ if (priority != null) {
+ switch (priority) {
+ case NotificationCompat.PRIORITY_MAX:
+ priorityString = "max";
+ break;
+ case NotificationCompat.PRIORITY_LOW:
+ priorityString = "low";
+ break;
+ case NotificationCompat.PRIORITY_MIN:
+ priorityString = "min";
+ break;
+ case NotificationCompat.PRIORITY_DEFAULT:
+ priorityString = "default";
+ break;
+ }
+ }
+
+ bundle.putString("priority", priorityString);
+
+ Uri uri = remoteNotification.getImageUrl();
+
+ if(uri != null) {
+ String imageUrl = uri.toString();
+
+ bundle.putString("bigPictureUrl", imageUrl);
+ bundle.putString("largeIconUrl", imageUrl);
+ }
+ }
+
+ Bundle dataBundle = new Bundle();
+ Map notificationData = message.getData();
+
+ for(Map.Entry entry : notificationData.entrySet()) {
+ dataBundle.putString(entry.getKey(), entry.getValue());
+ }
+
+ bundle.putParcelable("data", dataBundle);
+
+ Log.v(LOG_TAG, "onMessageReceived: " + bundle);
+
+ // We need to run this on the main thread, as the React code assumes that is true.
+ // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers:
+ // "Can't create handler inside thread that has not called Looper.prepare()"
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ public void run() {
+ // Construct and load our normal React JS code bundle
+ final ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager();
+ ReactContext context = mReactInstanceManager.getCurrentReactContext();
+ // If it's constructed, send a notificationre
+ if (context != null) {
+ handleRemotePushNotification((ReactApplicationContext) context, bundle);
+ } else {
+ // Otherwise wait for construction, then send the notification
+ mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
+ public void onReactContextInitialized(ReactContext context) {
+ handleRemotePushNotification((ReactApplicationContext) context, bundle);
+ mReactInstanceManager.removeReactInstanceEventListener(this);
+ }
+ });
+ if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
+ // Construct it in the background
+ mReactInstanceManager.createReactContextInBackground();
+ }
+ }
+ }
+ });
+ }
+
+ private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) {
+
+ // If notification ID is not provided by the user for push notification, generate one at random
+ if (bundle.getString("id") == null) {
+ SecureRandom randomNumberGenerator = new SecureRandom();
+ bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt()));
+ }
+
+ Application applicationContext = (Application) context.getApplicationContext();
+
+ RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication());
+ RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext);
+
+ boolean isForeground = pushNotificationHelper.isApplicationInForeground();
+
+ RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context);
+ bundle.putBoolean("foreground", isForeground);
+ bundle.putBoolean("userInteraction", false);
+ jsDelivery.notifyNotification(bundle);
+
+ // If contentAvailable is set to true, then send out a remote fetch event
+ if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) {
+ jsDelivery.notifyRemoteFetch(bundle);
+ }
+
+ if (config.getNotificationForeground() || !isForeground) {
+ Log.v(LOG_TAG, "sendNotification: " + bundle);
+
+ pushNotificationHelper.sendToNotificationCentre(bundle);
+ }
+ }
+
+ private String getLocalizedString(String text, String locKey, String[] locArgs) {
+ if(text != null) {
+ return text;
+ }
+
+ Context context = mFirebaseMessagingService.getApplicationContext();
+ String packageName = context.getPackageName();
+
+ String result = null;
+
+ if (locKey != null) {
+ int id = context.getResources().getIdentifier(locKey, "string", packageName);
+ if (id != 0) {
+ if (locArgs != null) {
+ result = context.getResources().getString(id, (Object[]) locArgs);
+ } else {
+ result = context.getResources().getString(id);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/component/index.android.js b/component/index.android.js
index d3d2758fc..0a609cbf9 100644
--- a/component/index.android.js
+++ b/component/index.android.js
@@ -1,18 +1,16 @@
'use strict';
-var {
- NativeModules,
- DeviceEventEmitter,
-} = require('react-native');
+import { NativeModules, DeviceEventEmitter } from "react-native";
-var RNPushNotification = NativeModules.RNPushNotification;
-var _notifHandlers = new Map();
+let RNPushNotification = NativeModules.ReactNativePushNotification;
+let _notifHandlers = new Map();
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
+var NOTIF_ACTION_EVENT = 'notificationActionReceived';
var REMOTE_FETCH_EVENT = 'remoteFetch';
-var NotificationsComponent = function() {
+let NotificationsComponent = function() {
};
@@ -26,57 +24,59 @@ NotificationsComponent.prototype.getInitialNotification = function () {
});
};
-NotificationsComponent.prototype.requestPermissions = function(senderID: string) {
- RNPushNotification.requestPermissions(senderID);
+NotificationsComponent.prototype.requestPermissions = function() {
+ RNPushNotification.requestPermissions();
};
-NotificationsComponent.prototype.subscribeToTopic = function(topic: string) {
+NotificationsComponent.prototype.subscribeToTopic = function(topic) {
RNPushNotification.subscribeToTopic(topic);
};
-NotificationsComponent.prototype.cancelLocalNotifications = function(details: Object) {
- RNPushNotification.cancelLocalNotifications(details);
+NotificationsComponent.prototype.unsubscribeFromTopic = function(topic) {
+ RNPushNotification.unsubscribeFromTopic(topic);
};
-NotificationsComponent.prototype.clearLocalNotification = function(details: Object) {
- RNPushNotification.clearLocalNotification(details);
+NotificationsComponent.prototype.cancelLocalNotification = function(details) {
+ RNPushNotification.cancelLocalNotification(details);
+};
+
+NotificationsComponent.prototype.clearLocalNotification = function(details, tag) {
+ RNPushNotification.clearLocalNotification(details, tag);
};
NotificationsComponent.prototype.cancelAllLocalNotifications = function() {
RNPushNotification.cancelAllLocalNotifications();
};
-NotificationsComponent.prototype.presentLocalNotification = function(details: Object) {
+NotificationsComponent.prototype.presentLocalNotification = function(details) {
RNPushNotification.presentLocalNotification(details);
};
-NotificationsComponent.prototype.scheduleLocalNotification = function(details: Object) {
+NotificationsComponent.prototype.scheduleLocalNotification = function(details) {
RNPushNotification.scheduleLocalNotification(details);
};
-NotificationsComponent.prototype.setApplicationIconBadgeNumber = function(number: number) {
+NotificationsComponent.prototype.setApplicationIconBadgeNumber = function(number) {
if (!RNPushNotification.setApplicationIconBadgeNumber) {
return;
}
RNPushNotification.setApplicationIconBadgeNumber(number);
};
-NotificationsComponent.prototype.abandonPermissions = function() {
- /* Void */
-};
-
-NotificationsComponent.prototype.checkPermissions = function(callback: Function) {
+NotificationsComponent.prototype.checkPermissions = function(callback) {
RNPushNotification.checkPermissions().then(alert => callback({ alert }));
};
-NotificationsComponent.prototype.addEventListener = function(type: string, handler: Function) {
- var listener;
+NotificationsComponent.prototype.addEventListener = function(type, handler) {
+ let listener;
if (type === 'notification') {
listener = DeviceEventEmitter.addListener(
DEVICE_NOTIF_EVENT,
function(notifData) {
- var data = JSON.parse(notifData.dataJSON);
- handler(data);
+ if (notifData && notifData.dataJSON) {
+ let data = JSON.parse(notifData.dataJSON);
+ handler(data);
+ }
}
);
} else if (type === 'register') {
@@ -90,17 +90,29 @@ NotificationsComponent.prototype.addEventListener = function(type: string, handl
listener = DeviceEventEmitter.addListener(
REMOTE_FETCH_EVENT,
function(notifData) {
- var notificationData = JSON.parse(notifData.dataJSON)
- handler(notificationData);
+ if (notifData && notifData.dataJSON) {
+ let notificationData = JSON.parse(notifData.dataJSON)
+ handler(notificationData);
+ }
}
);
- }
+ } else if (type === 'action') {
+ listener = DeviceEventEmitter.addListener(
+ NOTIF_ACTION_EVENT,
+ function(actionData) {
+ if (actionData && actionData.dataJSON) {
+ var action = JSON.parse(actionData.dataJSON)
+ handler(action);
+ }
+ }
+ );
+ }
_notifHandlers.set(type, listener);
};
-NotificationsComponent.prototype.removeEventListener = function(type: string, handler: Function) {
- var listener = _notifHandlers.get(type);
+NotificationsComponent.prototype.removeEventListener = function(type, handler) {
+ let listener = _notifHandlers.get(type);
if (!listener) {
return;
}
@@ -108,7 +120,7 @@ NotificationsComponent.prototype.removeEventListener = function(type: string, ha
_notifHandlers.delete(type);
}
-NotificationsComponent.prototype.registerNotificationActions = function(details: Object) {
+NotificationsComponent.prototype.registerNotificationActions = function(details) {
RNPushNotification.registerNotificationActions(details);
}
@@ -116,7 +128,48 @@ NotificationsComponent.prototype.clearAllNotifications = function() {
RNPushNotification.clearAllNotifications()
}
+NotificationsComponent.prototype.removeAllDeliveredNotifications = function() {
+ RNPushNotification.removeAllDeliveredNotifications();
+}
+
+NotificationsComponent.prototype.getDeliveredNotifications = function(callback) {
+ RNPushNotification.getDeliveredNotifications(callback);
+}
+NotificationsComponent.prototype.getScheduledLocalNotifications = function(callback) {
+ RNPushNotification.getScheduledLocalNotifications(callback);
+}
+NotificationsComponent.prototype.removeDeliveredNotifications = function(identifiers) {
+ RNPushNotification.removeDeliveredNotifications(identifiers);
+}
+
+NotificationsComponent.prototype.abandonPermissions = function() {
+ RNPushNotification.abandonPermissions();
+}
+
+NotificationsComponent.prototype.invokeApp = function(data) {
+ RNPushNotification.invokeApp(data);
+}
+
+NotificationsComponent.prototype.getChannels = function(callback) {
+ RNPushNotification.getChannels(callback);
+}
+
+NotificationsComponent.prototype.channelExists = function(channel_id, callback) {
+ RNPushNotification.channelExists(channel_id, callback);
+}
+
+NotificationsComponent.prototype.createChannel = function(channelInfo, callback) {
+ RNPushNotification.createChannel(channelInfo, callback);
+}
+
+NotificationsComponent.prototype.channelBlocked = function(channel_id, callback) {
+ RNPushNotification.channelBlocked(channel_id, callback);
+}
+
+NotificationsComponent.prototype.deleteChannel = function(channel_id) {
+ RNPushNotification.deleteChannel(channel_id);
+}
+
module.exports = {
- state: false,
component: new NotificationsComponent()
};
diff --git a/component/index.ios.js b/component/index.ios.js
index 400214be0..82eee6a92 100644
--- a/component/index.ios.js
+++ b/component/index.ios.js
@@ -1,9 +1,7 @@
"use strict";
-import { AppState } from "react-native";
import PushNotificationIOS from "@react-native-community/push-notification-ios";
module.exports = {
- state: AppState,
component: PushNotificationIOS
};
diff --git a/example/.babelrc b/example/.babelrc
deleted file mode 100644
index 108657ce5..000000000
--- a/example/.babelrc
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "retainLines": true,
- "compact": true,
- "comments": false,
- "presets": [
- "react-native"
- ],
- "sourceMaps": false
-}
\ No newline at end of file
diff --git a/example/.eslintrc.js b/example/.eslintrc.js
new file mode 100644
index 000000000..40c6dcd05
--- /dev/null
+++ b/example/.eslintrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: '@react-native-community',
+};
diff --git a/example/.flowconfig b/example/.flowconfig
index 3c0adb566..786366c4f 100644
--- a/example/.flowconfig
+++ b/example/.flowconfig
@@ -5,63 +5,70 @@
; Ignore "BUCK" generated dirs
/\.buckd/
-; Ignore unexpected extra "@providesModule"
-.*/node_modules/.*/node_modules/fbjs/.*
+; Ignore polyfills
+node_modules/react-native/Libraries/polyfills/.*
-; Ignore duplicate module providers
-; For RN Apps installed via npm, "Libraries" folder is inside
-; "node_modules/react-native" but in the source repo it is in the root
-.*/Libraries/react-native/React.js
+; These should not be required directly
+; require from fbjs/lib instead: require('fbjs/lib/warning')
+node_modules/warning/.*
-; Ignore polyfills
-.*/Libraries/polyfills/.*
+; Flow doesn't support platforms
+.*/Libraries/Utilities/LoadingView.js
-; Ignore metro
-.*/node_modules/metro/.*
+[untyped]
+.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
-node_modules/react-native/Libraries/react-native/react-native-interface.js
+node_modules/react-native/interface.js
node_modules/react-native/flow/
-node_modules/react-native/flow-github/
[options]
emoji=true
-module.system=haste
-module.system.haste.use_name_reducers=true
-# get basename
-module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
-# strip .js or .js.flow suffix
-module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
-# strip .ios suffix
-module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
-module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
-module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
-module.system.haste.paths.blacklist=.*/__tests__/.*
-module.system.haste.paths.blacklist=.*/__mocks__/.*
-module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.*
-module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.*
-
-munge_underscores=true
-
-module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
+esproposal.optional_chaining=enable
+esproposal.nullish_coalescing=enable
module.file_ext=.js
-module.file_ext=.jsx
module.file_ext=.json
-module.file_ext=.native.js
+module.file_ext=.ios.js
+
+munge_underscores=true
+
+module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1'
+module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
+[lints]
+sketchy-null-number=warn
+sketchy-null-mixed=warn
+sketchy-number=warn
+untyped-type-import=warn
+nonstrict-import=warn
+deprecated-type=warn
+unsafe-getters-setters=warn
+inexact-spread=warn
+unnecessary-invariant=warn
+signature-verification-failure=warn
+deprecated-utility=error
+
+[strict]
+deprecated-type
+nonstrict-import
+sketchy-null
+unclear-type
+unsafe-getters-setters
+untyped-import
+untyped-type-import
+
[version]
-^0.75.0
+^0.113.0
diff --git a/example/.gitignore b/example/.gitignore
index 5d647565f..5366d9fd5 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -20,13 +20,13 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
-project.xcworkspace
# Android/IntelliJ
#
build/
.idea
.gradle
+
local.properties
*.iml
@@ -54,3 +54,6 @@ buck-out/
# Bundle artifact
*.jsbundle
+
+# CocoaPods
+/ios/Pods/
diff --git a/example/.prettierrc.js b/example/.prettierrc.js
new file mode 100644
index 000000000..5c4de1a4f
--- /dev/null
+++ b/example/.prettierrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+ bracketSpacing: false,
+ jsxBracketSameLine: true,
+ singleQuote: true,
+ trailingComma: 'all',
+};
diff --git a/example/App.js b/example/App.js
index 75dc49998..eb08ef637 100644
--- a/example/App.js
+++ b/example/App.js
@@ -6,41 +6,137 @@
* @flow
*/
-import React, { Component } from 'react';
-import { TextInput, StyleSheet, Text, View, TouchableOpacity, Alert } from 'react-native';
+import React, {Component} from 'react';
+import {
+ TextInput,
+ StyleSheet,
+ Text,
+ View,
+ TouchableOpacity,
+ Alert,
+} from 'react-native';
import NotifService from './NotifService';
-import appConfig from './app.json';
-
-type Props = {};
-export default class App extends Component {
+export default class App extends Component {
constructor(props) {
super(props);
- this.state = {
- senderId: appConfig.senderID
- };
+ this.state = {};
- this.notif = new NotifService(this.onRegister.bind(this), this.onNotif.bind(this));
+ this.notif = new NotifService(
+ this.onRegister.bind(this),
+ this.onNotif.bind(this),
+ );
}
render() {
return (
- Example app react-native-push-notification
+
+ Example app react-native-push-notification
+
-
+
- { this.notif.localNotif() }}>Local Notification (now)
- { this.notif.scheduleNotif() }}>Schedule Notification in 30s
- { this.notif.cancelNotif() }}>Cancel last notification (if any)
- { this.notif.cancelAll() }}>Cancel all notifications
- { this.notif.checkPermission(this.handlePerm.bind(this)) }}>Check Permission
+ {
+ this.notif.localNotif();
+ }}>
+ Local Notification (now)
+
+ {
+ this.notif.localNotif('sample.mp3');
+ }}>
+ Local Notification with sound (now)
+
+ {
+ this.notif.scheduleNotif();
+ }}>
+ Schedule Notification in 30s
+
+ {
+ this.notif.scheduleNotif('sample.mp3');
+ }}>
+ Schedule Notification with sound in 30s
+
+ {
+ this.notif.cancelNotif();
+ }}>
+ Cancel last notification (if any)
+
+ {
+ this.notif.cancelAll();
+ }}>
+ Cancel all notifications
+
+ {
+ this.notif.checkPermission(this.handlePerm.bind(this));
+ }}>
+ Check Permission
+
+ {
+ this.notif.requestPermissions();
+ }}>
+ Request Permissions
+
+ {
+ this.notif.abandonPermissions();
+ }}>
+ Abandon Permissions
+
+ {
+ this.notif.getScheduledLocalNotifications(notifs => console.log(notifs));
+ }}>
+ Console.Log Scheduled Local Notifications
+
+ {
+ this.notif.getDeliveredNotifications(notifs => console.log(notifs));
+ }}>
+ Console.Log Delivered Notifications
+
+ {
+ this.notif.createOrUpdateChannel();
+ }}>
+ Create or update a channel
+
+ {
+ this.notif.popInitialNotification();
+ }}>
+ popInitialNotification
+
- {this.setState({ senderId: e })}} placeholder="GCM ID" />
- { this.notif.configure(this.onRegister.bind(this), this.onNotif.bind(this), this.state.senderId) }}>Configure Sender ID
- {this.state.gcmRegistered && GCM Configured !}
+
+ {this.state.fcmRegistered && FCM Configured !}
@@ -48,22 +144,18 @@ export default class App extends Component {
}
onRegister(token) {
- Alert.alert("Registered !", JSON.stringify(token));
- console.log(token);
- this.setState({ registerToken: token.token, gcmRegistered: true });
+ this.setState({registerToken: token.token, fcmRegistered: true});
}
onNotif(notif) {
- console.log(notif);
Alert.alert(notif.title, notif.message);
}
handlePerm(perms) {
- Alert.alert("Permissions", JSON.stringify(perms));
+ Alert.alert('Permissions', JSON.stringify(perms));
}
}
-
const styles = StyleSheet.create({
container: {
flex: 1,
@@ -78,26 +170,26 @@ const styles = StyleSheet.create({
},
button: {
borderWidth: 1,
- borderColor: "#000000",
+ borderColor: '#000000',
margin: 5,
padding: 5,
- width: "70%",
- backgroundColor: "#DDDDDD",
+ width: '70%',
+ backgroundColor: '#DDDDDD',
borderRadius: 5,
},
textField: {
borderWidth: 1,
- borderColor: "#AAAAAA",
+ borderColor: '#AAAAAA',
margin: 5,
padding: 5,
- width: "70%"
+ width: '70%',
},
spacer: {
height: 10,
},
title: {
- fontWeight: "bold",
+ fontWeight: 'bold',
fontSize: 20,
- textAlign: "center",
- }
+ textAlign: 'center',
+ },
});
diff --git a/example/NotifService.js b/example/NotifService.js
index 086f59d80..6935285c1 100644
--- a/example/NotifService.js
+++ b/example/NotifService.js
@@ -1,107 +1,150 @@
-import PushNotification from 'react-native-push-notification';
+import PushNotification, {Importance} from 'react-native-push-notification';
+import NotificationHandler from './NotificationHandler';
export default class NotifService {
-
constructor(onRegister, onNotification) {
- this.configure(onRegister, onNotification);
-
this.lastId = 0;
- }
+ this.lastChannelCounter = 0;
- configure(onRegister, onNotification, gcm = "") {
- PushNotification.configure({
- // (optional) Called when Token is generated (iOS and Android)
- onRegister: onRegister, //this._onRegister.bind(this),
+ this.createDefaultChannels();
- // (required) Called when a remote or local notification is opened or received
- onNotification: onNotification, //this._onNotification,
+ NotificationHandler.attachRegister(onRegister);
+ NotificationHandler.attachNotification(onNotification);
- // ANDROID ONLY: GCM Sender ID (optional - not required for local notifications, but is need to receive remote push notifications)
- senderID: gcm,
+ // Clear badge number at start
+ PushNotification.getApplicationIconBadgeNumber(function (number) {
+ if (number > 0) {
+ PushNotification.setApplicationIconBadgeNumber(0);
+ }
+ });
+
+ PushNotification.getChannels(function(channels) {
+ console.log(channels);
+ });
+ }
- // IOS ONLY (optional): default: all - Permissions to register.
- permissions: {
- alert: true,
- badge: true,
- sound: true
+ createDefaultChannels() {
+ PushNotification.createChannel(
+ {
+ channelId: "default-channel-id", // (required)
+ channelName: `Default channel`, // (required)
+ channelDescription: "A default channel", // (optional) default: undefined.
+ soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
+ importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
+ vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
},
+ (created) => console.log(`createChannel 'default-channel-id' returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
+ );
+ PushNotification.createChannel(
+ {
+ channelId: "sound-channel-id", // (required)
+ channelName: `Sound channel`, // (required)
+ channelDescription: "A sound channel", // (optional) default: undefined.
+ soundName: "sample.mp3", // (optional) See `soundName` parameter of `localNotification` function
+ importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
+ vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
+ },
+ (created) => console.log(`createChannel 'sound-channel-id' returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
+ );
+ }
- // Should the initial notification be popped automatically
- // default: true
- popInitialNotification: true,
+ createOrUpdateChannel() {
+ this.lastChannelCounter++;
+ PushNotification.createChannel(
+ {
+ channelId: "custom-channel-id", // (required)
+ channelName: `Custom channel - Counter: ${this.lastChannelCounter}`, // (required)
+ channelDescription: `A custom channel to categorise your custom notifications. Updated at: ${Date.now()}`, // (optional) default: undefined.
+ soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
+ importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
+ vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
+ },
+ (created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
+ );
+ }
- /**
- * (optional) default: true
- * - Specified if permissions (ios) and token (android and ios) will requested or not,
- * - if not, you must call PushNotificationsHandler.requestPermissions() later
- */
- requestPermissions: true,
- });
+ popInitialNotification() {
+ PushNotification.popInitialNotification((notification) => console.log('InitialNotication:', notification));
}
- localNotif() {
+ localNotif(soundName) {
this.lastId++;
PushNotification.localNotification({
/* Android Only Properties */
- id: ''+this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
- ticker: "My Notification Ticker", // (optional)
+ channelId: soundName ? 'sound-channel-id' : 'default-channel-id',
+ ticker: 'My Notification Ticker', // (optional)
autoCancel: true, // (optional) default: true
- largeIcon: "ic_launcher", // (optional) default: "ic_launcher"
- smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher"
- bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop
- subText: "This is a subText", // (optional) default: none
- color: "red", // (optional) default: system default
+ largeIcon: 'ic_launcher', // (optional) default: "ic_launcher"
+ smallIcon: 'ic_notification', // (optional) default: "ic_notification" with fallback for "ic_launcher"
+ bigText: 'My big text that will be shown when notification is expanded', // (optional) default: "message" prop
+ subText: 'This is a subText', // (optional) default: none
+ color: 'red', // (optional) default: system default
vibrate: true, // (optional) default: true
vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
tag: 'some_tag', // (optional) add tag to message
- group: "group", // (optional) add group to message
+ group: 'group', // (optional) add group to message
+ groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false
ongoing: false, // (optional) set whether this is an "ongoing" notification
+ actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more
+ invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true
+
+ when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null.
+ usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false.
+ timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null
/* iOS only properties */
- alertAction: 'view', // (optional) default: view
- category: null, // (optional) default: null
- userInfo: null, // (optional) default: null (object containing additional notification data)
+ category: '', // (optional) default: empty string
+ subtitle: "My Notification Subtitle", // (optional) smaller title below notification title
/* iOS and Android properties */
- title: "Local Notification", // (optional)
- message: "My Notification Message", // (required)
- playSound: false, // (optional) default: true
- soundName: 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
- number: '10', // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
- actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more
+ id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
+ title: 'Local Notification', // (optional)
+ message: 'My Notification Message', // (required)
+ userInfo: { screen: 'home' }, // (optional) default: {} (using null throws a JSON value '' error)
+ playSound: !!soundName, // (optional) default: true
+ soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
+ number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
});
}
- scheduleNotif() {
+ scheduleNotif(soundName) {
this.lastId++;
PushNotification.localNotificationSchedule({
- date: new Date(Date.now() + (30 * 1000)), // in 30 secs
+ date: new Date(Date.now() + 30 * 1000), // in 30 secs
/* Android Only Properties */
- id: ''+this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
- ticker: "My Notification Ticker", // (optional)
+ channelId: soundName ? 'sound-channel-id' : 'default-channel-id',
+ ticker: 'My Notification Ticker', // (optional)
autoCancel: true, // (optional) default: true
- largeIcon: "ic_launcher", // (optional) default: "ic_launcher"
- smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher"
- bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop
- subText: "This is a subText", // (optional) default: none
- color: "blue", // (optional) default: system default
+ largeIcon: 'ic_launcher', // (optional) default: "ic_launcher"
+ smallIcon: 'ic_notification', // (optional) default: "ic_notification" with fallback for "ic_launcher"
+ bigText: 'My big text that will be shown when notification is expanded', // (optional) default: "message" prop
+ subText: 'This is a subText', // (optional) default: none
+ color: 'blue', // (optional) default: system default
vibrate: true, // (optional) default: true
vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
tag: 'some_tag', // (optional) add tag to message
- group: "group", // (optional) add group to message
+ group: 'group', // (optional) add group to message
+ groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false
ongoing: false, // (optional) set whether this is an "ongoing" notification
+ actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more
+ invokeApp: false, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true
+ when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null.
+ usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false.
+ timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null
+
/* iOS only properties */
- alertAction: 'view', // (optional) default: view
- category: null, // (optional) default: null
- userInfo: null, // (optional) default: null (object containing additional notification data)
-
+ category: '', // (optional) default: empty string
+
/* iOS and Android properties */
- title: "Scheduled Notification", // (optional)
- message: "My Notification Message", // (required)
- playSound: true, // (optional) default: true
- soundName: 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
+ id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
+ title: 'Scheduled Notification', // (optional)
+ message: 'My Notification Message', // (required)
+ userInfo: { sceen: "home" }, // (optional) default: {} (using null throws a JSON value '' error)
+ playSound: !!soundName, // (optional) default: true
+ soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
+ number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
});
}
@@ -109,11 +152,27 @@ export default class NotifService {
return PushNotification.checkPermissions(cbk);
}
+ requestPermissions() {
+ return PushNotification.requestPermissions();
+ }
+
cancelNotif() {
- PushNotification.cancelLocalNotifications({id: ''+this.lastId});
+ PushNotification.cancelLocalNotification(this.lastId);
}
cancelAll() {
PushNotification.cancelAllLocalNotifications();
}
-}
\ No newline at end of file
+
+ abandonPermissions() {
+ PushNotification.abandonPermissions();
+ }
+
+ getScheduledLocalNotifications(callback) {
+ PushNotification.getScheduledLocalNotifications(callback);
+ }
+
+ getDeliveredNotifications(callback) {
+ PushNotification.getDeliveredNotifications(callback);
+ }
+}
diff --git a/example/NotificationHandler.js b/example/NotificationHandler.js
new file mode 100644
index 000000000..040d3c0cf
--- /dev/null
+++ b/example/NotificationHandler.js
@@ -0,0 +1,78 @@
+import PushNotification from 'react-native-push-notification';
+
+class NotificationHandler {
+ onNotification(notification) {
+ console.log('NotificationHandler:', notification);
+
+ if (typeof this._onNotification === 'function') {
+ this._onNotification(notification);
+ }
+ }
+
+ onRegister(token) {
+ console.log('NotificationHandler:', token);
+
+ if (typeof this._onRegister === 'function') {
+ this._onRegister(token);
+ }
+ }
+
+ onAction(notification) {
+ console.log ('Notification action received:');
+ console.log(notification.action);
+ console.log(notification);
+
+ if(notification.action === 'Yes') {
+ PushNotification.invokeApp(notification);
+ }
+ }
+
+ // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
+ onRegistrationError(err) {
+ console.log(err);
+ }
+
+ attachRegister(handler) {
+ this._onRegister = handler;
+ }
+
+ attachNotification(handler) {
+ this._onNotification = handler;
+ }
+}
+
+const handler = new NotificationHandler();
+
+PushNotification.configure({
+ // (optional) Called when Token is generated (iOS and Android)
+ onRegister: handler.onRegister.bind(handler),
+
+ // (required) Called when a remote or local notification is opened or received
+ onNotification: handler.onNotification.bind(handler),
+
+ // (optional) Called when Action is pressed (Android)
+ onAction: handler.onAction.bind(handler),
+
+ // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
+ onRegistrationError: handler.onRegistrationError.bind(handler),
+
+ // IOS ONLY (optional): default: all - Permissions to register.
+ permissions: {
+ alert: true,
+ badge: true,
+ sound: true,
+ },
+
+ // Should the initial notification be popped automatically
+ // default: true
+ popInitialNotification: true,
+
+ /**
+ * (optional) default: true
+ * - Specified if permissions (ios) and token (android and ios) will requested or not,
+ * - if not, you must call PushNotificationsHandler.requestPermissions() later
+ */
+ requestPermissions: true,
+});
+
+export default handler;
diff --git a/example/__tests__/App-test.js b/example/__tests__/App-test.js
new file mode 100644
index 000000000..178476699
--- /dev/null
+++ b/example/__tests__/App-test.js
@@ -0,0 +1,14 @@
+/**
+ * @format
+ */
+
+import 'react-native';
+import React from 'react';
+import App from '../App';
+
+// Note: test renderer must be required after react-native.
+import renderer from 'react-test-renderer';
+
+it('renders correctly', () => {
+ renderer.create();
+});
diff --git a/example/android/.project b/example/android/.project
new file mode 100644
index 000000000..0812d9e3f
--- /dev/null
+++ b/example/android/.project
@@ -0,0 +1,17 @@
+
+
+ example
+ Project android created by Buildship.
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 000000000..342e81ef5
--- /dev/null
+++ b/example/android/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/example/android/app/.classpath b/example/android/app/.classpath
new file mode 100644
index 000000000..eb19361b5
--- /dev/null
+++ b/example/android/app/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/example/android/app/.project b/example/android/app/.project
new file mode 100644
index 000000000..ac485d7c3
--- /dev/null
+++ b/example/android/app/.project
@@ -0,0 +1,23 @@
+
+
+ app
+ Project app created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 000000000..b3d49cd88
--- /dev/null
+++ b/example/android/app/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3))
+connection.project.dir=..
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/example/android/app/BUCK b/example/android/app/BUCK
index c8f560323..a4cb8a5b0 100644
--- a/example/android/app/BUCK
+++ b/example/android/app/BUCK
@@ -8,23 +8,13 @@
# - `buck install -r android/app` - compile, install and run application
#
+load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
+
lib_deps = []
-for jarfile in glob(['libs/*.jar']):
- name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
- lib_deps.append(':' + name)
- prebuilt_jar(
- name = name,
- binary_jar = jarfile,
- )
+create_aar_targets(glob(["libs/*.aar"]))
-for aarfile in glob(['libs/*.aar']):
- name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
- lib_deps.append(':' + name)
- android_prebuilt_aar(
- name = name,
- aar = aarfile,
- )
+create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index 90e7199c1..3ff475d22 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -15,9 +15,14 @@ import com.android.build.OutputFile
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
- * // the entry file for bundle generation
+ * // the entry file for bundle generation. If none specified and
+ * // "index.android.js" exists, it will be used. Otherwise "index.js" is
+ * // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
+ * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
+ * bundleCommand: "ram-bundle",
+ *
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
@@ -73,7 +78,7 @@ import com.android.build.OutputFile
*/
project.ext.react = [
- entryFile: "index.js"
+ enableHermes: false, // clean and rebuild if changing
]
apply from: "../../node_modules/react-native/react.gradle"
@@ -93,9 +98,35 @@ def enableSeparateBuildPerCPUArchitecture = false
*/
def enableProguardInReleaseBuilds = false
+/**
+ * The preferred build flavor of JavaScriptCore.
+ *
+ * For example, to use the international variant, you can use:
+ * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
+ *
+ * The international variant includes ICU i18n library and necessary data
+ * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
+ * give correct results when using with locales other than en-US. Note that
+ * this variant is about 6MiB larger per architecture than default.
+ */
+def jscFlavor = 'org.webkit:android-jsc:+'
+
+/**
+ * Whether to enable the Hermes VM.
+ *
+ * This should be set on project.ext.react and mirrored here. If it is not set
+ * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
+ * and the benefits of using Hermes will therefore be sharply reduced.
+ */
+def enableHermes = project.ext.react.get("enableHermes", false);
+
android {
compileSdkVersion rootProject.ext.compileSdkVersion
- buildToolsVersion rootProject.ext.buildToolsVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
defaultConfig {
applicationId "com.example"
@@ -103,49 +134,82 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
- ndk {
- abiFilters "armeabi-v7a", "x86"
- }
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
- include "armeabi-v7a", "x86"
+ include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
+ }
+ }
+ signingConfigs {
+ debug {
+ storeFile file('debug.keystore')
+ storePassword 'android'
+ keyAlias 'androiddebugkey'
+ keyPassword 'android'
}
}
buildTypes {
+ debug {
+ signingConfig signingConfigs.debug
+ }
release {
+ // Caution! In production, you need to generate your own keystore file.
+ // see https://facebook.github.io/react-native/docs/signed-apk-android.
+ signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
+
+ packagingOptions {
+ pickFirst "lib/armeabi-v7a/libc++_shared.so"
+ pickFirst "lib/arm64-v8a/libc++_shared.so"
+ pickFirst "lib/x86/libc++_shared.so"
+ pickFirst "lib/x86_64/libc++_shared.so"
+ }
+
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
- // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
- def versionCodes = ["armeabi-v7a":1, "x86":2]
+ // https://developer.android.com/studio/build/configure-apk-splits.html
+ def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
+
}
}
}
dependencies {
- compile project(':react-native-push-notification')
- compile fileTree(dir: "libs", include: ["*.jar"])
- compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
- compile "com.facebook.react:react-native:+" // From node_modules
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ //noinspection GradleDynamicVersion
+ implementation "com.facebook.react:react-native:+" // From node_modules
+
+ implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
+
+ if (enableHermes) {
+ def hermesPath = "../../node_modules/hermes-engine/android/";
+ debugImplementation files(hermesPath + "hermes-debug.aar")
+ releaseImplementation files(hermesPath + "hermes-release.aar")
+ } else {
+ implementation jscFlavor
+ }
}
+apply plugin: 'com.google.gms.google-services'
+
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
+
+apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
diff --git a/example/android/app/build_defs.bzl b/example/android/app/build_defs.bzl
new file mode 100644
index 000000000..fff270f8d
--- /dev/null
+++ b/example/android/app/build_defs.bzl
@@ -0,0 +1,19 @@
+"""Helper definitions to glob .aar and .jar targets"""
+
+def create_aar_targets(aarfiles):
+ for aarfile in aarfiles:
+ name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
+ lib_deps.append(":" + name)
+ android_prebuilt_aar(
+ name = name,
+ aar = aarfile,
+ )
+
+def create_jar_targets(jarfiles):
+ for jarfile in jarfiles:
+ name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
+ lib_deps.append(":" + name)
+ prebuilt_jar(
+ name = name,
+ binary_jar = jarfile,
+ )
diff --git a/example/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro
index a92fa177e..11b025724 100644
--- a/example/android/app/proguard-rules.pro
+++ b/example/android/app/proguard-rules.pro
@@ -8,10 +8,3 @@
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 34a9de9e5..8a88f01e5 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -1,19 +1,25 @@
+ package="com.example">
+
+
+
+ android:theme="@style/AppTheme"
+ android:usesCleartextTraffic="true">
@@ -22,49 +28,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
diff --git a/example/android/app/src/main/java/com/example/MainActivity.java b/example/android/app/src/main/java/com/example/MainActivity.java
index e84b72551..5e57fb914 100644
--- a/example/android/app/src/main/java/com/example/MainActivity.java
+++ b/example/android/app/src/main/java/com/example/MainActivity.java
@@ -4,12 +4,12 @@
public class MainActivity extends ReactActivity {
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "example";
- }
+ /**
+ * Returns the name of the main component registered from JavaScript. This is
+ * used to schedule rendering of the component.
+ */
+ @Override
+ protected String getMainComponentName() {
+ return "example";
+ }
}
diff --git a/example/android/app/src/main/java/com/example/MainApplication.java b/example/android/app/src/main/java/com/example/MainApplication.java
index d85de4d9a..fd8ec883d 100644
--- a/example/android/app/src/main/java/com/example/MainApplication.java
+++ b/example/android/app/src/main/java/com/example/MainApplication.java
@@ -1,38 +1,39 @@
package com.example;
import android.app.Application;
-
+import android.content.Context;
+import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
-import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
+import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
-import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
-
-import java.util.Arrays;
+import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
- private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
+ private final ReactNativeHost mReactNativeHost =
+ new ReactNativeHost(this) {
+ @Override
+ public boolean getUseDeveloperSupport() {
+ return BuildConfig.DEBUG;
+ }
- @Override
- protected List getPackages() {
- return Arrays.asList(
- new MainReactPackage(),
- new ReactNativePushNotificationPackage()
- );
- }
+ @Override
+ protected List getPackages() {
+ @SuppressWarnings("UnnecessaryLocalVariable")
+ List packages = new PackageList(this).getPackages();
+ // Packages that cannot be autolinked yet can be added manually here, for example:
+ // packages.add(new MyReactNativePackage());
+ return packages;
+ }
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
- };
+ @Override
+ protected String getJSMainModuleName() {
+ return "index";
+ }
+ };
@Override
public ReactNativeHost getReactNativeHost() {
@@ -43,5 +44,37 @@ public ReactNativeHost getReactNativeHost() {
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
+ initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
+ }
+
+ /**
+ * Loads Flipper in React Native templates. Call this in the onCreate method with something like
+ * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
+ *
+ * @param context
+ * @param reactInstanceManager
+ */
+ private static void initializeFlipper(
+ Context context, ReactInstanceManager reactInstanceManager) {
+ if (BuildConfig.DEBUG) {
+ try {
+ /*
+ We use reflection here to pick up the class that initializes Flipper,
+ since Flipper library is not available in release mode
+ */
+ Class> aClass = Class.forName("com.example.ReactNativeFlipper");
+ aClass
+ .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
+ .invoke(null, context, reactInstanceManager);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
}
}
diff --git a/example/android/app/src/main/res/raw/sample.mp3 b/example/android/app/src/main/res/raw/sample.mp3
new file mode 100644
index 000000000..4569ff11f
Binary files /dev/null and b/example/android/app/src/main/res/raw/sample.mp3 differ
diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml
index d75426c8a..3ea30b725 100644
--- a/example/android/app/src/main/res/values/strings.xml
+++ b/example/android/app/src/main/res/values/strings.xml
@@ -1,3 +1,5 @@
example
+ Exemple title loc_key
+ Exemple message loc_key: %1$s
diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml
index 319eb0ca1..62fe59fa4 100644
--- a/example/android/app/src/main/res/values/styles.xml
+++ b/example/android/app/src/main/res/values/styles.xml
@@ -3,6 +3,7 @@
diff --git a/example/android/build.gradle b/example/android/build.gradle
index 49569e4db..32a599bd5 100644
--- a/example/android/build.gradle
+++ b/example/android/build.gradle
@@ -1,16 +1,20 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
+ ext {
+ buildToolsVersion = "28.0.3"
+ minSdkVersion = 16
+ compileSdkVersion = 28
+ targetSdkVersion = 28
+ }
repositories {
+ google()
jcenter()
- maven {
- url 'https://maven.google.com/'
- name 'Google'
- }
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.3'
+ classpath("com.android.tools.build:gradle:3.5.2")
+ classpath('com.google.gms:google-services:4.3.3')
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -19,22 +23,17 @@ buildscript {
allprojects {
repositories {
mavenLocal()
- jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url "$rootDir/../node_modules/react-native/android"
+ url("$rootDir/../node_modules/react-native/android")
}
maven {
- url 'https://maven.google.com/'
- name 'Google'
+ // Android JSC is installed from npm
+ url("$rootDir/../node_modules/jsc-android/dist")
}
- }
-}
-ext {
- buildToolsVersion = "26.0.3"
- minSdkVersion = 16
- compileSdkVersion = 26
- targetSdkVersion = 26
- supportLibVersion = "26.1.0"
+ google()
+ jcenter()
+ maven { url 'https://www.jitpack.io' }
+ }
}
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
index 1fd964e90..1bbc8cc20 100644
--- a/example/android/gradle.properties
+++ b/example/android/gradle.properties
@@ -17,4 +17,12 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-android.useDeprecatedNdk=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+
+# Version of flipper SDK to use with React Native
+FLIPPER_VERSION=0.33.1
diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar
index b5166dad4..5c2d1cf01 100644
Binary files a/example/android/gradle/wrapper/gradle-wrapper.jar and b/example/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
index 81a86e213..1ba7206f8 100644
--- a/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
diff --git a/example/android/gradlew b/example/android/gradlew
index 91a7e269e..83f2acfdc 100755
--- a/example/android/gradlew
+++ b/example/android/gradlew
@@ -1,4 +1,20 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
##
@@ -6,20 +22,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +64,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +75,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -110,10 +125,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +170,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/example/android/gradlew.bat b/example/android/gradlew.bat
index 8a0b282aa..9618d8d96 100644
--- a/example/android/gradlew.bat
+++ b/example/android/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,14 +24,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +62,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +75,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/example/android/keystores/BUCK b/example/android/keystores/BUCK
deleted file mode 100644
index 88e4c31b2..000000000
--- a/example/android/keystores/BUCK
+++ /dev/null
@@ -1,8 +0,0 @@
-keystore(
- name = "debug",
- properties = "debug.keystore.properties",
- store = "debug.keystore",
- visibility = [
- "PUBLIC",
- ],
-)
diff --git a/example/android/keystores/debug.keystore.properties b/example/android/keystores/debug.keystore.properties
deleted file mode 100644
index 121bfb49f..000000000
--- a/example/android/keystores/debug.keystore.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-key.store=debug.keystore
-key.alias=androiddebugkey
-key.store.password=android
-key.alias.password=android
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
index 819c58ab6..263c9e8ca 100644
--- a/example/android/settings.gradle
+++ b/example/android/settings.gradle
@@ -1,5 +1,3 @@
rootProject.name = 'example'
-include ':react-native-push-notification'
-project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
-
+apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
diff --git a/example/app.json b/example/app.json
index ea94bc4c6..2f89ceb8b 100644
--- a/example/app.json
+++ b/example/app.json
@@ -1,5 +1,4 @@
{
"name": "example",
- "displayName": "React Native Push Notification Example",
- "senderID": "YOUR-GCM-ID"
-}
\ No newline at end of file
+ "displayName": "React Native Push Notification Example"
+}
diff --git a/example/babel.config.js b/example/babel.config.js
new file mode 100644
index 000000000..f842b77fc
--- /dev/null
+++ b/example/babel.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ presets: ['module:metro-react-native-babel-preset'],
+};
diff --git a/example/index.js b/example/index.js
index 802b4350d..a850d031d 100644
--- a/example/index.js
+++ b/example/index.js
@@ -1,4 +1,6 @@
-/** @format */
+/**
+ * @format
+ */
import {AppRegistry} from 'react-native';
import App from './App';
diff --git a/example/ios/Podfile b/example/ios/Podfile
new file mode 100644
index 000000000..72234cc84
--- /dev/null
+++ b/example/ios/Podfile
@@ -0,0 +1,24 @@
+platform :ios, '10.0'
+require_relative '../node_modules/react-native/scripts/react_native_pods'
+require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
+
+target 'example' do
+ # Pods for example
+ config = use_native_modules!
+
+ use_react_native!(:path => config["reactNativePath"])
+
+ target 'exampleTests' do
+ inherit! :complete
+ # Pods for testing
+ end
+end
+
+target 'example-tvOS' do
+ # Pods for example-tvOS
+
+ target 'example-tvOSTests' do
+ inherit! :search_paths
+ # Pods for testing
+ end
+end
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
new file mode 100644
index 000000000..14c07e3af
--- /dev/null
+++ b/example/ios/Podfile.lock
@@ -0,0 +1,375 @@
+PODS:
+ - boost-for-react-native (1.63.0)
+ - DoubleConversion (1.1.6)
+ - FBLazyVector (0.63.3)
+ - FBReactNativeSpec (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - RCTRequired (= 0.63.3)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - Folly (2020.01.13.00):
+ - boost-for-react-native
+ - DoubleConversion
+ - Folly/Default (= 2020.01.13.00)
+ - glog
+ - Folly/Default (2020.01.13.00):
+ - boost-for-react-native
+ - DoubleConversion
+ - glog
+ - glog (0.3.5)
+ - RCTRequired (0.63.3)
+ - RCTTypeSafety (0.63.3):
+ - FBLazyVector (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTRequired (= 0.63.3)
+ - React-Core (= 0.63.3)
+ - React (0.63.3):
+ - React-Core (= 0.63.3)
+ - React-Core/DevSupport (= 0.63.3)
+ - React-Core/RCTWebSocket (= 0.63.3)
+ - React-RCTActionSheet (= 0.63.3)
+ - React-RCTAnimation (= 0.63.3)
+ - React-RCTBlob (= 0.63.3)
+ - React-RCTImage (= 0.63.3)
+ - React-RCTLinking (= 0.63.3)
+ - React-RCTNetwork (= 0.63.3)
+ - React-RCTSettings (= 0.63.3)
+ - React-RCTText (= 0.63.3)
+ - React-RCTVibration (= 0.63.3)
+ - React-callinvoker (0.63.3)
+ - React-Core (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default (= 0.63.3)
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/CoreModulesHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/Default (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/DevSupport (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default (= 0.63.3)
+ - React-Core/RCTWebSocket (= 0.63.3)
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - React-jsinspector (= 0.63.3)
+ - Yoga
+ - React-Core/RCTActionSheetHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTAnimationHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTBlobHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTImageHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTLinkingHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTNetworkHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTSettingsHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTTextHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTVibrationHeaders (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-Core/RCTWebSocket (0.63.3):
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-Core/Default (= 0.63.3)
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsiexecutor (= 0.63.3)
+ - Yoga
+ - React-CoreModules (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core/CoreModulesHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-RCTImage (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-cxxreact (0.63.3):
+ - boost-for-react-native (= 1.63.0)
+ - DoubleConversion
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-callinvoker (= 0.63.3)
+ - React-jsinspector (= 0.63.3)
+ - React-jsi (0.63.3):
+ - boost-for-react-native (= 1.63.0)
+ - DoubleConversion
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-jsi/Default (= 0.63.3)
+ - React-jsi/Default (0.63.3):
+ - boost-for-react-native (= 1.63.0)
+ - DoubleConversion
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-jsiexecutor (0.63.3):
+ - DoubleConversion
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-jsinspector (0.63.3)
+ - React-RCTActionSheet (0.63.3):
+ - React-Core/RCTActionSheetHeaders (= 0.63.3)
+ - React-RCTAnimation (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core/RCTAnimationHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTBlob (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - React-Core/RCTBlobHeaders (= 0.63.3)
+ - React-Core/RCTWebSocket (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-RCTNetwork (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTImage (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core/RCTImageHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - React-RCTNetwork (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTLinking (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - React-Core/RCTLinkingHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTNetwork (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core/RCTNetworkHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTSettings (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - RCTTypeSafety (= 0.63.3)
+ - React-Core/RCTSettingsHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - React-RCTText (0.63.3):
+ - React-Core/RCTTextHeaders (= 0.63.3)
+ - React-RCTVibration (0.63.3):
+ - FBReactNativeSpec (= 0.63.3)
+ - Folly (= 2020.01.13.00)
+ - React-Core/RCTVibrationHeaders (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - ReactCommon/turbomodule/core (= 0.63.3)
+ - ReactCommon/turbomodule/core (0.63.3):
+ - DoubleConversion
+ - Folly (= 2020.01.13.00)
+ - glog
+ - React-callinvoker (= 0.63.3)
+ - React-Core (= 0.63.3)
+ - React-cxxreact (= 0.63.3)
+ - React-jsi (= 0.63.3)
+ - RNCPushNotificationIOS (1.10.1):
+ - React-Core
+ - Yoga (1.14.0)
+
+DEPENDENCIES:
+ - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
+ - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
+ - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
+ - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
+ - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
+ - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
+ - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
+ - React (from `../node_modules/react-native/`)
+ - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
+ - React-Core (from `../node_modules/react-native/`)
+ - React-Core/DevSupport (from `../node_modules/react-native/`)
+ - React-Core/RCTWebSocket (from `../node_modules/react-native/`)
+ - React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
+ - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
+ - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
+ - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
+ - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
+ - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
+ - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
+ - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
+ - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
+ - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
+ - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
+ - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
+ - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
+ - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
+ - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
+ - "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
+ - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
+
+SPEC REPOS:
+ trunk:
+ - boost-for-react-native
+
+EXTERNAL SOURCES:
+ DoubleConversion:
+ :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
+ FBLazyVector:
+ :path: "../node_modules/react-native/Libraries/FBLazyVector"
+ FBReactNativeSpec:
+ :path: "../node_modules/react-native/Libraries/FBReactNativeSpec"
+ Folly:
+ :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
+ glog:
+ :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
+ RCTRequired:
+ :path: "../node_modules/react-native/Libraries/RCTRequired"
+ RCTTypeSafety:
+ :path: "../node_modules/react-native/Libraries/TypeSafety"
+ React:
+ :path: "../node_modules/react-native/"
+ React-callinvoker:
+ :path: "../node_modules/react-native/ReactCommon/callinvoker"
+ React-Core:
+ :path: "../node_modules/react-native/"
+ React-CoreModules:
+ :path: "../node_modules/react-native/React/CoreModules"
+ React-cxxreact:
+ :path: "../node_modules/react-native/ReactCommon/cxxreact"
+ React-jsi:
+ :path: "../node_modules/react-native/ReactCommon/jsi"
+ React-jsiexecutor:
+ :path: "../node_modules/react-native/ReactCommon/jsiexecutor"
+ React-jsinspector:
+ :path: "../node_modules/react-native/ReactCommon/jsinspector"
+ React-RCTActionSheet:
+ :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
+ React-RCTAnimation:
+ :path: "../node_modules/react-native/Libraries/NativeAnimation"
+ React-RCTBlob:
+ :path: "../node_modules/react-native/Libraries/Blob"
+ React-RCTImage:
+ :path: "../node_modules/react-native/Libraries/Image"
+ React-RCTLinking:
+ :path: "../node_modules/react-native/Libraries/LinkingIOS"
+ React-RCTNetwork:
+ :path: "../node_modules/react-native/Libraries/Network"
+ React-RCTSettings:
+ :path: "../node_modules/react-native/Libraries/Settings"
+ React-RCTText:
+ :path: "../node_modules/react-native/Libraries/Text"
+ React-RCTVibration:
+ :path: "../node_modules/react-native/Libraries/Vibration"
+ ReactCommon:
+ :path: "../node_modules/react-native/ReactCommon"
+ RNCPushNotificationIOS:
+ :path: "../node_modules/@react-native-community/push-notification-ios"
+ Yoga:
+ :path: "../node_modules/react-native/ReactCommon/yoga"
+
+SPEC CHECKSUMS:
+ boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
+ DoubleConversion: cde416483dac037923206447da6e1454df403714
+ FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d
+ FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f
+ Folly: b73c3869541e86821df3c387eb0af5f65addfab4
+ glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
+ RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047
+ RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab
+ React: f36e90f3ceb976546e97df3403e37d226f79d0e3
+ React-callinvoker: 18874f621eb96625df7a24a7dc8d6e07391affcd
+ React-Core: ac3d816b8e3493970153f4aaf0cff18af0bb95e6
+ React-CoreModules: 4016d3a4e518bcfc4f5a51252b5a05692ca6f0e1
+ React-cxxreact: ffc9129013b87cb36cf3f30a86695a3c397b0f99
+ React-jsi: df07aa95b39c5be3e41199921509bfa929ed2b9d
+ React-jsiexecutor: b56c03e61c0dd5f5801255f2160a815f4a53d451
+ React-jsinspector: 8e68ffbfe23880d3ee9bafa8be2777f60b25cbe2
+ React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa
+ React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2
+ React-RCTBlob: 0b284339cbe4b15705a05e2313a51c6d8b51fa40
+ React-RCTImage: d1756599ebd4dc2cb19d1682fe67c6b976658387
+ React-RCTLinking: 9af0a51c6d6a4dd1674daadafffc6d03033a6d18
+ React-RCTNetwork: 332c83929cc5eae0b3bbca4add1d668e1fc18bda
+ React-RCTSettings: d6953772cfd55f2c68ad72b7ef29efc7ec49f773
+ React-RCTText: 65a6de06a7389098ce24340d1d3556015c38f746
+ React-RCTVibration: 8e9fb25724a0805107fc1acc9075e26f814df454
+ ReactCommon: 4167844018c9ed375cc01a843e9ee564399e53c3
+ RNCPushNotificationIOS: 87b8d16d3ede4532745e05b03c42cff33a36cc45
+ Yoga: 7d13633d129fd179e01b8953d38d47be90db185a
+
+PODFILE CHECKSUM: 9f7efe26f7ad5184f28ac62478069370942924e2
+
+COCOAPODS: 1.11.2
diff --git a/example/ios/example-tvOS/Info.plist b/example/ios/example-tvOS/Info.plist
index 2fb6a11c2..ecbd496be 100644
--- a/example/ios/example-tvOS/Info.plist
+++ b/example/ios/example-tvOS/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable$(EXECUTABLE_NAME)CFBundleIdentifier
- org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)CFBundleInfoDictionaryVersion6.0CFBundleName
@@ -22,6 +22,19 @@
1LSRequiresIPhoneOS
+ NSAppTransportSecurity
+
+ NSExceptionDomains
+
+ localhost
+
+ NSExceptionAllowsInsecureHTTPLoads
+
+
+
+
+ NSLocationWhenInUseUsageDescription
+ UILaunchStoryboardNameLaunchScreenUIRequiredDeviceCapabilities
@@ -36,19 +49,5 @@
UIViewControllerBasedStatusBarAppearance
- NSLocationWhenInUseUsageDescription
-
- NSAppTransportSecurity
-
-
- NSExceptionDomains
-
- localhost
-
- NSExceptionAllowsInsecureHTTPLoads
-
-
-
-
diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj
index 777fdb18f..bc6e7614d 100644
--- a/example/ios/example.xcodeproj/project.pbxproj
+++ b/example/ios/example.xcodeproj/project.pbxproj
@@ -7,75 +7,23 @@
objects = {
/* Begin PBXBuildFile section */
- 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
- 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
- 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
- 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
- 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
- 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
- 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
- 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
- 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
- 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
- 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
- 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
- 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; };
- 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
- 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
- 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D16E6891FA4F8E400B85C8A /* libReact.a */; };
2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
- 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
- 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
- 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
- ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
+ 3997B5ABB1D8AA3BF2205130 /* libPods-example-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ACCB69D76B81B3D29BE3BB2B /* libPods-example-tvOSTests.a */; };
+ 4303B027D05E61B36AF2D9DA /* libPods-example-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D89C42625470FE853701396C /* libPods-example-tvOS.a */; };
+ 4BF20923B09DA7D7C7D74054 /* libPods-example-exampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F3EFF15EA907A6500887787 /* libPods-example-exampleTests.a */; };
+ 66172E2B135131DB9C88C137 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67C595176EF92CCFA00C1943 /* libPods-example.a */; };
+ AECB905824658DC600ED1B83 /* sample.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = AECB905724658DC600ED1B83 /* sample.mp3 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTActionSheet;
- };
- 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTGeolocation;
- };
- 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
- remoteInfo = RCTImage;
- };
- 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B511DB1A9E6C8500147676;
- remoteInfo = RCTNetwork;
- };
- 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
- remoteInfo = RCTVibration;
- };
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
@@ -83,27 +31,6 @@
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = example;
};
- 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTSettings;
- };
- 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
- remoteInfo = RCTWebSocket;
- };
- 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
- remoteInfo = React;
- };
2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
@@ -111,223 +38,13 @@
remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
remoteInfo = "example-tvOS";
};
- 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = ADD01A681E09402E00F6D226;
- remoteInfo = "RCTBlob-tvOS";
- };
- 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
- remoteInfo = fishhook;
- };
- 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
- remoteInfo = "fishhook-tvOS";
- };
- 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = EBF21BDC1FC498900052F4D5;
- remoteInfo = jsinspector;
- };
- 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5;
- remoteInfo = "jsinspector-tvOS";
- };
- 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
- remoteInfo = "third-party";
- };
- 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
- remoteInfo = "third-party-tvOS";
- };
- 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 139D7E881E25C6D100323FB7;
- remoteInfo = "double-conversion";
- };
- 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D383D621EBD27B9005632C8;
- remoteInfo = "double-conversion-tvOS";
- };
- 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
- remoteInfo = privatedata;
- };
- 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
- remoteInfo = "privatedata-tvOS";
- };
- 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
- remoteInfo = "RCTImage-tvOS";
- };
- 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28471D9B043800D4039D;
- remoteInfo = "RCTLinking-tvOS";
- };
- 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
- remoteInfo = "RCTNetwork-tvOS";
- };
- 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28611D9B046600D4039D;
- remoteInfo = "RCTSettings-tvOS";
- };
- 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
- remoteInfo = "RCTText-tvOS";
- };
- 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28881D9B049200D4039D;
- remoteInfo = "RCTWebSocket-tvOS";
- };
- 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
- remoteInfo = "React-tvOS";
- };
- 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
- remoteInfo = yoga;
- };
- 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
- remoteInfo = "yoga-tvOS";
- };
- 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
- remoteInfo = cxxreact;
- };
- 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
- remoteInfo = "cxxreact-tvOS";
- };
- 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
- remoteInfo = jschelpers;
- };
- 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
- remoteInfo = "jschelpers-tvOS";
- };
- 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTAnimation;
- };
- 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
- remoteInfo = "RCTAnimation-tvOS";
- };
- 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTLinking;
- };
- 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B5119B1A9E6C1200147676;
- remoteInfo = RCTText;
- };
- ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
- remoteInfo = RCTBlob;
- };
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
- 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; };
- 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; };
- 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; };
- 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; };
- 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; };
00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = ""; };
- 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; };
- 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; };
13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = ""; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/AppDelegate.m; sourceTree = ""; };
@@ -335,14 +52,24 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = ""; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; };
- 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; };
+ 15BD6A0C81A3E52CBA666C17 /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = ""; };
2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; };
- 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; };
- 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; };
- ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; };
+ 2F3EFF15EA907A6500887787 /* libPods-example-exampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-exampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 37D30ECBCC5696F54DDBDB07 /* Pods-example-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.release.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.release.xcconfig"; sourceTree = ""; };
+ 454237A3C32EB61EE42721D8 /* Pods-example-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.debug.xcconfig"; sourceTree = ""; };
+ 52FCA686CB54A0F6E8129E44 /* Pods-example-exampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-exampleTests.debug.xcconfig"; path = "Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests.debug.xcconfig"; sourceTree = ""; };
+ 566FF18746355BDCE5A6333B /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = ""; };
+ 67C595176EF92CCFA00C1943 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 68FB3463CAEF28E88730ADEE /* Pods-example-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.release.xcconfig"; sourceTree = ""; };
+ ACCB69D76B81B3D29BE3BB2B /* libPods-example-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ AECB905724658DC600ED1B83 /* sample.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = sample.mp3; sourceTree = ""; };
+ AED90B1C243E6D21006F11F7 /* example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = example.entitlements; path = example/example.entitlements; sourceTree = ""; };
+ B43E6CF3919EF7ACAF9CC8B7 /* Pods-example-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.debug.xcconfig"; sourceTree = ""; };
+ C528DBA88EA5CBFA010ECC73 /* Pods-example-exampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-exampleTests.release.xcconfig"; path = "Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests.release.xcconfig"; sourceTree = ""; };
+ D89C42625470FE853701396C /* libPods-example-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
+ ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -350,7 +77,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */,
+ 4BF20923B09DA7D7C7D74054 /* libPods-example-exampleTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -358,19 +85,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */,
- 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */,
- 146834051AC3E58100842450 /* libReact.a in Frameworks */,
- 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */,
- 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
- 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
- 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
- 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
- 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
- 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
- 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
- 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
- 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
+ 66172E2B135131DB9C88C137 /* libPods-example.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -378,14 +93,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */,
- 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */,
- 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
- 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
- 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
- 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
- 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
- 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
+ 4303B027D05E61B36AF2D9DA /* libPods-example-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -393,55 +101,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */,
+ 3997B5ABB1D8AA3BF2205130 /* libPods-example-tvOSTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 00C302B61ABCB90400DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 00C302BC1ABCB91800DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
- 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 00C302D41ABCB9D200DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
- 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
- );
- name = Products;
- sourceTree = "";
- };
00E356EF1AD99517003FC87E /* exampleTests */ = {
isa = PBXGroup;
children = (
@@ -459,29 +125,11 @@
name = "Supporting Files";
sourceTree = "";
};
- 139105B71AF99BAD00B5F7CC /* Products */ = {
- isa = PBXGroup;
- children = (
- 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
- 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 139FDEE71B06529A00C62182 /* Products */ = {
- isa = PBXGroup;
- children = (
- 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
- 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
- 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */,
- 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
13B07FAE1A68108700A75B9A /* example */ = {
isa = PBXGroup;
children = (
+ AECB905724658DC600ED1B83 /* sample.mp3 */,
+ AED90B1C243E6D21006F11F7 /* example.entitlements */,
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
@@ -493,83 +141,26 @@
name = example;
sourceTree = "";
};
- 146834001AC3E56700842450 /* Products */ = {
- isa = PBXGroup;
- children = (
- 146834041AC3E56700842450 /* libReact.a */,
- 3DAD3EA31DF850E9000B6D8A /* libReact.a */,
- 3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
- 3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
- 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
- 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
- 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
- 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
- 2DF0FFDF2056DD460020B375 /* libjsinspector.a */,
- 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */,
- 2DF0FFE32056DD460020B375 /* libthird-party.a */,
- 2DF0FFE52056DD460020B375 /* libthird-party.a */,
- 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */,
- 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */,
- 2DF0FFEB2056DD460020B375 /* libprivatedata.a */,
- 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
- 2D16E6891FA4F8E400B85C8A /* libReact.a */,
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
+ ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
+ 67C595176EF92CCFA00C1943 /* libPods-example.a */,
+ 2F3EFF15EA907A6500887787 /* libPods-example-exampleTests.a */,
+ D89C42625470FE853701396C /* libPods-example-tvOS.a */,
+ ACCB69D76B81B3D29BE3BB2B /* libPods-example-tvOSTests.a */,
);
name = Frameworks;
sourceTree = "";
};
- 5E91572E1DD0AC6500FF2AA8 /* Products */ = {
- isa = PBXGroup;
- children = (
- 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
- 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 78C398B11ACF4ADC00677621 /* Products */ = {
- isa = PBXGroup;
- children = (
- 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
- 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
- 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
- 146833FF1AC3E56700842450 /* React.xcodeproj */,
- 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
- ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */,
- 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
- 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
- 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
- 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
- 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
- 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
- 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
- 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
);
name = Libraries;
sourceTree = "";
};
- 832341B11AAA6A8300B99B32 /* Products */ = {
- isa = PBXGroup;
- children = (
- 832341B51AAA6A8300B99B32 /* libRCTText.a */,
- 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
- );
- name = Products;
- sourceTree = "";
- };
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@@ -578,6 +169,7 @@
00E356EF1AD99517003FC87E /* exampleTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
+ AD372BDC7243AEAD7BA39FD9 /* Pods */,
);
indentWidth = 2;
sourceTree = "";
@@ -595,13 +187,19 @@
name = Products;
sourceTree = "";
};
- ADBDB9201DFEBF0600ED6528 /* Products */ = {
+ AD372BDC7243AEAD7BA39FD9 /* Pods */ = {
isa = PBXGroup;
children = (
- ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */,
- 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */,
- );
- name = Products;
+ 15BD6A0C81A3E52CBA666C17 /* Pods-example.debug.xcconfig */,
+ 566FF18746355BDCE5A6333B /* Pods-example.release.xcconfig */,
+ 52FCA686CB54A0F6E8129E44 /* Pods-example-exampleTests.debug.xcconfig */,
+ C528DBA88EA5CBFA010ECC73 /* Pods-example-exampleTests.release.xcconfig */,
+ B43E6CF3919EF7ACAF9CC8B7 /* Pods-example-tvOS.debug.xcconfig */,
+ 37D30ECBCC5696F54DDBDB07 /* Pods-example-tvOS.release.xcconfig */,
+ 454237A3C32EB61EE42721D8 /* Pods-example-tvOSTests.debug.xcconfig */,
+ 68FB3463CAEF28E88730ADEE /* Pods-example-tvOSTests.release.xcconfig */,
+ );
+ path = Pods;
sourceTree = "";
};
/* End PBXGroup section */
@@ -611,9 +209,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */;
buildPhases = (
+ B0ED5983C06627818B5DC217 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
+ CEF8B2703D93599E45D6BF6B /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -629,17 +229,20 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
buildPhases = (
+ 2DCA07023D4AA069A0C9D6BE /* [CP] Check Pods Manifest.lock */,
+ FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
+ 14C94C1C1903F2189AE891A6 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = example;
- productName = "Hello World";
+ productName = example;
productReference = 13B07F961A680F5B00A75B9A /* example.app */;
productType = "com.apple.product-type.application";
};
@@ -647,6 +250,8 @@
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */;
buildPhases = (
+ 8F6D0FED697FE82D2DF59178 /* [CP] Check Pods Manifest.lock */,
+ FD10A7F122414F3F0027D42C /* Start Packager */,
2D02E4771E0B4A5D006451C7 /* Sources */,
2D02E4781E0B4A5D006451C7 /* Frameworks */,
2D02E4791E0B4A5D006451C7 /* Resources */,
@@ -665,6 +270,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */;
buildPhases = (
+ 5313D15A4BFFB977CEC741B2 /* [CP] Check Pods Manifest.lock */,
2D02E48C1E0B4A5D006451C7 /* Sources */,
2D02E48D1E0B4A5D006451C7 /* Frameworks */,
2D02E48E1E0B4A5D006451C7 /* Resources */,
@@ -685,13 +291,15 @@
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0610;
- ORGANIZATIONNAME = Facebook;
+ LastUpgradeCheck = 1130;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
+ 13B07F861A680F5B00A75B9A = {
+ LastSwiftMigration = 1120;
+ };
2D02E47A1E0B4A5D006451C7 = {
CreatedOnToolsVersion = 8.2.1;
ProvisioningStyle = Automatic;
@@ -705,7 +313,7 @@
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */;
compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
+ developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -714,56 +322,6 @@
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
- projectReferences = (
- {
- ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
- ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
- },
- {
- ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
- ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- },
- {
- ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */;
- ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- },
- {
- ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
- ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
- },
- {
- ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
- ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- },
- {
- ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
- ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- },
- {
- ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
- ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- },
- {
- ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
- ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- },
- {
- ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
- ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- },
- {
- ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
- ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
- },
- {
- ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
- ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- },
- {
- ProductGroup = 146834001AC3E56700842450 /* Products */;
- ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- },
- );
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* example */,
@@ -774,268 +332,6 @@
};
/* End PBXProject section */
-/* Begin PBXReferenceProxy section */
- 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTActionSheet.a;
- remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTGeolocation.a;
- remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTImage.a;
- remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTNetwork.a;
- remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTVibration.a;
- remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTSettings.a;
- remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTWebSocket.a;
- remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 146834041AC3E56700842450 /* libReact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libReact.a;
- remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTBlob-tvOS.a";
- remoteRef = 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libfishhook.a;
- remoteRef = 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libfishhook-tvOS.a";
- remoteRef = 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFDF2056DD460020B375 /* libjsinspector.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjsinspector.a;
- remoteRef = 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libjsinspector-tvOS.a";
- remoteRef = 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE32056DD460020B375 /* libthird-party.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libthird-party.a";
- remoteRef = 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE52056DD460020B375 /* libthird-party.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libthird-party.a";
- remoteRef = 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libdouble-conversion.a";
- remoteRef = 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libdouble-conversion.a";
- remoteRef = 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFEB2056DD460020B375 /* libprivatedata.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libprivatedata.a;
- remoteRef = 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libprivatedata-tvOS.a";
- remoteRef = 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTImage-tvOS.a";
- remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTLinking-tvOS.a";
- remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTNetwork-tvOS.a";
- remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTSettings-tvOS.a";
- remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTText-tvOS.a";
- remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTWebSocket-tvOS.a";
- remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libReact.a;
- remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libyoga.a;
- remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libyoga.a;
- remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libcxxreact.a;
- remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libcxxreact.a;
- remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjschelpers.a;
- remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjschelpers.a;
- remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTAnimation.a;
- remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTAnimation.a;
- remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTLinking.a;
- remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTText.a;
- remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTBlob.a;
- remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
-/* End PBXReferenceProxy section */
-
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
@@ -1050,6 +346,7 @@
files = (
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
+ AECB905824658DC600ED1B83 /* sample.mp3 in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1085,6 +382,24 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
+ 14C94C1C1903F2189AE891A6 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1099,6 +414,150 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
+ 2DCA07023D4AA069A0C9D6BE /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 5313D15A4BFFB977CEC741B2 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-example-tvOSTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 8F6D0FED697FE82D2DF59178 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-example-tvOS-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ B0ED5983C06627818B5DC217 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-example-exampleTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ CEF8B2703D93599E45D6BF6B /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ FD10A7F022414F080027D42C /* Start Packager */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Start Packager";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+ FD10A7F122414F3F0027D42C /* Start Packager */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Start Packager";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -1166,6 +625,7 @@
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 52FCA686CB54A0F6E8129E44 /* Pods-example-exampleTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -1178,7 +638,9 @@
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
+ "$(inherited)",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
};
@@ -1186,6 +648,7 @@
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = C528DBA88EA5CBFA010ECC73 /* Pods-example-exampleTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
@@ -1195,7 +658,9 @@
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
+ "$(inherited)",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
};
@@ -1203,10 +668,17 @@
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 15BD6A0C81A3E52CBA666C17 /* Pods-example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = example/example.entitlements;
CURRENT_PROJECT_VERSION = 1;
- DEAD_CODE_STRIPPING = NO;
+ ENABLE_BITCODE = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "FB_SONARKIT_ENABLED=1",
+ );
INFOPLIST_FILE = example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
@@ -1214,15 +686,21 @@
"-ObjC",
"-lc++",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = example;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 566FF18746355BDCE5A6333B /* Pods-example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = example/example.entitlements;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -1231,13 +709,16 @@
"-ObjC",
"-lc++",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = example;
+ SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
2D02E4971E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = B43E6CF3919EF7ACAF9CC8B7 /* Pods-example-tvOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@@ -1251,10 +732,11 @@
INFOPLIST_FILE = "example-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
+ "$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.example-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
@@ -1264,6 +746,7 @@
};
2D02E4981E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 37D30ECBCC5696F54DDBDB07 /* Pods-example-tvOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@@ -1277,10 +760,11 @@
INFOPLIST_FILE = "example-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
+ "$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.example-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
@@ -1290,6 +774,7 @@
};
2D02E4991E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 454237A3C32EB61EE42721D8 /* Pods-example-tvOSTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -1302,10 +787,11 @@
INFOPLIST_FILE = "example-tvOSTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
+ "$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.example-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
@@ -1315,6 +801,7 @@
};
2D02E49A1E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 68FB3463CAEF28E88730ADEE /* Pods-example-tvOSTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -1327,10 +814,11 @@
INFOPLIST_FILE = "example-tvOSTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
+ "$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.example-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
@@ -1342,24 +830,37 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -1373,6 +874,12 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
+ LIBRARY_SEARCH_PATHS = (
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+ "\"$(inherited)\"",
+ );
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -1383,17 +890,28 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -1401,6 +919,7 @@
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1408,6 +927,12 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
+ LIBRARY_SEARCH_PATHS = (
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+ "\"$(inherited)\"",
+ );
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme
index a36391c90..8046697ed 100644
--- a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme
+++ b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme
@@ -1,25 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 000000000..18d981003
--- /dev/null
+++ b/example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/example/ios/example/AppDelegate.h b/example/ios/example/AppDelegate.h
index d4f2580b1..3c1381ce7 100644
--- a/example/ios/example/AppDelegate.h
+++ b/example/ios/example/AppDelegate.h
@@ -1,14 +1,8 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
+#import
#import
+#import
-@interface AppDelegate : UIResponder
-
+@interface AppDelegate : UIResponder
@property (nonatomic, strong) UIWindow *window;
@end
diff --git a/example/ios/example/AppDelegate.m b/example/ios/example/AppDelegate.m
index eba94f353..117e74e33 100644
--- a/example/ios/example/AppDelegate.m
+++ b/example/ios/example/AppDelegate.m
@@ -1,27 +1,30 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
#import "AppDelegate.h"
+#import
#import
#import
+#import
+#import
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
- NSURL *jsCodeLocation;
- jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
+ RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"example"
+ initialProperties:nil];
- RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
- moduleName:@"example"
- initialProperties:nil
- launchOptions:launchOptions];
+ // Define UNUserNotificationCenter
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+
+ [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)completionHandler:^(BOOL granted, NSError * _Nullable error) {
+ if (granted) {
+ center.delegate = self;
+ }
+ }];
+
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
@@ -32,4 +35,55 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
return YES;
}
+-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
+{
+ completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
+}
+
+// Required to register for notifications
+- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
+{
+ [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
+}
+// Required for the register event.
+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
+{
+ [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+}
+// Required for the notification event. You must call the completion handler after handling the remote notification.
+- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
+fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
+{
+ [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
+}
+// Required for the registrationError event.
+- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
+{
+ [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
+}
+
+// IOS 10+ Required for localNotification event
+- (void)userNotificationCenter:(UNUserNotificationCenter *)center
+didReceiveNotificationResponse:(UNNotificationResponse *)response
+ withCompletionHandler:(void (^)(void))completionHandler
+{
+ [RNCPushNotificationIOS didReceiveNotificationResponse:response];
+ completionHandler();
+}
+
+// IOS 4-10 Required for the localNotification event.
+- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+{
+ [RNCPushNotificationIOS didReceiveLocalNotification:notification];
+}
+
+- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
+{
+#if DEBUG
+ return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
+#else
+ return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
+#endif
+}
+
@end
diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json
index 118c98f74..81213230d 100644
--- a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -2,37 +2,52 @@
"images" : [
{
"idiom" : "iphone",
- "size" : "29x29",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "20x20"
},
{
"idiom" : "iphone",
- "size" : "29x29",
- "scale" : "3x"
+ "scale" : "3x",
+ "size" : "20x20"
},
{
"idiom" : "iphone",
- "size" : "40x40",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "29x29"
},
{
"idiom" : "iphone",
- "size" : "40x40",
- "scale" : "3x"
+ "scale" : "3x",
+ "size" : "29x29"
},
{
"idiom" : "iphone",
- "size" : "60x60",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "40x40"
},
{
"idiom" : "iphone",
- "size" : "60x60",
- "scale" : "3x"
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "idiom" : "ios-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
}
],
"info" : {
- "version" : 1,
- "author" : "xcode"
+ "author" : "xcode",
+ "version" : 1
}
-}
\ No newline at end of file
+}
diff --git a/example/ios/example/Info.plist b/example/ios/example/Info.plist
index 44e178a6f..173ee5c0a 100644
--- a/example/ios/example/Info.plist
+++ b/example/ios/example/Info.plist
@@ -9,7 +9,7 @@
CFBundleExecutable$(EXECUTABLE_NAME)CFBundleIdentifier
- org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)CFBundleInfoDictionaryVersion6.0CFBundleName
@@ -24,6 +24,27 @@
1LSRequiresIPhoneOS
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+ NSExceptionDomains
+
+ localhost
+
+ NSExceptionAllowsInsecureHTTPLoads
+
+
+
+
+ NSLocationWhenInUseUsageDescription
+
+ UIBackgroundModes
+
+ fetch
+ processing
+ remote-notification
+ UILaunchStoryboardNameLaunchScreenUIRequiredDeviceCapabilities
@@ -38,19 +59,5 @@
UIViewControllerBasedStatusBarAppearance
- NSLocationWhenInUseUsageDescription
-
- NSAppTransportSecurity
-
-
- NSExceptionDomains
-
- localhost
-
- NSExceptionAllowsInsecureHTTPLoads
-
-
-
-
diff --git a/example/ios/example/example.entitlements b/example/ios/example/example.entitlements
new file mode 100644
index 000000000..903def2af
--- /dev/null
+++ b/example/ios/example/example.entitlements
@@ -0,0 +1,8 @@
+
+
+
+
+ aps-environment
+ development
+
+
diff --git a/example/ios/example/main.m b/example/ios/example/main.m
index c73e00625..b1df44b95 100644
--- a/example/ios/example/main.m
+++ b/example/ios/example/main.m
@@ -1,10 +1,3 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
#import
#import "AppDelegate.h"
diff --git a/example/ios/exampleTests/Info.plist b/example/ios/exampleTests/Info.plist
index 886825ccc..ba72822e8 100644
--- a/example/ios/exampleTests/Info.plist
+++ b/example/ios/exampleTests/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable$(EXECUTABLE_NAME)CFBundleIdentifier
- org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)CFBundleInfoDictionaryVersion6.0CFBundleName
diff --git a/example/ios/exampleTests/exampleTests.m b/example/ios/exampleTests/exampleTests.m
index 8c594de06..9809b80c3 100644
--- a/example/ios/exampleTests/exampleTests.m
+++ b/example/ios/exampleTests/exampleTests.m
@@ -1,10 +1,3 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
#import
#import
@@ -12,7 +5,7 @@
#import
#define TIMEOUT_SECONDS 600
-#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
+#define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface exampleTests : XCTestCase
@@ -40,11 +33,13 @@ - (void)testRendersWelcomeScreen
BOOL foundElement = NO;
__block NSString *redboxError = nil;
+#ifdef DEBUG
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
+#endif
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
@@ -58,7 +53,9 @@ - (void)testRendersWelcomeScreen
}];
}
+#ifdef DEBUG
RCTSetLogFunction(RCTDefaultLogFunction);
+#endif
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
diff --git a/example/ios/sample.mp3 b/example/ios/sample.mp3
new file mode 100644
index 000000000..4569ff11f
Binary files /dev/null and b/example/ios/sample.mp3 differ
diff --git a/example/metro.config.js b/example/metro.config.js
new file mode 100644
index 000000000..13a964217
--- /dev/null
+++ b/example/metro.config.js
@@ -0,0 +1,17 @@
+/**
+ * Metro configuration for React Native
+ * https://github.com/facebook/react-native
+ *
+ * @format
+ */
+
+module.exports = {
+ transformer: {
+ getTransformOptions: async () => ({
+ transform: {
+ experimentalImportSupport: false,
+ inlineRequires: false,
+ },
+ }),
+ },
+};
diff --git a/example/package.json b/example/package.json
index 4e90e315d..5710b7cd2 100644
--- a/example/package.json
+++ b/example/package.json
@@ -3,19 +3,28 @@
"version": "0.0.1",
"private": true,
"scripts": {
- "start": "node node_modules/react-native/local-cli/cli.js start",
- "test": "jest"
+ "android": "react-native run-android",
+ "ios": "react-native run-ios",
+ "start": "react-native start",
+ "test": "jest",
+ "lint": "eslint .",
+ "pod-install": "cd ios && pod install"
},
"dependencies": {
- "react": "16.4.1",
- "react-native": "0.56.0",
- "react-native-push-notification": "git+https://git@github.com/zo0r/react-native-push-notification.git"
+ "@react-native-community/push-notification-ios": "^1.10.1",
+ "react": "16.13.1",
+ "react-native": "0.63.3",
+ "react-native-push-notification": "zo0r/react-native-push-notification#dev"
},
"devDependencies": {
- "babel-jest": "23.4.0",
- "babel-preset-react-native": "^5",
- "jest": "23.4.1",
- "react-test-renderer": "16.4.1"
+ "@babel/core": "^7.9.0",
+ "@babel/runtime": "^7.9.2",
+ "@react-native-community/eslint-config": "^1.0.0",
+ "babel-jest": "^25.3.0",
+ "eslint": "^6.8.0",
+ "jest": "^25.3.0",
+ "metro-react-native-babel-preset": "^0.59.0",
+ "react-test-renderer": "16.11.0"
},
"jest": {
"preset": "react-native"
diff --git a/index.js b/index.js
index e43141fdb..716ea0ed2 100644
--- a/index.js
+++ b/index.js
@@ -4,292 +4,505 @@
'use strict';
-var RNNotificationsComponent = require( './component' );
-
-var AppState = RNNotificationsComponent.state;
-var RNNotifications = RNNotificationsComponent.component;
-
-var Platform = require('react-native').Platform;
-
-var Notifications = {
- handler: RNNotifications,
- onRegister: false,
- onError: false,
- onNotification: false,
+import { AppState, Platform } from 'react-native';
+import { component } from './component';
+
+const Notifications = {
+ handler: component,
+ onRegister: false,
+ onRegistrationError: false,
+ onNotification: false,
+ onAction: false,
onRemoteFetch: false,
- isLoaded: false,
- hasPoppedInitialNotification: false,
+ isLoaded: false,
+ isPopInitialNotification: false,
- isPermissionsRequestPending: false,
+ isPermissionsRequestPending: false,
- permissions: {
- alert: true,
- badge: true,
- sound: true
- }
+ permissions: {
+ alert: true,
+ badge: true,
+ sound: true
+ }
};
-Notifications.callNative = function(name: String, params: Array) {
- if ( typeof this.handler[name] === 'function' ) {
- if ( typeof params !== 'array' &&
- typeof params !== 'object' ) {
- params = [];
- }
-
- return this.handler[name](...params);
- } else {
- return null;
- }
+Notifications.callNative = function(name, params) {
+ if ( typeof this.handler[name] === 'function' ) {
+ if ( typeof params !== 'array' &&
+ typeof params !== 'object' ) {
+ params = [];
+ }
+
+ return this.handler[name](...params);
+ } else {
+ return null;
+ }
};
/**
* Configure local and remote notifications
- * @param {Object} options
- * @param {function} options.onRegister - Fired when the user registers for remote notifications.
- * @param {function} options.onNotification - Fired when a remote notification is received.
- * @param {function} options.onError - None
- * @param {Object} options.permissions - Permissions list
- * @param {Boolean} options.requestPermissions - Check permissions when register
+ * @param {Object} options
+ * @param {function} options.onRegister - Fired when the user registers for remote notifications.
+ * @param {function} options.onNotification - Fired when a remote notification is received.
+ * @param {function} options.onAction - Fired when a remote notification is received.
+ * @param {function} options.onRegistrationError - Fired when the user fails to register for remote notifications.
+ * @param {Object} options.permissions - Permissions list
+ * @param {Boolean} options.requestPermissions - Check permissions when register
*/
-Notifications.configure = function(options: Object) {
- if ( typeof options.onRegister !== 'undefined' ) {
- this.onRegister = options.onRegister;
- }
-
- if ( typeof options.onError !== 'undefined' ) {
- this.onError = options.onError;
- }
-
- if ( typeof options.onNotification !== 'undefined' ) {
- this.onNotification = options.onNotification;
- }
-
- if ( typeof options.permissions !== 'undefined' ) {
- this.permissions = options.permissions;
- }
-
- if ( typeof options.senderID !== 'undefined' ) {
- this.senderID = options.senderID;
- }
-
- if ( typeof options.onRemoteFetch !== 'undefined' ) {
- this.onRemoteFetch = options.onRemoteFetch;
- }
-
- if ( this.isLoaded === false ) {
- this._onRegister = this._onRegister.bind(this);
- this._onNotification = this._onNotification.bind(this);
- this._onRemoteFetch = this._onRemoteFetch.bind(this);
- this.callNative( 'addEventListener', [ 'register', this._onRegister ] );
- this.callNative( 'addEventListener', [ 'notification', this._onNotification ] );
- this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] );
- Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null
-
- this.isLoaded = true;
- }
-
- if ( this.hasPoppedInitialNotification === false &&
- ( options.popInitialNotification === undefined || options.popInitialNotification === true ) ) {
- this.popInitialNotification(function(firstNotification) {
- if ( firstNotification !== null ) {
- this._onNotification(firstNotification, true);
- }
- }.bind(this));
- this.hasPoppedInitialNotification = true;
- }
-
- if ( options.requestPermissions !== false ) {
- this._requestPermissions();
- }
-
+Notifications.configure = function(options) {
+ if ( typeof options.onRegister !== 'undefined' ) {
+ this.onRegister = options.onRegister;
+ }
+
+ if ( typeof options.onRegistrationError !== 'undefined' ) {
+ this.onRegistrationError = options.onRegistrationError;
+ }
+
+ if ( typeof options.onNotification !== 'undefined' ) {
+ this.onNotification = options.onNotification;
+ }
+
+ if ( typeof options.onAction !== 'undefined' ) {
+ this.onAction = options.onAction;
+ }
+
+ if ( typeof options.permissions !== 'undefined' ) {
+ this.permissions = options.permissions;
+ }
+
+ if ( typeof options.onRemoteFetch !== 'undefined' ) {
+ this.onRemoteFetch = options.onRemoteFetch;
+ }
+
+ if ( this.isLoaded === false ) {
+ this._onRegister = this._onRegister.bind(this);
+ this._onRegistrationError = this._onRegistrationError.bind(this);
+ this._onNotification = this._onNotification.bind(this);
+ this._onRemoteFetch = this._onRemoteFetch.bind(this);
+ this._onAction = this._onAction.bind(this);
+ this.callNative( 'addEventListener', [ 'register', this._onRegister ] );
+ this.callNative( 'addEventListener', [ 'registrationError', this._onRegistrationError ] );
+ this.callNative( 'addEventListener', [ 'notification', this._onNotification ] );
+ this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] );
+ Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'action', this._onAction ] ) : null
+ Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null
+
+ this.isLoaded = true;
+ }
+
+ const handlePopInitialNotification = (state) => {
+ if('active' !== state) {
+ return;
+ }
+
+ if (options.popInitialNotification === undefined || options.popInitialNotification === true) {
+ this.popInitialNotification(function(firstNotification) {
+ if(this.isPopInitialNotification) {
+ return;
+ }
+
+ this.isPopInitialNotification = true;
+
+ if (!firstNotification || false === firstNotification.userInteraction) {
+ return;
+ }
+
+ this._onNotification(firstNotification, true);
+ }.bind(this));
+ }
+ }
+
+ AppState.addEventListener('change', handlePopInitialNotification.bind(this));
+
+ handlePopInitialNotification(AppState.currentState);
+
+ if ( options.requestPermissions !== false ) {
+ this._requestPermissions();
+ }
};
/* Unregister */
Notifications.unregister = function() {
- this.callNative( 'removeEventListener', [ 'register', this._onRegister ] )
- this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] )
- this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] )
- Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null
- this.isLoaded = false;
+ this.callNative( 'removeEventListener', [ 'register', this._onRegister ] )
+ this.callNative( 'removeEventListener', [ 'registrationError', this._onRegistrationError ] )
+ this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] )
+ this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] )
+ Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'action', this._onAction ] ) : null
+ Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null
+ this.isLoaded = false;
};
/**
* Local Notifications
- * @param {Object} details
- * @param {String} details.title - The title displayed in the notification alert.
- * @param {String} details.message - The message displayed in the notification alert.
- * @param {String} details.ticker - ANDROID ONLY: The ticker displayed in the status bar.
- * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert.
+ * @param {Object} details
+ * @param {String} details.title - The title displayed in the notification alert.
+ * @param {String} details.message - The message displayed in the notification alert.
+ * @param {String} details.ticker - ANDROID ONLY: The ticker displayed in the status bar.
+ * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert.
*/
-Notifications.localNotification = function(details: Object) {
- if ( Platform.OS === 'ios' ) {
- // https://developer.apple.com/reference/uikit/uilocalnotification
-
- let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour
-
- if (details.hasOwnProperty('playSound') && !details.playSound) {
- soundName = ''; // empty string results in no sound (and no vibration)
- }
-
- // for valid fields see: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html
- // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle
-
- this.handler.presentLocalNotification({
- alertTitle: details.title,
- alertBody: details.message,
- alertAction: details.alertAction,
- category: details.category,
- soundName: soundName,
- applicationIconBadgeNumber: details.number,
- userInfo: details.userInfo
- });
- } else {
- this.handler.presentLocalNotification(details);
- }
+Notifications.localNotification = function({...details}) {
+ if ('android' === Platform.OS && details && !details.channelId) {
+ console.warn('No channel id passed, notifications may not work.');
+ }
+
+ if (details && typeof details.id === 'number') {
+ if (isNaN(details.id)) {
+ console.warn('NaN value has been passed as id');
+ delete details.id;
+ }
+ else {
+ details.id = '' + details.id;
+ }
+ }
+
+ if (Platform.OS === 'ios') {
+ // https://developer.apple.com/reference/uikit/uilocalnotification
+
+ let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour
+
+ if (details.hasOwnProperty('playSound') && !details.playSound) {
+ soundName = ''; // empty string results in no sound (and no vibration)
+ }
+
+ if(details.picture) {
+ details.userInfo = details.userInfo || {};
+ details.userInfo.image = details.picture;
+ }
+
+ // for valid fields see: https://github.com/react-native-push-notification-ios/push-notification-ios#addnotificationrequest
+
+ this.handler.addNotificationRequest({
+ id: (!details.id ? Math.floor(Math.random() * Math.pow(2, 32)).toString() : details.id),
+ title: details.title,
+ subtitle: details.subtitle,
+ body: details.message,
+ badge: details.number,
+ sound: soundName,
+ isSilent: details.playSound === false,
+ category: details.category,
+ userInfo: details.userInfo
+ });
+ } else {
+ if (details && typeof details.number === 'number') {
+ if(isNaN(details.number)) {
+ console.warn('NaN value has been passed as number');
+ delete details.number;
+ }
+ else {
+ details.number = '' + details.number;
+ }
+ }
+
+ if (details && typeof details.shortcutId === 'number') {
+ if(isNaN(details.shortcutId)) {
+ console.warn('NaN value has been passed as shortcutId');
+ delete details.shortcutId;
+ }
+ else {
+ details.shortcutId = '' + details.shortcutId;
+ }
+ }
+
+ if(details && Array.isArray(details.actions)) {
+ details.actions = JSON.stringify(details.actions);
+ }
+
+ if(details.userInfo) {
+ details.userInfo = JSON.stringify(details.userInfo);
+ }
+
+ if(details.picture && !details.bigPictureUrl) {
+ details.bigPictureUrl = details.picture;
+ }
+
+ this.handler.presentLocalNotification(details);
+ }
};
/**
* Local Notifications Schedule
- * @param {Object} details (same as localNotification)
- * @param {Date} details.date - The date and time when the system should deliver the notification
+ * @param {Object} details (same as localNotification)
+ * @param {Date} details.date - The date and time when the system should deliver the notification
*/
-Notifications.localNotificationSchedule = function(details: Object) {
- if ( Platform.OS === 'ios' ) {
- let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour
-
- if (details.hasOwnProperty('playSound') && !details.playSound) {
- soundName = ''; // empty string results in no sound (and no vibration)
- }
-
- const iosDetails = {
- fireDate: details.date.toISOString(),
- alertTitle: details.title,
- alertBody: details.message,
- category: details.category,
- soundName: soundName,
- userInfo: details.userInfo,
- repeatInterval: details.repeatType
- };
-
- if(details.number) {
- iosDetails.applicationIconBadgeNumber = parseInt(details.number, 10);
- }
-
- // ignore Android only repeatType
- if (!details.repeatType || details.repeatType === 'time') {
- delete iosDetails.repeatInterval;
- }
- this.handler.scheduleLocalNotification(iosDetails);
- } else {
- details.fireDate = details.date.getTime();
- delete details.date;
- // ignore iOS only repeatType
- if (['year'].includes(details.repeatType)) {
- delete details.repeatType;
- }
- this.handler.scheduleLocalNotification(details);
- }
+Notifications.localNotificationSchedule = function({...details}) {
+ if ('android' === Platform.os && details && !details.channelId) {
+ console.warn('No channel id passed, notifications may not work.');
+ }
+
+ if (details && typeof details.id === 'number') {
+ if(isNaN(details.id)) {
+ console.warn('NaN value has been passed as id');
+ delete details.id;
+ }
+ else {
+ details.id = '' + details.id;
+ }
+ }
+
+ if (Platform.OS === 'ios') {
+ let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour
+
+ if (details.hasOwnProperty('playSound') && !details.playSound) {
+ soundName = ''; // empty string results in no sound (and no vibration)
+ }
+
+ if(details.picture) {
+ details.userInfo = details.userInfo || {};
+ details.userInfo.image = details.picture;
+ }
+
+ const repeatsComponent = {
+ second: ['minute', 'hour', 'day', 'week', 'month'].includes(details.repeatType),
+ minute: ['hour', 'day', 'week', 'month'].includes(details.repeatType),
+ hour: ['day', 'week', 'month'].includes(details.repeatType),
+ day: details.repeatType == "month",
+ dayOfWeek: details.repeatType == "week",
+ };
+
+ const iosDetails = {
+ id: (!details.id ? Math.floor(Math.random() * Math.pow(2, 32)).toString() : details.id),
+ fireDate: details.date.toISOString(),
+ title: details.title,
+ subtitle: details.subtitle,
+ body: details.message,
+ sound: soundName,
+ isSilent: details.playSound === false,
+ category: details.category,
+ userInfo: details.userInfo,
+ repeats: ['minute', 'hour', 'day', 'week', 'month'].includes(details.repeatType),
+ repeatsComponent: repeatsComponent
+ };
+
+ if (details.number) {
+ iosDetails.badge = parseInt(details.number, 10);
+ }
+
+ this.handler.addNotificationRequest(iosDetails);
+ } else {
+ if (details && typeof details.number === 'number') {
+ if (isNaN(details.number)) {
+ console.warn('NaN value has been passed as number');
+ delete details.number;
+ }
+ else {
+ details.number = '' + details.number;
+ }
+ }
+
+ if (details && typeof details.shortcutId === 'number') {
+ if (isNaN(details.shortcutId)) {
+ console.warn('NaN value has been passed as shortcutId');
+ delete details.shortcutId;
+ }
+ else {
+ details.shortcutId = '' + details.shortcutId;
+ }
+ }
+
+ if(details && Array.isArray(details.actions)) {
+ details.actions = JSON.stringify(details.actions);
+ }
+
+ if(details.userInfo) {
+ details.userInfo = JSON.stringify(details.userInfo);
+ }
+
+ if(details.picture && !details.bigPictureUrl) {
+ details.bigPictureUrl = details.picture;
+ }
+
+ details.fireDate = details.date.getTime();
+ delete details.date;
+
+ this.handler.scheduleLocalNotification(details);
+ }
};
/* Internal Functions */
-Notifications._onRegister = function(token: String) {
- if ( this.onRegister !== false ) {
- this.onRegister({
- token: token,
- os: Platform.OS
- });
- }
+Notifications._onRegister = function(token) {
+ if ( this.onRegister !== false ) {
+ this.onRegister({
+ token: token,
+ os: Platform.OS
+ });
+ }
};
-Notifications._onRemoteFetch = function(notificationData: Object) {
- if ( this.onRemoteFetch !== false ) {
- this.onRemoteFetch(notificationData)
- }
+Notifications._onRegistrationError = function(err) {
+ if ( this.onRegistrationError !== false ) {
+ this.onRegistrationError(err);
+ }
};
-Notifications._onNotification = function(data, isFromBackground = null) {
- if ( isFromBackground === null ) {
- isFromBackground = (
- data.foreground === false ||
- AppState.currentState === 'background'
- );
- }
+Notifications._onRemoteFetch = function(notificationData) {
+ if ( this.onRemoteFetch !== false ) {
+ this.onRemoteFetch(notificationData)
+ }
+};
- if ( this.onNotification !== false ) {
- if ( Platform.OS === 'ios' ) {
- this.onNotification({
- foreground: ! isFromBackground,
- userInteraction: isFromBackground,
- message: data.getMessage(),
- data: data.getData(),
- badge: data.getBadgeCount(),
- alert: data.getAlert(),
- sound: data.getSound(),
- finish: (res) => data.finish(res)
- });
- } else {
- var notificationData = {
- foreground: ! isFromBackground,
- finish: () => {},
- ...data
- };
-
- if ( typeof notificationData.data === 'string' ) {
- try {
- notificationData.data = JSON.parse(notificationData.data);
- } catch(e) {
- /* void */
- }
- }
+Notifications._onAction = function({...notification}) {
+ if ( typeof notification.data === 'string' ) {
+ try {
+ notification.data = JSON.parse(notificationData.data);
+ } catch(e) {
+ /* void */
+ }
+ }
- this.onNotification(notificationData);
- }
- }
+ this.onAction(notification);
+}
+
+Notifications._transformNotificationObject = function(data, isFromBackground = null) {
+ if(!data) {
+ return;
+ }
+
+ if ( isFromBackground === null ) {
+ isFromBackground = (
+ data.foreground === false ||
+ AppState.currentState === 'background' ||
+ AppState.currentState === 'unknown'
+ );
+ }
+
+ let _notification;
+
+ if ( Platform.OS === 'ios' ) {
+ const notifData = data.getData();
+
+ _notification = {
+ id: notifData?.id,
+ foreground: !isFromBackground,
+ userInteraction: notifData?.userInteraction === 1 || false,
+ message: data.getMessage(),
+ data: notifData,
+ badge: data.getBadgeCount(),
+ title: data.getTitle(),
+ subtitle: data.getSubtitle(),
+ soundName: data.getSound(),
+ fireDate: Date.parse(data._fireDate),
+ action: data.getActionIdentifier(),
+ reply_text: data.getUserText(),
+ finish: (res) => data.finish(res)
+ };
+
+ if(isNaN(_notification.fireDate)) {
+ delete _notification.fireDate;
+ }
+
+ } else {
+ _notification = {
+ foreground: !isFromBackground,
+ finish: () => {},
+ ...data,
+ };
+
+ if ( typeof _notification.data === 'string' ) {
+ try {
+ _notification.data = JSON.parse(_notification.data);
+ } catch(e) {
+ /* void */
+ }
+ }
+
+ if ( typeof _notification.userInfo === 'string' ) {
+ try {
+ _notification.userInfo = JSON.parse(_notification.userInfo);
+ } catch(e) {
+ /* void */
+ }
+ }
+
+
+ _notification.data = {
+ ...(typeof _notification.userInfo === 'object' ? _notification.userInfo : {}),
+ ...(typeof _notification.data === 'object' ? _notification.data : {}),
+ };
+
+ delete _notification.userInfo;
+ delete _notification.notificationId;
+ }
+
+ return _notification;
+}
+
+Notifications._onNotification = function(data, initialNotification = false) {
+ if ( this.onNotification !== false ) {
+ let notification = data;
+
+ if(!initialNotification) {
+ notification = this._transformNotificationObject(data);
+ }
+
+ this.onNotification(notification);
+ }
};
/* onResultPermissionResult */
Notifications._onPermissionResult = function() {
- this.isPermissionsRequestPending = false;
+ this.isPermissionsRequestPending = false;
};
// Prevent requestPermissions called twice if ios result is pending
Notifications._requestPermissions = function() {
- if ( Platform.OS === 'ios' ) {
- if ( this.isPermissionsRequestPending === false ) {
- this.isPermissionsRequestPending = true;
- return this.callNative( 'requestPermissions', [ this.permissions ])
- .then(this._onPermissionResult.bind(this))
- .catch(this._onPermissionResult.bind(this));
- }
- } else if ( typeof this.senderID !== 'undefined' ) {
- return this.callNative( 'requestPermissions', [ this.senderID ]);
- }
+ if ( Platform.OS === 'ios' ) {
+ if ( this.isPermissionsRequestPending === false ) {
+ this.isPermissionsRequestPending = true;
+ return this.callNative( 'requestPermissions', [ this.permissions ])
+ .then(this._onPermissionResult.bind(this))
+ .catch(this._onPermissionResult.bind(this));
+ }
+ } else if (Platform.OS === 'android') {
+ return this.callNative( 'requestPermissions', []);
+ }
};
// Stock requestPermissions function
Notifications.requestPermissions = function() {
- if ( Platform.OS === 'ios' ) {
- return this.callNative( 'requestPermissions', [ this.permissions ]);
- } else if ( typeof this.senderID !== 'undefined' ) {
- return this.callNative( 'requestPermissions', [ this.senderID ]);
- }
+ if ( Platform.OS === 'ios' ) {
+ return this.callNative( 'requestPermissions', [ this.permissions ]);
+ } else if (Platform.OS === 'android') {
+ return this.callNative( 'requestPermissions', []);
+ }
};
/* Fallback functions */
Notifications.subscribeToTopic = function() {
- return this.callNative('subscribeToTopic', arguments);
+ return this.callNative('subscribeToTopic', arguments);
+};
+
+Notifications.unsubscribeFromTopic = function () {
+ return this.callNative('unsubscribeFromTopic', arguments);
};
Notifications.presentLocalNotification = function() {
- return this.callNative('presentLocalNotification', arguments);
+ return this.callNative('presentLocalNotification', arguments);
};
Notifications.scheduleLocalNotification = function() {
- return this.callNative('scheduleLocalNotification', arguments);
+ return this.callNative('scheduleLocalNotification', arguments);
+};
+
+Notifications.cancelLocalNotifications = function(userInfo) {
+ console.warn('This method is now deprecated, please use `cancelLocalNotification` (remove the ending `s`).');
+
+ return this.cancelLocalNotification(userInfo);
};
-Notifications.cancelLocalNotifications = function() {
- return this.callNative('cancelLocalNotifications', arguments);
+Notifications.cancelLocalNotification = function(notificationId) {
+ if(typeof notificationId === 'object') {
+ notificationId = notificationId?.id;
+ }
+
+ if(typeof notificationId === 'number') {
+ notificationId = '' + notificationId;
+ }
+
+ if ( Platform.OS === 'ios' ) {
+ return this.callNative('removePendingNotificationRequests', [[notificationId]]);
+ } else {
+ return this.callNative('cancelLocalNotification', [notificationId]);
+ }
};
Notifications.clearLocalNotification = function() {
@@ -297,38 +510,137 @@ Notifications.clearLocalNotification = function() {
};
Notifications.cancelAllLocalNotifications = function() {
- return this.callNative('cancelAllLocalNotifications', arguments);
+ if ( Platform.OS === 'ios' ) {
+ return this.callNative('removeAllPendingNotificationRequests', arguments);
+ } else if (Platform.OS === 'android') {
+ return this.callNative('cancelAllLocalNotifications', arguments);
+ }
};
Notifications.setApplicationIconBadgeNumber = function() {
- return this.callNative('setApplicationIconBadgeNumber', arguments);
+ return this.callNative('setApplicationIconBadgeNumber', arguments);
};
Notifications.getApplicationIconBadgeNumber = function() {
- return this.callNative('getApplicationIconBadgeNumber', arguments);
+ return this.callNative('getApplicationIconBadgeNumber', arguments);
};
Notifications.popInitialNotification = function(handler) {
- this.callNative('getInitialNotification').then(function(result){
- handler(result);
- });
-};
-
-Notifications.abandonPermissions = function() {
- return this.callNative('abandonPermissions', arguments);
+ this.callNative('getInitialNotification').then((result) => {
+ handler(
+ this._transformNotificationObject(result, true)
+ );
+ });
};
Notifications.checkPermissions = function() {
- return this.callNative('checkPermissions', arguments);
+ return this.callNative('checkPermissions', arguments);
};
-Notifications.registerNotificationActions = function() {
- return this.callNative('registerNotificationActions', arguments)
+/* Abandon Permissions */
+Notifications.abandonPermissions = function() {
+ return this.callNative('abandonPermissions', arguments);
}
Notifications.clearAllNotifications = function() {
- // Only available for Android
- return this.callNative('clearAllNotifications', arguments)
+ // Only available for Android
+ return this.callNative('clearAllNotifications', arguments)
+}
+
+Notifications.removeAllDeliveredNotifications = function() {
+ return this.callNative('removeAllDeliveredNotifications', arguments);
+}
+
+Notifications.getDeliveredNotifications = function() {
+ return this.callNative('getDeliveredNotifications', arguments);
}
+Notifications.getScheduledLocalNotifications = function(callback) {
+ const mapNotifications = (notifications) => {
+ let mappedNotifications = [];
+ if(notifications?.length > 0) {
+ if(Platform.OS === 'ios'){
+ mappedNotifications = notifications.map(notif => {
+ return ({
+ soundName: notif?.sound,
+ id: notif.id,
+ date: (notif.date ? new Date(notif.date) : null),
+ number: notif?.badge,
+ message: notif?.body,
+ title: notif?.title,
+ data: notif?.userInfo
+ })
+ })
+ } else if(Platform.OS === 'android') {
+ mappedNotifications = notifications.map(notif => {
+
+ try {
+ notif.data = JSON.parse(notif.data);
+ } catch(e) { }
+
+ return ({
+ soundName: notif.soundName,
+ repeatInterval: notif.repeatInterval,
+ id: notif.id,
+ date: new Date(notif.date),
+ number: notif.number,
+ message: notif.message,
+ title: notif.title,
+ data: notif.data,
+ })
+ })
+ }
+ }
+ callback(mappedNotifications);
+ }
+
+ if(Platform.OS === 'ios'){
+ return this.callNative('getPendingNotificationRequests', [mapNotifications]);
+ } else {
+ return this.callNative('getScheduledLocalNotifications', [mapNotifications]);
+ }
+}
+
+Notifications.removeDeliveredNotifications = function() {
+ return this.callNative('removeDeliveredNotifications', arguments);
+}
+
+Notifications.invokeApp = function() {
+ return this.callNative('invokeApp', arguments);
+};
+
+Notifications.getChannels = function() {
+ return this.callNative('getChannels', arguments);
+};
+
+Notifications.channelExists = function() {
+ return this.callNative('channelExists', arguments);
+};
+
+Notifications.createChannel = function() {
+ return this.callNative('createChannel', arguments);
+};
+
+Notifications.channelBlocked = function() {
+ return this.callNative('channelBlocked', arguments);
+};
+
+Notifications.deleteChannel = function() {
+ return this.callNative('deleteChannel', arguments);
+};
+
+Notifications.setNotificationCategories = function() {
+ return this.callNative('setNotificationCategories', arguments);
+}
+
+// https://developer.android.com/reference/android/app/NotificationManager#IMPORTANCE_DEFAULT
+Notifications.Importance = Object.freeze({
+ DEFAULT: 3,
+ HIGH: 4,
+ LOW: 2,
+ MIN: 1,
+ NONE: 0,
+ UNSPECIFIED: -1000,
+});
+
module.exports = Notifications;
diff --git a/package.json b/package.json
index d27fcd3cb..7720b5453 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "react-native-push-notification",
- "version": "3.1.9",
+ "version": "8.1.1",
"description": "React Native Local and Remote Notifications",
- "main": "index",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
@@ -14,7 +14,7 @@
"notifications",
"push",
"apns",
- "gcm"
+ "firebase"
],
"bugs": {
"url": "https://github.com/zo0r/react-native-push-notification/issues"
@@ -23,10 +23,8 @@
"type": "git",
"url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git"
},
- "dependencies": {
- "@react-native-community/push-notification-ios": "^1.0.1"
- },
"peerDependencies": {
+ "@react-native-community/push-notification-ios": "^1.10.1",
"react-native": ">=0.33"
},
"author": "zo0r ",
diff --git a/submitting-a-pull-request.md b/submitting-a-pull-request.md
index 53e46e7ce..1d406cec8 100644
--- a/submitting-a-pull-request.md
+++ b/submitting-a-pull-request.md
@@ -1,6 +1,6 @@
## Pull Requests
-If you are thinking of, or have prepared a pull request, **thank you!** You efforts are greatly apprecaited by everyone associated with this project.
+If you are thinking of, or have prepared a pull request, **thank you!** Your efforts are greatly appreciated by everyone associated with this project.
In order to get your PR accepted please ensure the following:
@@ -23,7 +23,7 @@ If you are testing someones PR, please provide the following feedback:
* are you happy that the change in behaviour works as described, and you have tested the change on all affected operating systems?
* in your opinion, is the code written _sensibly_?
* is it clean and tidy?
- * there are and unnecessary changes?
+ * there are any unnecessary changes?
* is it documented appropriately?
-
\ No newline at end of file
+
diff --git a/trouble-shooting.md b/trouble-shooting.md
index 52a764e51..1d10fd128 100644
--- a/trouble-shooting.md
+++ b/trouble-shooting.md
@@ -7,6 +7,31 @@ Known bugs and issues:
* (Android) Tapping an alert in the notification centre will sometimes not result in `onNotification` being called [issue 281](https://github.com/zo0r/react-native-push-notification/issues/281)
* (Android) Not all local notification features are supported yet (PRs welcome)
* (iOS) The OS can penalise your app for not calling the completion handler and will stop (or delay) sending notifications to your app. This will be supported from RN-0.38 [PR 227](https://github.com/zo0r/react-native-push-notification/pull/277)
+ * (Android and iOS) Don't use a string to get the date for schedule a local notification, it only works with remote debugger enabled, [explanation](https://stackoverflow.com/a/41881765/8519917).
+
+
+ ```javascript
+ // It doesn't work with the javascript engine used by React Native
+ const date = new Date("10-10-2020 12:30");
+ ```
+ A good practice to get valid date could be:
+
+ ```javascript
+ // Get date to schedule a local notification today at 12:30:00
+ const hour = 12;
+ const minute = 30;
+ const second = 0;
+
+ const now = new Date();
+ const date = new Date(
+ now.getFullYear(),
+ now.getMonth(),
+ now.getDate(),
+ hour,
+ minute,
+ second
+ );
+ ```
# Android tips
@@ -25,7 +50,7 @@ Known bugs and issues:
# About notifications...
-There are a number of different types of notifications, and they have subtly different behaviours. There are essentially 4 types, let's call them _local notifications_ (1), _noisy remote push notifications_ (2), _silent remote push notifications_ (3) and _mixed remote push notifications_ (4).
+There are a number of different types of notifications, and they have subtly different behaviours. There are essentially 4 types, let's call them _local notifications_ (1), _noisy remote push notifications_ (2) and _silent remote push notifications_ (3).
## 1. local notifications
@@ -178,53 +203,8 @@ The crucial bit of an iOS silent notification is presence of the `"content-avail
After you have processed the notification you must call isn't `finish` method (as of RN 0.38).
-## 4. _mixed_ remote push notifications
-
-_Mixed_ remote push notifications are both delivered to your app AND to the notification center.
-
-#### Android _mixed_ remote push notifications
-
-Android doesn't directly support mixed notifications. If you try to combine the above approaches you will see a _noisy_ notification but it will not be delivered to your app. This library does however provide a basic work-around. By adding `message` field to a _silent_ notification the library will synthesize a local notification as well as deliver a _silent_ notification to your app. Something like this:
-
-```json
-{
- "to": "",
- "time_to_live": 86400,
- "collapse_key": "new_message",
- "delay_while_idle": false,
- "data": {
- "title": "title",
- "message": "this is a mixed test 14:03:29.676",
- "your-key": "your-value"
- }
-}
-```
-
-The resulting local notification will include the message as well as a few other (optional) fields: _title_, _sound_ and _colour_
-
-#### iOS _mixed_ remote push notifications
-
-Just combine the above _silent_ and _noisy_ notifications and send to APNS:
-
-```json
-{
- "aps": {
- "alert": {
- "body": "body 16:03:49.889",
- "title": "title"
- },
- "badge": 1,
- "sound": "default"
- },
- "payload": "{\"your-key\":\"your-value\"}"
-}
-```
-
-It will be delivered to both the notification centre **and** your app if the app is running in the background, but only to your app if it's running in the foreground.
-
#### Some useful links
- * http://www.fantageek.com/blog/2016/04/15/push-notification-in-practice/
* https://devcenter.verivo.com/display/doc/Handling+Push+Notifications+on+iOS
* https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1
* http://stackoverflow.com/questions/12071726/how-to-use-beginbackgroundtaskwithexpirationhandler-for-already-running-task-in