mirror of
https://github.com/zhigang1992/react-native-notifications.git
synced 2026-01-12 22:50:34 +08:00
V3 (#437)
* Add typescript support * Add unit tests * Splits requestPermissionsWithCategories to two functions * Done converting the js part to typescript * typescript WIP * Fix unit * Fix e2e * Identical API for Android and iOS * Fix bundle * build typescript before test-e2e-ios * build typescript before test-e2e-ios * Add docousaurus documentation * Fix rebase from master * Move android and ios folders into lib folder * Split Notification.ts, Fix android example module * Add test coverage for Notification.ts, clean old js files * Updated docs * Move ios and android commands to designated classes * Remove package.json unused packages * Fix e2e * Fix docs, remove circleci config file * 3.0.0-alpha.0 * Update README.md * Fix js tests * Add missing flavors * Update release script * Add pretest scripts * Update release script * Revert manual version change * Fix release build * Gradle resolve react-native version flavor * Fix documentation website * Add identical registerRemoteNotifications api for iOS and Android * Finish API documentation * Merge from master branch * Fix build * Remove NOTIFICATION_RECEIVED_FOREGROUND_EVENT_NAME * Fix iOS example project * Split specific iOS events, Update docs * Add subscription documentation guide * Add Local Notifications documentation guide * Fix handling actions, Add event handling documentation guide * Fix platforms logo * Fix iOS unit tests * Update package.json version to 3.0.0-beta.0 and generate CHANGELOG.gren.md [ci skip] * Fix documentation * Add prerelease script * Update package.json version to 3.0.0-beta.1 and generate CHANGELOG.gren.md [ci skip] * Add npm run docusaurus * Add removeAllDeliveredNotifications support for both iOS and Android * Add CI tag support * Fix podspec * Update iOS installation * Fix android installation * fix build.gradle rn package.json path * Fix iOS * Add NotificationFactory * Fix tests * Fix resolving gradle react native version * find rn package.json by checking if the file exists instead of an exception in JsonSlurper * Fix e2e * Update package.json version to 3.0.0-beta.2 and generate CHANGELOG.gren.md [ci skip] * Rename setBadgesCount to setBadgeCount * add ios and android Notifications object getters * Update package.json version to 3.0.0-beta.3 and generate CHANGELOG.gren.md [ci skip] * Fix android token registration * Update package.json version to 3.0.0-beta.4 and generate CHANGELOG.gren.md [ci skip] Co-authored-by: wixmobile <41264282+wixmobile@users.noreply.github.com> Co-authored-by: Artal Druk <artald@wix.com>
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
ios:
|
||||
macos:
|
||||
xcode: "10.2.1"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: scripts/install.ios.sh
|
||||
- run:
|
||||
name: npm install
|
||||
command: npm install
|
||||
- run:
|
||||
name: iOS unit tests
|
||||
command: 'npm run test-unit-ios'
|
||||
- run:
|
||||
name: Detox iOS e2e tests
|
||||
command: 'npm run test-e2e-ios-release'
|
||||
android:
|
||||
macos:
|
||||
xcode: "10.2.1"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Android
|
||||
command: scripts/install.android.sh
|
||||
- run:
|
||||
name: npm install
|
||||
command: npm install
|
||||
- run:
|
||||
name: Android unit tests
|
||||
command: 'npm run test-unit-android'
|
||||
workflows:
|
||||
version: 2
|
||||
test:
|
||||
jobs:
|
||||
- ios
|
||||
- android
|
||||
2
.dockerignore
Executable file
2
.dockerignore
Executable file
@@ -0,0 +1,2 @@
|
||||
*/node_modules
|
||||
*.log
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -15,8 +15,12 @@ npm-debug.log
|
||||
#####
|
||||
# Android
|
||||
|
||||
android/local.properties
|
||||
android/*.iml
|
||||
lib/android/local.properties
|
||||
lib/android/*.iml
|
||||
lib/android/.idea
|
||||
lib/android/build
|
||||
lib/android/.gradle
|
||||
*.gradle
|
||||
|
||||
#####
|
||||
# OS X temporary files that should never be committed
|
||||
@@ -187,6 +191,6 @@ coverage/
|
||||
package-lock.json
|
||||
|
||||
.history
|
||||
android/.idea
|
||||
android/build
|
||||
android/.gradle
|
||||
|
||||
# Typescript build
|
||||
lib/dist/
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
example/
|
||||
test/
|
||||
RNNotifications/DerivedData
|
||||
node_modules/
|
||||
website/
|
||||
docs/
|
||||
docs_old/
|
||||
scripts/
|
||||
e2e/
|
||||
|
||||
.eslintrc
|
||||
*.yml
|
||||
@@ -10,4 +14,5 @@ coverage/
|
||||
android/.idea
|
||||
android/build/
|
||||
.idea
|
||||
.history/
|
||||
.history/
|
||||
.github/
|
||||
@@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## 3.0.0-beta.4 (14/01/2020)
|
||||
*No changelog for this release.*
|
||||
|
||||
---
|
||||
|
||||
## 3.0.0-beta.3 (13/01/2020)
|
||||
*No changelog for this release.*
|
||||
|
||||
---
|
||||
|
||||
## 3.0.0-beta.2 (13/01/2020)
|
||||
*No changelog for this release.*
|
||||
|
||||
---
|
||||
|
||||
## 2.1.7 (14/12/2019)
|
||||
*No changelog for this release.*
|
||||
|
||||
|
||||
10
Dockerfile
Executable file
10
Dockerfile
Executable file
@@ -0,0 +1,10 @@
|
||||
FROM node:8.11.4
|
||||
|
||||
WORKDIR /app/website
|
||||
|
||||
EXPOSE 3000 35729
|
||||
COPY ./docs /app/docs
|
||||
COPY ./website /app/website
|
||||
RUN yarn install
|
||||
|
||||
CMD ["yarn", "start"]
|
||||
15
README.md
15
README.md
@@ -1,4 +1,7 @@
|
||||
# React Native Notifications [](https://circleci.com/gh/wix/react-native-notifications/tree/master)
|
||||
# React Native Notifications
|
||||

|
||||
[](https://jenkins-oss.wixpress.com/job/multi-react-native-notifications-master/)
|
||||
[](https://github.com/wix/react-native-navigation/tree/master)
|
||||
|
||||
Handle all the aspects of push notifications for your app, including remote and local notifications, interactive notifications, silent notifications, and more.
|
||||
|
||||
@@ -27,14 +30,8 @@ _For information regarding proper integration with [react-native-navigation](htt
|
||||
_Upcoming: local notifications, background-state Rx queue (iOS equivalent)_
|
||||
|
||||
|
||||
# Table of Content
|
||||
|
||||
- [Installation and setup](./docs/installation.md) - Setting up the library in your app
|
||||
- [Subscription](./docs/subscription.md) - Signing in to push notifications vendors (e.g. GCM)
|
||||
- [Notification Events (notfications core)](./docs/notificationsEvents.md) - Handling push notification arrival, notification opening by users
|
||||
- [Local notifications](./docs/localNotifications.md) - Manually triggering notifications (i.e. not via push)
|
||||
- [Advanced iOS topics](./docs/advancedIos.md) - e.g. managed notifications, PushKit API, Notifications actions
|
||||
- [Notifications layout control - Android (wiki page)](https://github.com/wix/react-native-notifications/wiki/Android:-Layout-Customization) - Learn how to fully customize your notifications layout on Android!
|
||||
# Quick Links
|
||||
- [Documentation](https://wix.github.io/react-native-notifications/)
|
||||
|
||||
# License
|
||||
The MIT License.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
static NSString* const RNRegistered = @"remoteNotificationsRegistered";
|
||||
static NSString* const RNRegistrationFailed = @"remoteNotificationsRegistrationFailed";
|
||||
static NSString* const RNPushKitRegistered = @"pushKitRegistered";
|
||||
static NSString* const RNNotificationReceivedForeground = @"notificationReceivedForeground";
|
||||
static NSString* const RNNotificationOpened = @"notificationOpened";
|
||||
static NSString* const RNPushKitNotificationReceived = @"pushKitNotificationReceived";
|
||||
|
||||
|
||||
@interface RNEventEmitter : RCTEventEmitter <RCTBridgeModule>
|
||||
|
||||
+ (void)sendEvent:(NSString *)event body:(NSDictionary *)body;
|
||||
|
||||
@end
|
||||
18
docker-compose.yml
Executable file
18
docker-compose.yml
Executable file
@@ -0,0 +1,18 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
docusaurus:
|
||||
build: .
|
||||
ports:
|
||||
- 3000:3000
|
||||
- 35729:35729
|
||||
volumes:
|
||||
- ./docs:/app/docs
|
||||
- ./website/blog:/app/website/blog
|
||||
- ./website/core:/app/website/core
|
||||
- ./website/i18n:/app/website/i18n
|
||||
- ./website/pages:/app/website/pages
|
||||
- ./website/static:/app/website/static
|
||||
- ./website/sidebars.json:/app/website/sidebars.json
|
||||
- ./website/siteConfig.js:/app/website/siteConfig.js
|
||||
working_dir: /app/website
|
||||
165
docs/advanced-ios.md
Normal file
165
docs/advanced-ios.md
Normal file
@@ -0,0 +1,165 @@
|
||||
---
|
||||
id: advanced-ios
|
||||
title: iOS Advanced API
|
||||
sidebar_label: iOS
|
||||
---
|
||||
|
||||
## PushKit API
|
||||
|
||||
The PushKit framework provides the classes for your iOS apps to receive background pushes from remote servers. it has better support for background notifications compared to regular push notifications with `content-available: 1`. More info in [iOS PushKit documentation](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Reference/PushKit_Framework/).
|
||||
|
||||
### Register to PushKit
|
||||
[Prepare your app to receive VoIP push notifications](https://developer.apple.com/library/ios/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html)
|
||||
|
||||
### Listen to PushKit notifications
|
||||
On receiving PushKit notification, a `pushKitNotificationReceived` event will be fired with the notification payload.
|
||||
|
||||
```js
|
||||
Notifications.ios.events().registerPushKitNotificationReceived((payload: object) => {
|
||||
console.log(JSON.stringify(payload));
|
||||
});
|
||||
```
|
||||
|
||||
In your ReactNative code, add event handler for `pushKitRegistered` event and call to `registerPushKit()`:
|
||||
|
||||
```javascript
|
||||
constructor() {
|
||||
Notifications.ios.events().registerPushKitRegistered((event: RegisteredPushKit) => {
|
||||
console.log("PushKit Token Received: " + event.pushKitToken);
|
||||
});
|
||||
|
||||
Notifications.ios.events().registerPushKitNotificationReceived((payload: object) => {
|
||||
console.log('PushKit notification Received: ' + JSON.stringify(payload));
|
||||
});
|
||||
|
||||
Notifications.ios.registerPushKit();
|
||||
}
|
||||
```
|
||||
|
||||
> 1. Notice that PushKit device token and regular notifications device token are different, so you must handle two different tokens in the server side in order to support this feature.
|
||||
> 2. PushKit will not request permissions from the user for push notifications.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Interactive / Actionable Notifications
|
||||
|
||||
> This section provides description for iOS. For notifications customization on Android, refer to [our wiki](https://github.com/wix/react-native-notifications/wiki/Android-Customizations#customizing-notifications-layout).
|
||||
|
||||
Interactive notifications allow you to reply to a message right from the notification banner or take action right from the lock screen.
|
||||
|
||||
On the Lock screen and within Notification Center, you swipe from right to left
|
||||
to reveal actions. Destructive actions, like trashing an email, are color-coded red. Relatively neutral actions, like dismissing an alert or declining an invitation, are color-coded gray.
|
||||
|
||||
For banners, you pull down to reveal actions as buttons. For popups, the actions are immediately visible — the buttons are right there.
|
||||
|
||||
You can find more info about interactive notifications [here](http://www.imore.com/interactive-notifications-ios-8-explained).
|
||||
|
||||

|
||||
|
||||
|
||||
Notification **actions** allow the user to interact with a given notification.
|
||||
|
||||
Notification **categories** allow you to group multiple actions together, and to connect the actions with the push notification itself.
|
||||
|
||||
Follow the basic workflow of adding interactive notifications to your app:
|
||||
|
||||
1. Config the actions.
|
||||
2. Group actions together into categories.
|
||||
3. Register to push notifications with the configured categories.
|
||||
4. Push a notification (or trigger a [local](#triggering-local-notifications) one) with the configured category name.
|
||||
|
||||
### Example
|
||||
#### Config the Actions
|
||||
We will config two actions: upvote and reply.
|
||||
|
||||
```javascript
|
||||
import { Notifications, NotificationAction, NotificationCategory } from 'react-native-notifications';
|
||||
|
||||
let upvoteAction = new NotificationAction({
|
||||
activationMode: "background",
|
||||
title: String.fromCodePoint(0x1F44D),
|
||||
identifier: "UPVOTE_ACTION",
|
||||
textInput: {
|
||||
buttonTitle: 'title',
|
||||
placeholder: 'placeholder text'
|
||||
}
|
||||
});
|
||||
|
||||
let replyAction = new NotificationAction({
|
||||
activationMode: "background",
|
||||
title: "Reply",
|
||||
authenticationRequired: true,
|
||||
identifier: "REPLY_ACTION"
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
#### Config the Category
|
||||
We will group `upvote` action and `reply` action into a single category: `EXAMPLE_CATEGORY `. If the notification contains `EXAMPLE_CATEGORY ` under `category` field, those actions will appear.
|
||||
|
||||
```javascript
|
||||
let exampleCategory = new NotificationCategory({
|
||||
identifier: "EXAMPLE_CATEGORY",
|
||||
actions: [upvoteAction, replyAction]
|
||||
});
|
||||
```
|
||||
|
||||
#### Register to Push Notifications
|
||||
Instead of basic registration like we've done before, we will register the device to push notifications with the category we've just created.
|
||||
|
||||
```javascript
|
||||
Notifications.setCategories([exampleCategory]);
|
||||
```
|
||||
|
||||
#### Push an Interactive Notification
|
||||
Notification payload should look like this:
|
||||
|
||||
```javascript
|
||||
{
|
||||
aps: {
|
||||
// ... (alert, sound, badge, etc)
|
||||
category: "EXAMPLE_CATEGORY"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The [example app](https://github.com/wix/react-native-notifications/tree/master/example) contains this interactive notification example, you can follow there.
|
||||
|
||||
### `NotificationAction` Payload
|
||||
|
||||
- `title` - Action button title.
|
||||
- `identifier` - Action identifier (must be unique).
|
||||
- `activationMode` - Indicating whether the app should activate to the foreground or background.
|
||||
- `foreground` (default) - Activate the app and put it in the foreground.
|
||||
- `background` - Activate the app and put it in the background. If the app is already in the foreground, it remains in the foreground.
|
||||
- `textInput` - `TextInput` payload, when supplied, the system will present text input in this action.
|
||||
- `destructive` - A Boolean value indicating whether the action is destructive. When the value of this property is `true`, the system displays the corresponding button differently to indicate that the action is destructive.
|
||||
- `authenticationRequired` - A Boolean value indicating whether the user must unlock the device before the action is performed.
|
||||
|
||||
### `NotificationCategory` Payload
|
||||
|
||||
- `identifier` - The name of the action group (must be unique).
|
||||
- `actions` - An array of `NotificationAction` objects, which related to this category.
|
||||
|
||||
### `TextInput` Payload
|
||||
|
||||
- `buttonTitle` - Title of the `send` button.
|
||||
- `placeholder` - Placeholder for the `textInput`.
|
||||
|
||||
|
||||
#### Get and set application icon badges count (iOS only)
|
||||
|
||||
Get the current number:
|
||||
```javascript
|
||||
Notifications.ios.getBadgeCount((count) => console.log(count));
|
||||
```
|
||||
|
||||
Set to specific number:
|
||||
```javascript
|
||||
Notifications.ios.setBadgeCount(2);
|
||||
```
|
||||
Clear badges icon:
|
||||
```javascript
|
||||
Notifications.ios.setBadgeCount(0);
|
||||
```
|
||||
12
docs/android-api.md
Executable file
12
docs/android-api.md
Executable file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: android-api
|
||||
title: Android Specific Commands
|
||||
sidebar_label: Android specific
|
||||
---
|
||||
|
||||
## refreshToken()
|
||||
Request a new token for sending push notifications.
|
||||
|
||||
```js
|
||||
Notifications.android.refreshToken();
|
||||
```
|
||||
55
docs/general-api.md
Executable file
55
docs/general-api.md
Executable file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: general-api
|
||||
title: General Commands
|
||||
sidebar_label: General
|
||||
---
|
||||
|
||||
## registerRemoteNotifications()
|
||||
Requests remote notification permissions, prompting the user's dialog box on iOS and request a token on Android.
|
||||
If the user accept the remote notifications permissions, `RemoteNotificationsRegistered` event will get called with the device token.
|
||||
|
||||
```js
|
||||
Notifications.registerRemoteNotifications();
|
||||
```
|
||||
|
||||
## getInitialNotification()
|
||||
This method returns a promise. If the app was launched by a push notification, this promise resolves to an object of type [Notification](notification-object). Otherwise, it resolves to undefined.
|
||||
|
||||
```js
|
||||
const notification: Notification = await Notifications.getInitialNotification();
|
||||
```
|
||||
|
||||
## postLocalNotification(notification, id?)
|
||||
Posts local notification to the device notification center.
|
||||
|
||||
```js
|
||||
Notifications.postLocalNotification({
|
||||
body: 'Local notificiation!',
|
||||
title: 'Local Notification Title',
|
||||
sound: 'chime.aiff',
|
||||
category: 'SOME_CATEGORY',
|
||||
link: 'localNotificationLink',
|
||||
fireDate: new Date()
|
||||
}, id);
|
||||
```
|
||||
|
||||
## cancelLocalNotification(id)
|
||||
Relevant for notifications sent with `fireDate`.
|
||||
|
||||
```js
|
||||
Notifications.cancelLocalNotification(id);
|
||||
```
|
||||
|
||||
## isRegisteredForRemoteNotifications()
|
||||
Check if the app has permissions to send remote notifications.
|
||||
|
||||
```js
|
||||
const hasPermissions: boolean = await Notifications.isRegisteredForRemoteNotifications();
|
||||
```
|
||||
|
||||
## removeAllDeliveredNotifications()
|
||||
Remove all delivered notifications from Notification Center
|
||||
|
||||
```js
|
||||
Notifications.removeAllDeliveredNotifications();
|
||||
```
|
||||
47
docs/general-events.md
Executable file
47
docs/general-events.md
Executable file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: general-events
|
||||
title: General
|
||||
sidebar_label: General
|
||||
---
|
||||
|
||||
## registerRemoteNotificationsRegistered()
|
||||
Fired when the user registers for remote notifications. The handler will be invoked with an event holding the hex string representing the `deviceToken`
|
||||
|
||||
```js
|
||||
Notifications.events().registerRemoteNotificationsRegistered((event: Registered) => {
|
||||
console.log(event.deviceToken);
|
||||
});
|
||||
```
|
||||
|
||||
## registerNotificationReceived()
|
||||
Fired when a remote notification is received in foreground state. The handler will be invoked with an instance of [Notification](notification-object).
|
||||
Should call completion function on iOS, will be ignored on Android.
|
||||
|
||||
```js
|
||||
Notifications.events().registerNotificationReceived((notification: Notification, completion: (response: NotificationCompletion) => void) => {
|
||||
console.log(JSON.stringify(notification.data));
|
||||
|
||||
// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.
|
||||
completion({alert: true, sound: true, badge: false});
|
||||
});
|
||||
```
|
||||
|
||||
## registerRemoteNotificationOpened()
|
||||
Fired when a remote notification is opened from dead or background state. The handler will be invoked with an instance of [Notification](notification-object).
|
||||
Should call completion function on iOS, will be ignored on Android.
|
||||
|
||||
```js
|
||||
Notifications.events().registerRemoteNotificationOpened((notification: Notification, completion: () => void) => {
|
||||
console.log(JSON.stringify(notification.data));
|
||||
completion();
|
||||
});
|
||||
```
|
||||
|
||||
## registerRemoteNotificationsRegistrationFailed()
|
||||
Fired when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. The handler will be invoked with {localizedDescription: string, code: string, domain: string}.
|
||||
|
||||
```js
|
||||
Notifications.events().registerRemoteNotificationsRegistrationFailed((event: RegistrationError) => {
|
||||
console.log(event.code, event.localizedDescription, event.domain);
|
||||
});
|
||||
```
|
||||
64
docs/installation-android.md
Executable file
64
docs/installation-android.md
Executable file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
id: installation-android
|
||||
title: Android Installation
|
||||
sidebar_label: Android Installation
|
||||
---
|
||||
|
||||
Add the library to your application class (e.g. `MainApplication.java`):
|
||||
|
||||
```java
|
||||
import com.wix.reactnativenotifications.RNNotificationsPackage;
|
||||
|
||||
...
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
// ...
|
||||
// Add this line:
|
||||
new RNNotificationsPackage(MainApplication.this)
|
||||
);
|
||||
```
|
||||
|
||||
### Receiving push notifications
|
||||
|
||||
> Note: This section is only necessary in case you wish to be able to **receive** push notifications in your React-Native app.
|
||||
|
||||
Push notifications on Android are managed and dispatched using [Google's FCM service](https://firebase.google.com/docs/cloud-messaging). The following installation steps are a TL;DR of [Google's FCM setup guide](https://firebase.google.com/docs/cloud-messaging/android/client). You can follow them to get FCM integrated quickly, but we recommend that you will in the very least have a peek at the guide's overview.
|
||||
|
||||
#### Step #1: Subscribe to Google's FCM
|
||||
|
||||
To set FCM in your app, you must first create a google-services.json file. If you have no existing API project yet, the easiest way to go about in creating one is using [this step-by-step installation process](https://firebase.google.com/docs/android/setup);
|
||||
|
||||
|
||||
#### Step #2: Copy google-services.json
|
||||
|
||||
After creating google-services.json, copy it into your project's android/app folder.
|
||||
|
||||
#### Step #3: Add google-services package to Project/build.gradle
|
||||
```gradle
|
||||
buildscript {
|
||||
...
|
||||
dependencies {
|
||||
...
|
||||
classpath 'com.google.gms:google-services:4.0.0'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step #4: Add firebase-core package and apply google-services plugin in Project/app/build.gradle
|
||||
```gradle
|
||||
dependencies {
|
||||
...
|
||||
implementation 'com.google.firebase:firebase-core:16.0.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
```
|
||||
|
||||
#### Step #5: Link react-native-notifications in Project/android/settings.gradle
|
||||
```gradle
|
||||
include ':react-native-notifications'
|
||||
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-notifications/lib/android/app')
|
||||
```
|
||||
88
docs/installation-ios.md
Executable file
88
docs/installation-ios.md
Executable file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
id: installation-ios
|
||||
title: iOS Installation
|
||||
sidebar_label: iOS Installation
|
||||
---
|
||||
|
||||
As with any React Native project, the first step is to add the project as an npm dependency.
|
||||
|
||||
Start by running this:
|
||||
|
||||
```
|
||||
$ npm install react-native-notifications --save
|
||||
```
|
||||
|
||||
### Installation with CocoaPods
|
||||
|
||||
Projects generated using newer versions of react-native use CocoaPods by default. In that case it's easier to install react-native-navigation using CocoaPods.
|
||||
|
||||
1. Add the following to `Podfile`:
|
||||
|
||||
```diff
|
||||
platform :ios, '9.0'
|
||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||
|
||||
target 'YourApp' do
|
||||
# Pods for YourApp
|
||||
pod 'React', :path => '../node_modules/react-native/'
|
||||
pod 'React-Core', :path => '../node_modules/react-native/React'
|
||||
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
|
||||
pod 'React-fishhook', :path => '../node_modules/react-native/Libraries/fishhook'
|
||||
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
|
||||
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
|
||||
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
|
||||
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
|
||||
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
|
||||
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
|
||||
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
|
||||
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
|
||||
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
|
||||
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
|
||||
|
||||
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
|
||||
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
|
||||
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
|
||||
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
|
||||
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
|
||||
|
||||
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
|
||||
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
|
||||
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
|
||||
|
||||
+ pod 'ReactNativeNotifications', :podspec => '../node_modules/react-native-notifications/ReactNativeNotifications.podspec'
|
||||
|
||||
use_native_modules!
|
||||
end
|
||||
```
|
||||
|
||||
2. `cd ios && pod install`
|
||||
|
||||
3. Add the following line at the top of your `AppDelegate.m`
|
||||
|
||||
```objective-c
|
||||
#import "RNNotifications.h"
|
||||
```
|
||||
|
||||
Start monitor notifications in: `application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions`
|
||||
|
||||
```objective-c
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
[RNNotifications startMonitorNotifications]; // -> Add this line
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
And add the following methods to support registration:
|
||||
|
||||
```objective-c
|
||||
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
||||
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
|
||||
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
|
||||
}
|
||||
70
docs/ios-api.md
Executable file
70
docs/ios-api.md
Executable file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: ios-api
|
||||
title: iOS Specific Commands
|
||||
sidebar_label: iOS specific
|
||||
---
|
||||
|
||||
## requestPermissions()
|
||||
Requests notification permissions from iOS, prompting the user's dialog box.
|
||||
|
||||
```js
|
||||
Notifications.ios.requestPermissions();
|
||||
```
|
||||
|
||||
## checkPermissions()
|
||||
See what push permissions are currently enabled.
|
||||
|
||||
```js
|
||||
Notifications.ios.checkPermissions();
|
||||
```
|
||||
|
||||
## abandonPermissions()
|
||||
Unregister for all remote notifications received via Apple Push Notification service.
|
||||
|
||||
You should call this method in rare circumstances only, such as when a new version of the app removes support for all types of remote notifications. Users can temporarily prevent apps from receiving remote notifications through the Notifications section of the Settings app. Apps unregistered through this method can always re-register.
|
||||
|
||||
```js
|
||||
Notifications.ios.abandonPermissions();
|
||||
```
|
||||
|
||||
## registerPushKit()
|
||||
Register for PushKit notifications
|
||||
|
||||
```js
|
||||
Notifications.ios.registerPushKit();
|
||||
```
|
||||
|
||||
## cancelAllLocalNotifications()
|
||||
Cancels all scheduled localNotifications
|
||||
|
||||
```js
|
||||
Notifications.ios.cancelAllLocalNotifications();
|
||||
```
|
||||
|
||||
## getDeliveredNotifications()
|
||||
Provides you with a list of the app’s notifications that are still displayed in Notification Center
|
||||
|
||||
```js
|
||||
Notifications.ios.getDeliveredNotifications();
|
||||
```
|
||||
|
||||
## removeDeliveredNotifications()
|
||||
Removes the specified notifications from Notification Center
|
||||
|
||||
```js
|
||||
Notifications.ios.removeDeliveredNotifications(identifiers);
|
||||
```
|
||||
|
||||
## getBadgeCount()
|
||||
Gets the badge count number from the aps object
|
||||
|
||||
```js
|
||||
Notifications.ios.getBadgeCount();
|
||||
```
|
||||
|
||||
## setBadgeCount()
|
||||
Sets the badge number for the app icon on the home screen
|
||||
|
||||
```js
|
||||
Notifications.ios.setBadgeCount(1);
|
||||
```
|
||||
24
docs/ios-events.md
Executable file
24
docs/ios-events.md
Executable file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: ios-events
|
||||
title: iOS
|
||||
sidebar_label: iOS specific
|
||||
---
|
||||
|
||||
## registerPushKitRegistered()
|
||||
Fired when the user registers for PushKit notifications. The handler will be invoked with an event holding the hex string representing the `pushKitToken`
|
||||
|
||||
```js
|
||||
Notifications.ios.events().registerPushKitRegistered((event: RegisteredPushKit) => {
|
||||
console.log(event.pushKitToken);
|
||||
});
|
||||
```
|
||||
|
||||
## registerPushKitNotificationReceived()
|
||||
Fired when a PushKit notification is received. The handler will be invoked with the notification object.
|
||||
|
||||
```js
|
||||
Notifications.ios.events().registerPushKitNotificationReceived((payload: object) => {
|
||||
console.log(JSON.stringify(payload));
|
||||
});
|
||||
```
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
id: localNotifications
|
||||
title: Local Notifications
|
||||
sidebar_label: Local Notifications
|
||||
---
|
||||
|
||||
# Local Notifications
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
|
||||
|
||||
You can manually trigger local notifications in your JS code, to be posted immediately or in the future.
|
||||
Triggering local notifications is fully compatible with React Native `PushNotificationsIOS` library.
|
||||
@@ -9,7 +12,7 @@ Triggering local notifications is fully compatible with React Native `PushNotifi
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
let localNotification = NotificationsIOS.localNotification({
|
||||
let localNotification = Notifications.postLocalNotification({
|
||||
body: "Local notificiation!",
|
||||
title: "Local Notification Title",
|
||||
sound: "chime.aiff",
|
||||
@@ -32,12 +35,12 @@ Notification object contains:
|
||||
|
||||
### Cancel Scheduled Local Notifications
|
||||
|
||||
The `NotificationsIOS.localNotification()` and `NotificationsAndroid.localNotification()` methods return unique `notificationId` values, which can be used in order to cancel specific local notifications that were scheduled for delivery on `fireDate` and have not yet been delivered. You can cancel local notification by calling `NotificationsIOS.cancelLocalNotification(notificationId)` or `NotificationsAndroid.cancelLocalNotification(notificationId)`.
|
||||
The `Notifications.postLocalNotification()` method return unique `notificationId` values, which can be used in order to cancel specific local notifications that were scheduled for delivery on `fireDate` and have not yet been delivered. You can cancel local notification by calling `Notifications.cancelLocalNotification(notificationId)`.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
let someLocalNotification = NotificationsIOS.localNotification({
|
||||
let someLocalNotification = Notifications.postLocalNotification({
|
||||
body: "Local notificiation!",
|
||||
title: "Local Notification Title",
|
||||
sound: "chime.aiff",
|
||||
@@ -45,23 +48,23 @@ let someLocalNotification = NotificationsIOS.localNotification({
|
||||
userInfo: { }
|
||||
});
|
||||
|
||||
NotificationsIOS.cancelLocalNotification(someLocalNotification);
|
||||
Notifications.cancelLocalNotification(someLocalNotification);
|
||||
```
|
||||
|
||||
To cancel all local notifications (**iOS only!**), use `cancelAllLocalNotifications()`:
|
||||
|
||||
```javascript
|
||||
NotificationsIOS.cancelAllLocalNotifications();
|
||||
Notifications.ios.cancelAllLocalNotifications();
|
||||
```
|
||||
|
||||
#### Cancel Delivered Local Notifications (iOS 10+ only)
|
||||
|
||||
To dismiss notifications from the notification center that have already been shown to the user, call `NotificationsIOS.removeDeliveredNotifications([notificationId])`:
|
||||
To dismiss notifications from the notification center that have already been shown to the user, call `Notifications.ios.removeDeliveredNotifications([notificationId])`:
|
||||
|
||||
```javascript
|
||||
let someLocalNotification = NotificationsIOS.localNotification({...});
|
||||
let someLocalNotification = Notifications.postLocalNotification({...});
|
||||
|
||||
NotificationsIOS.removeDeliveredNotifications([someLocalNotification]);
|
||||
Notifications.ios.removeDeliveredNotifications([someLocalNotification]);
|
||||
```
|
||||
|
||||
Call `removeAllDeliveredNotifications()` to dismiss all delivered notifications
|
||||
@@ -69,12 +72,12 @@ Call `removeAllDeliveredNotifications()` to dismiss all delivered notifications
|
||||
notifications).
|
||||
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
|
||||
|
||||
Much like on iOS, notifications can be triggered locally. The API to do so is a simplified version of the iOS equivalent that works more natually with the Android perception of push (remote) notifications:
|
||||
|
||||
```javascript
|
||||
NotificationsAndroid.localNotification({
|
||||
Notifications.postLocalNotification({
|
||||
title: "Local notification",
|
||||
body: "This notification was generated by the app!",
|
||||
extra: "data"
|
||||
|
||||
25
docs/notification-object.md
Executable file
25
docs/notification-object.md
Executable file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
id: notification-object
|
||||
title: Notification object
|
||||
sidebar_label: Notification
|
||||
---
|
||||
|
||||
Contains the payload data.
|
||||
|
||||
- **`title`**- returns the notification's title string.
|
||||
- **`subtitle`**- returns the notification's title string. (iOS only)
|
||||
- **`body`**- returns the notification's main message string.
|
||||
- **`sound`**- returns the sound string from the `aps` object.
|
||||
- **`badge`**- returns the badge count number from the `aps` object.
|
||||
- **`category`**- returns the category from the `aps` object (related to interactive notifications).
|
||||
- **`payload`**- returns the full payload sent from server.
|
||||
|
||||
Example:
|
||||
```js
|
||||
Notifications.events().registerNotificationReceived((notification: Notification, completion: (response: NotificationCompletion) => void) => {
|
||||
// Prints the notification payload
|
||||
console.log(JSON.stringify(notification.payload));
|
||||
|
||||
completion({alert: false, sound: false, badge: false});
|
||||
});
|
||||
```
|
||||
56
docs/notifications-events.md
Normal file
56
docs/notifications-events.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: notifications-events
|
||||
title: Handling Notification Events
|
||||
sidebar_label: Events
|
||||
---
|
||||
|
||||
When a push notification is received by the device, the application can be in one of the following states:
|
||||
|
||||
1. **Forground:** When the app is running and is used by the user right now; in this case, a `notificationReceived` event will be fired, do not forget to invoke `completion()` callback.
|
||||
|
||||
Finally, when a notification is _opened_ by the device user (i.e. tapped-on), a `notificationOpened` event is fired, here as well you need to remember invoking `completion()` callback.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
constructor() {
|
||||
Notifications.events().registerNotificationReceived((notification: Notification, completion: (response: NotificationCompletion) => void) => {
|
||||
console.log("Notification Received - Foreground", notification.data);
|
||||
|
||||
// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.
|
||||
completion({alert: true, sound: true, badge: false});
|
||||
});
|
||||
|
||||
Notifications.events().registerRemoteNotificationOpened((notification: Notification, completion: () => void, action: NotificationActionResponse) => {
|
||||
console.log("Notification opened by device user", notification.data);
|
||||
console.log(`Notification opened with an action identifier: ${action.identifier} and response text: ${action.text}`);
|
||||
completion();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Notification Object
|
||||
|
||||
When you receive a push notification, you'll get an instance of [Notification](notification-object) object, contains the following methods:
|
||||
|
||||
## Querying initial notification
|
||||
|
||||
React-Native's [`PushNotificationsIOS.getInitialNotification()`](https://facebook.github.io/react-native/docs/pushnotificationios.html#getinitialnotification) allows for the async retrieval of the original notification used to open the App on iOS, but it has no equivalent implementation for Android.
|
||||
|
||||
```javascript
|
||||
import {Notifications} from 'react-native-notifications';
|
||||
|
||||
Notifications.getInitialNotification()
|
||||
.then((notification) => {
|
||||
console.log("Initial notification was:", (notification ? notification.data : 'N/A'));
|
||||
})
|
||||
.catch((err) => console.error("getInitialNotifiation() failed", err));
|
||||
|
||||
```
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Notifications are considered 'initial' under the following terms:
|
||||
|
||||
> - User tapped on a notification, _AND_ -
|
||||
> - App was either not running at all ("dead" state), _OR_ it existed in the background with **no running activities** associated with it.
|
||||
@@ -1,46 +1,32 @@
|
||||
# Push Notifications Subscription
|
||||
---
|
||||
id: subscription
|
||||
title: Push Notifications Subscription
|
||||
sidebar_label: Subscription
|
||||
---
|
||||
|
||||
The typical flow for subscribing a device for receiving push notification in real time is to first register the device at the vendor's servers (e.g. GCM), then publishing the received token to your own push management servers.
|
||||
The typical flow for subscribing a device for receiving push notification in real time is to first register the device at the vendor's servers (e.g. FCM), then publishing the received token to your own push management servers.
|
||||
|
||||
This section is about the first part of the flow.
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
|
||||
|
||||
In order to handle notifications, you must register the `remoteNotificationsRegistered` event beforehand.
|
||||
|
||||
|
||||
In your React Native app:
|
||||
|
||||
```javascript
|
||||
import NotificationsIOS from 'react-native-notifications';
|
||||
import {Notifications} from 'react-native-notifications';
|
||||
|
||||
class App extends Component {
|
||||
constructor() {
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistrationFailed', this.onPushRegistrationFailed.bind(this));
|
||||
NotificationsIOS.requestPermissions();
|
||||
}
|
||||
|
||||
onPushRegistered(deviceToken) {
|
||||
// TODO: Send the token to my server so it could send back push notifications...
|
||||
console.log("Device Token Received", deviceToken);
|
||||
}
|
||||
Notifications.events().registerRemoteNotificationsRegistered((event: Registered) => {
|
||||
// TODO: Send the token to my server so it could send back push notifications...
|
||||
console.log("Device Token Received", event.deviceToken);
|
||||
});
|
||||
Notifications.events().registerRemoteNotificationsRegistrationFailed((event: RegistrationError) => {
|
||||
console.error(event);
|
||||
});
|
||||
|
||||
onPushRegistrationFailed(error) {
|
||||
// For example:
|
||||
//
|
||||
// error={
|
||||
// domain: 'NSCocoaErroDomain',
|
||||
// code: 3010,
|
||||
// localizedDescription: 'remote notifications are not supported in the simulator'
|
||||
// }
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// prevent memory leaks!
|
||||
NotificationsIOS.removeEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.removeEventListener('remoteNotificationsRegistrationFailed', this.onPushRegistrationFailed.bind(this));
|
||||
Notifications.requestPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,30 +34,12 @@ class App extends Component {
|
||||
|
||||
When you have the device token, POST it to your server and register the device in your notifications provider (Amazon SNS, Azure, etc.).
|
||||
|
||||
You can check if the user granted permissions by calling `checkPermissions()`:
|
||||
You can check if the user granted permissions on iOS by calling `checkPermissions()`:
|
||||
|
||||
```javascript
|
||||
NotificationsIOS.checkPermissions().then((currentPermissions) => {
|
||||
Notifications.ios.checkPermissions().then((currentPermissions) => {
|
||||
console.log('Badges enabled: ' + !!currentPermissions.badge);
|
||||
console.log('Sounds enabled: ' + !!currentPermissions.sound);
|
||||
console.log('Alerts enabled: ' + !!currentPermissions.alert);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
|
||||
|
||||
Android works similarly but using a different API; The equivalent code is:
|
||||
|
||||
```javascript
|
||||
import {NotificationsAndroid} from 'react-native-notifications';
|
||||
|
||||
// On Android, we allow for only one (global) listener per each event type.
|
||||
NotificationsAndroid.setRegistrationTokenUpdateListener((deviceToken) => {
|
||||
// TODO: Send the token to my server so it could send back push notifications...
|
||||
console.log('Push-notifications registered!', deviceToken)
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
`deviceToken` being the token used to identify the device on the GCM.
|
||||
|
||||
@@ -238,14 +238,14 @@ The [example app](https://github.com/wix/react-native-notifications/tree/master/
|
||||
|
||||
Get the current number:
|
||||
```javascript
|
||||
NotificationsIOS.getBadgesCount((count) => console.log(count));
|
||||
NotificationsIOS.getBadgeCount((count) => console.log(count));
|
||||
```
|
||||
|
||||
Set to specific number:
|
||||
```javascript
|
||||
NotificationsIOS.setBadgesCount(2);
|
||||
NotificationsIOS.setBadgeCount(2);
|
||||
```
|
||||
Clear badges icon:
|
||||
```javascript
|
||||
NotificationsIOS.setBadgesCount(0);
|
||||
NotificationsIOS.setBadgeCount(0);
|
||||
```
|
||||
@@ -54,7 +54,7 @@ Add a reference to the library's native code in your global `settings.gradle`:
|
||||
|
||||
```gradle
|
||||
include ':reactnativenotifications'
|
||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
|
||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app')
|
||||
```
|
||||
|
||||
Declare the library as a dependency in your **app-project's** `build.gradle`:
|
||||
84
docs_old/localNotifications.md
Normal file
84
docs_old/localNotifications.md
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
# Local Notifications
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
|
||||
|
||||
You can manually trigger local notifications in your JS code, to be posted immediately or in the future.
|
||||
Triggering local notifications is fully compatible with React Native `PushNotificationsIOS` library.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
let localNotification = NotificationsIOS.localNotification({
|
||||
body: "Local notificiation!",
|
||||
title: "Local Notification Title",
|
||||
sound: "chime.aiff",
|
||||
silent: false,
|
||||
category: "SOME_CATEGORY",
|
||||
userInfo: { }
|
||||
});
|
||||
```
|
||||
|
||||
Notification object contains:
|
||||
|
||||
- **`fireDate`**- The date and time when the system should deliver the notification (optinal - default is immidiate dispatch).
|
||||
- `body`- The message displayed in the notification alert.
|
||||
- `title`- The title of the notification, displayed in the notifications center.
|
||||
- `alertAction`- The "action" displayed beneath an actionable notification on the lockscreen (e.g. "Slide to **open**"). Note that Apple no longer shows this in iOS 10.
|
||||
- `sound`- The sound played when the notification is fired (optional -- will play default sound if unspecified). This must be the filename of a sound included in the application bundle; the sound must be 30 seconds or less and should be encoded with linear PCM or IMA4.
|
||||
- `silent`- Whether the notification sound should be suppressed (optional).
|
||||
- `category`- The category of this notification, required for [interactive notifications](#interactive--actionable-notifications-ios-only) (optional).
|
||||
- `userInfo`- An optional object containing additional notification data.
|
||||
|
||||
### Cancel Scheduled Local Notifications
|
||||
|
||||
The `NotificationsIOS.localNotification()` and `NotificationsAndroid.localNotification()` methods return unique `notificationId` values, which can be used in order to cancel specific local notifications that were scheduled for delivery on `fireDate` and have not yet been delivered. You can cancel local notification by calling `NotificationsIOS.cancelLocalNotification(notificationId)` or `NotificationsAndroid.cancelLocalNotification(notificationId)`.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
let someLocalNotification = NotificationsIOS.localNotification({
|
||||
body: "Local notificiation!",
|
||||
title: "Local Notification Title",
|
||||
sound: "chime.aiff",
|
||||
category: "SOME_CATEGORY",
|
||||
userInfo: { }
|
||||
});
|
||||
|
||||
NotificationsIOS.cancelLocalNotification(someLocalNotification);
|
||||
```
|
||||
|
||||
To cancel all local notifications (**iOS only!**), use `cancelAllLocalNotifications()`:
|
||||
|
||||
```javascript
|
||||
NotificationsIOS.cancelAllLocalNotifications();
|
||||
```
|
||||
|
||||
#### Cancel Delivered Local Notifications (iOS 10+ only)
|
||||
|
||||
To dismiss notifications from the notification center that have already been shown to the user, call `NotificationsIOS.removeDeliveredNotifications([notificationId])`:
|
||||
|
||||
```javascript
|
||||
let someLocalNotification = NotificationsIOS.localNotification({...});
|
||||
|
||||
NotificationsIOS.removeDeliveredNotifications([someLocalNotification]);
|
||||
```
|
||||
|
||||
Call `removeAllDeliveredNotifications()` to dismiss all delivered notifications
|
||||
(note that this will dismiss push notifications in addition to local
|
||||
notifications).
|
||||
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
|
||||
|
||||
Much like on iOS, notifications can be triggered locally. The API to do so is a simplified version of the iOS equivalent that works more natually with the Android perception of push (remote) notifications:
|
||||
|
||||
```javascript
|
||||
NotificationsAndroid.localNotification({
|
||||
title: "Local notification",
|
||||
body: "This notification was generated by the app!",
|
||||
extra: "data"
|
||||
});
|
||||
```
|
||||
|
||||
Upon notification opening (tapping by the device user), all data fields will be delivered as-is).
|
||||
77
docs_old/subscription.md
Normal file
77
docs_old/subscription.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Push Notifications Subscription
|
||||
|
||||
The typical flow for subscribing a device for receiving push notification in real time is to first register the device at the vendor's servers (e.g. GCM), then publishing the received token to your own push management servers.
|
||||
|
||||
This section is about the first part of the flow.
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
|
||||
|
||||
In order to handle notifications, you must register the `remoteNotificationsRegistered` event beforehand.
|
||||
|
||||
|
||||
In your React Native app:
|
||||
|
||||
```javascript
|
||||
import NotificationsIOS from 'react-native-notifications';
|
||||
|
||||
class App extends Component {
|
||||
constructor() {
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistrationFailed', this.onPushRegistrationFailed.bind(this));
|
||||
NotificationsIOS.requestPermissions();
|
||||
}
|
||||
|
||||
onPushRegistered(deviceToken) {
|
||||
// TODO: Send the token to my server so it could send back push notifications...
|
||||
console.log("Device Token Received", deviceToken);
|
||||
}
|
||||
|
||||
onPushRegistrationFailed(error) {
|
||||
// For example:
|
||||
//
|
||||
// error={
|
||||
// domain: 'NSCocoaErroDomain',
|
||||
// code: 3010,
|
||||
// localizedDescription: 'remote notifications are not supported in the simulator'
|
||||
// }
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// prevent memory leaks!
|
||||
NotificationsIOS.removeEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.removeEventListener('remoteNotificationsRegistrationFailed', this.onPushRegistrationFailed.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
When you have the device token, POST it to your server and register the device in your notifications provider (Amazon SNS, Azure, etc.).
|
||||
|
||||
You can check if the user granted permissions by calling `checkPermissions()`:
|
||||
|
||||
```javascript
|
||||
NotificationsIOS.checkPermissions().then((currentPermissions) => {
|
||||
console.log('Badges enabled: ' + !!currentPermissions.badge);
|
||||
console.log('Sounds enabled: ' + !!currentPermissions.sound);
|
||||
console.log('Alerts enabled: ' + !!currentPermissions.alert);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
|
||||
|
||||
Android works similarly but using a different API; The equivalent code is:
|
||||
|
||||
```javascript
|
||||
import {NotificationsAndroid} from 'react-native-notifications';
|
||||
|
||||
// On Android, we allow for only one (global) listener per each event type.
|
||||
NotificationsAndroid.setRegistrationTokenUpdateListener((deviceToken) => {
|
||||
// TODO: Send the token to my server so it could send back push notifications...
|
||||
console.log('Push-notifications registered!', deviceToken)
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
`deviceToken` being the token used to identify the device on the GCM.
|
||||
@@ -9,7 +9,7 @@ describe('Notifications', () => {
|
||||
describe('Foreground', () => {
|
||||
it('Should receive notification', async () => {
|
||||
await device.sendUserNotification(createNotification({link: 'foreground/notification'}));
|
||||
await expect(elementByLabel('foreground/notification')).toBeVisible();
|
||||
await linkShouldBeVisible('foreground/notification');
|
||||
});
|
||||
|
||||
it('Should open notification', async () => {
|
||||
@@ -30,9 +30,13 @@ describe('Notifications', () => {
|
||||
describe('Dead state', () => {
|
||||
it('Should receive notification', async () => {
|
||||
await device.launchApp({newInstance: true, userNotification: createNotification({link: 'deadState/notification'})});
|
||||
await expect(elementByLabel('deadState/notification')).toBeVisible();
|
||||
await linkShouldBeVisible('deadState/notification');
|
||||
});
|
||||
});
|
||||
|
||||
async function linkShouldBeVisible(link) {
|
||||
return await expect(elementByLabel(`Extra Link Param: ${link}`)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
function createNotification({link, showAlert}) {
|
||||
|
||||
@@ -2,8 +2,8 @@ apply plugin: "com.android.application"
|
||||
|
||||
project.ext.react = [
|
||||
root : "../../../",
|
||||
entryFile: "index.android.js",
|
||||
bundleAssetName: "index.android.bundle",
|
||||
entryFile: "index.js",
|
||||
bundleAssetName: "index.bundle",
|
||||
bundleInAlpha: true,
|
||||
bundleInBeta: true
|
||||
]
|
||||
@@ -13,10 +13,9 @@ apply from: "../../../node_modules/react-native/react.gradle"
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.wix.reactnativenotifications.app"
|
||||
minSdkVersion 19
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@@ -24,7 +23,6 @@ android {
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.wix.reactnativenotifications.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.facebook.react.ReactActivity;
|
||||
|
||||
|
||||
public class MainActivity extends ReactActivity {
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
return "WixRNNotifications";
|
||||
return "NotificationsExampleApp";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,12 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
return Arrays.asList(
|
||||
new MainReactPackage(),
|
||||
new RNNotificationsPackage(MainApplication.this)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include ':myapplication'
|
||||
|
||||
include ':react-native-notifications'
|
||||
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../android/app')
|
||||
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../lib/android/app')
|
||||
@@ -1,168 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
Button,
|
||||
TouchableHighlight
|
||||
} from 'react-native';
|
||||
|
||||
import {NotificationsAndroid, PendingNotifications} from 'react-native-notifications';
|
||||
|
||||
let mainScreen;
|
||||
|
||||
function onPushRegistered() {
|
||||
if (mainScreen) {
|
||||
mainScreen.onPushRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
function onNotificationOpened(notification) {
|
||||
if (mainScreen) {
|
||||
mainScreen.onNotificationOpened(notification)
|
||||
}
|
||||
}
|
||||
|
||||
function onNotificationReceived(notification) {
|
||||
if (mainScreen) {
|
||||
mainScreen.onNotificationReceived(notification)
|
||||
}
|
||||
}
|
||||
|
||||
// It's highly recommended to keep listeners registration at global scope rather than at screen-scope seeing that
|
||||
// component mount and unmount lifecycle tends to be asymmetric!
|
||||
NotificationsAndroid.setRegistrationTokenUpdateListener(onPushRegistered);
|
||||
NotificationsAndroid.setNotificationOpenedListener(onNotificationOpened);
|
||||
NotificationsAndroid.setNotificationReceivedListener(onNotificationReceived);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
titleText: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
bodyText: {
|
||||
fontSize: 18,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
mainButtonText: {
|
||||
fontSize: 25,
|
||||
fontStyle: 'italic',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
plainButtonText: {
|
||||
fontSize: 18,
|
||||
fontStyle: 'italic',
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
});
|
||||
|
||||
class MainComponent extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onPostNotification = this.onPostNotification.bind(this);
|
||||
this.onCancelNotification = this.onCancelNotification.bind(this);
|
||||
|
||||
this.state = {
|
||||
elapsed: 0,
|
||||
lastNotification: undefined
|
||||
};
|
||||
|
||||
console.log('ReactScreen', 'ReactScreen');
|
||||
mainScreen = this;
|
||||
|
||||
setInterval(this.onTick.bind(this), 1000);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log('ReactScreen', 'componentDidMount');
|
||||
PendingNotifications.getInitialNotification()
|
||||
.then((notification) => {console.log("getInitialNotification:", notification); this.setState({initialNotification: (notification ? notification.getData() : undefined)});})
|
||||
.catch((err) => console.error("getInitialNotifiation failed", err));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.log('ReactScreen', 'componentWillUnmount');
|
||||
}
|
||||
|
||||
onTick() {
|
||||
this.setState({elapsed: this.state.elapsed + 1});
|
||||
}
|
||||
|
||||
onPostNotification() {
|
||||
this.lastNotificationId = NotificationsAndroid.localNotification({title: "Local notification", body: "This notification was generated by the app!"});
|
||||
}
|
||||
|
||||
onCancelNotification() {
|
||||
if (this.lastNotificationId) {
|
||||
NotificationsAndroid.cancelLocalNotification(this.lastNotificationId);
|
||||
this.lastNotificationId = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.titleText}>Wix React Native Notifications</Text>
|
||||
<Text style={styles.bodyText}>{this.state.initialNotification ? 'Opened from notification' : ''}</Text>
|
||||
<Text style={styles.bodyText}>Last notification: {this.state.lastNotification ? '\n'+this.state.lastNotification.body + ` (opened at ''${this.state.notificationRxTime})` : "N/A"}</Text>
|
||||
<Text style={styles.bodyText}>Time elapsed: {this.state.elapsed}</Text>
|
||||
<Text>{"\n\n"}</Text>
|
||||
<TouchableHighlight onPress={() => this.onPostNotification()}>
|
||||
<Text style={styles.mainButtonText}>Try Me!</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={() => this.onCancelNotification()}>
|
||||
<Text style={styles.plainButtonText}>Undo last</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={() => this.onCheckPermissions()}>
|
||||
<Text style={styles.plainButtonText}>Check permissions</Text>
|
||||
</TouchableHighlight>
|
||||
<Button title={'Send local notification'} onPress={this.sendLocalNotification} testID={'sendLocalNotification'}/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
async onCheckPermissions() {
|
||||
const hasPermissions = await NotificationsAndroid.isRegisteredForRemoteNotifications();
|
||||
if (hasPermissions) {
|
||||
alert('Yay! You have permissions');
|
||||
} else {
|
||||
alert('Boo! You don\'t have permissions');
|
||||
}
|
||||
}
|
||||
|
||||
sendLocalNotification() {
|
||||
NotificationsAndroid.localNotification({
|
||||
title: "Local notification",
|
||||
body: "This notification was generated by the app!",
|
||||
extra: "data"
|
||||
});
|
||||
}
|
||||
|
||||
onPushRegistered() {
|
||||
}
|
||||
|
||||
onNotificationOpened(notification) {
|
||||
console.log("onNotificationOpened: ", notification);
|
||||
this.setState({lastNotification: notification.getData(), notificationRxTime: this.state.elapsed});
|
||||
}
|
||||
|
||||
onNotificationReceived(notification) {
|
||||
console.log("onNotificationReceived: ", notification);
|
||||
}
|
||||
}
|
||||
|
||||
AppRegistry.registerComponent('WixRNNotifications', () => MainComponent);
|
||||
@@ -1,160 +0,0 @@
|
||||
import {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
Button
|
||||
} from 'react-native';
|
||||
import React, {Component} from 'react';
|
||||
|
||||
import NotificationsIOS, { NotificationAction, NotificationCategory } from 'react-native-notifications';
|
||||
|
||||
let upvoteAction = new NotificationAction({
|
||||
activationMode: 'background',
|
||||
title: String.fromCodePoint(0x1F44D),
|
||||
identifier: 'UPVOTE_ACTION'
|
||||
});
|
||||
|
||||
let replyAction = new NotificationAction({
|
||||
activationMode: 'background',
|
||||
title: 'Reply',
|
||||
authenticationRequired: true,
|
||||
textInput: {
|
||||
buttonTitle: 'Reply now',
|
||||
placeholder: 'Insert message'
|
||||
},
|
||||
identifier: 'REPLY_ACTION'
|
||||
});
|
||||
|
||||
class NotificationsExampleApp extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
notifications: []
|
||||
};
|
||||
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.addEventListener('remoteNotificationsRegistrationFailed', this.onPushRegisteredFailed.bind(this));
|
||||
|
||||
NotificationsIOS.addEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
|
||||
NotificationsIOS.registerPushKit();
|
||||
|
||||
NotificationsIOS.addEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
|
||||
NotificationsIOS.addEventListener('notificationOpened', this.onNotificationOpened.bind(this));
|
||||
NotificationsIOS.addEventListener('pushKitNotificationReceived', this.onPushKitNotificationReceived.bind(this));
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const initialNotification = await NotificationsIOS.getInitialNotification();
|
||||
if (initialNotification) {
|
||||
this.setState({notifications: [initialNotification.getData().link, ...this.state.notifications]});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onPushRegistered(deviceToken) {
|
||||
console.log('Device Token Received: ' + deviceToken);
|
||||
}
|
||||
|
||||
onPushRegisteredFailed(error) {
|
||||
console.log('Remote notifiction registration failed: ' + error);
|
||||
}
|
||||
|
||||
onPushKitRegistered(deviceToken) {
|
||||
console.log('PushKit Token Received: ' + deviceToken);
|
||||
}
|
||||
|
||||
onPushKitNotificationReceived(notification) {
|
||||
console.log('PushKit notification Received: ' + JSON.stringify(notification));
|
||||
}
|
||||
|
||||
onNotificationReceivedForeground(notification, completion) {
|
||||
console.log('Notification Received Foreground with title: ' + JSON.stringify(notification));
|
||||
this.setState({
|
||||
notifications: [...this.state.notifications, notification.getData().link]
|
||||
});
|
||||
|
||||
completion({alert: notification.getData().showAlert, sound: false, badge: false});
|
||||
}
|
||||
|
||||
onNotificationOpened(notification, completion, action) {
|
||||
console.log('Notification Opened: ' + JSON.stringify(notification) + JSON.stringify(action));
|
||||
this.setState({
|
||||
notifications: [...this.state.notifications, `Notification Clicked: ${notification.getData().link}`]
|
||||
});
|
||||
completion();
|
||||
}
|
||||
|
||||
renderNotification(notification) {
|
||||
return <Text>{`${notification}`}</Text>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const notifications = this.state.notifications.map((notification, idx) =>
|
||||
(
|
||||
<View key={`notification_${idx}`}>
|
||||
{this.renderNotification(notification)}
|
||||
</View>
|
||||
));
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Button title={'Request permissions'} onPress={this.requestPermissions} testID={'requestPermissions'}/>
|
||||
<Button title={'Send local notification'} onPress={this.sendLocalNotification} testID={'sendLocalNotification'}/>
|
||||
<Button title={'Remove all delivered notifications'} onPress={this.removeAllDeliveredNotifications}/>
|
||||
{notifications}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
requestPermissions() {
|
||||
let cat = new NotificationCategory({
|
||||
identifier: 'SOME_CATEGORY',
|
||||
actions: [upvoteAction, replyAction]
|
||||
});
|
||||
NotificationsIOS.requestPermissions([cat]);
|
||||
}
|
||||
|
||||
sendLocalNotification() {
|
||||
NotificationsIOS.localNotification({
|
||||
body: 'Local notificiation!',
|
||||
title: 'Local Notification Title',
|
||||
sound: 'chime.aiff',
|
||||
category: 'SOME_CATEGORY',
|
||||
userInfo: { link: 'localNotificationLink' },
|
||||
});
|
||||
}
|
||||
|
||||
removeAllDeliveredNotifications() {
|
||||
NotificationsIOS.removeAllDeliveredNotifications();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
NotificationsIOS.removeEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
|
||||
NotificationsIOS.removeEventListener('notificationOpened', this.onNotificationOpened.bind(this));
|
||||
NotificationsIOS.removeEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
|
||||
NotificationsIOS.removeEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
instructions: {
|
||||
textAlign: 'center',
|
||||
color: '#333333',
|
||||
marginBottom: 5,
|
||||
},
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('NotificationsExampleApp', () => NotificationsExampleApp);
|
||||
157
example/index.js
Normal file
157
example/index.js
Normal file
@@ -0,0 +1,157 @@
|
||||
import {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
Button
|
||||
} from 'react-native';
|
||||
import React, {Component} from 'react';
|
||||
import {Notifications, NotificationAction, NotificationCategory} from 'react-native-notifications';
|
||||
|
||||
class NotificationsExampleApp extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
notifications: [],
|
||||
openedNotifications: [],
|
||||
};
|
||||
|
||||
this.registerNotificationEvents();
|
||||
this.setCategories();
|
||||
}
|
||||
|
||||
registerNotificationEvents() {
|
||||
Notifications.events().registerNotificationReceived((notification, completion) => {
|
||||
this.setState({
|
||||
notifications: [...this.state.notifications, notification]
|
||||
});
|
||||
|
||||
completion({alert: notification.payload.showAlert, sound: false, badge: false});
|
||||
});
|
||||
|
||||
Notifications.events().registerRemoteNotificationOpened((notification, completion) => {
|
||||
this.setState({
|
||||
openedNotifications: [...this.state.openedNotifications, notification]
|
||||
});
|
||||
|
||||
completion();
|
||||
});
|
||||
}
|
||||
|
||||
requestPermissions() {
|
||||
Notifications.registerRemoteNotifications();
|
||||
}
|
||||
|
||||
setCategories() {
|
||||
const upvoteAction = new NotificationAction({
|
||||
activationMode: 'background',
|
||||
title: String.fromCodePoint(0x1F44D),
|
||||
identifier: 'UPVOTE_ACTION'
|
||||
});
|
||||
|
||||
const replyAction = new NotificationAction({
|
||||
activationMode: 'background',
|
||||
title: 'Reply',
|
||||
authenticationRequired: true,
|
||||
textInput: {
|
||||
buttonTitle: 'Reply now',
|
||||
placeholder: 'Insert message'
|
||||
},
|
||||
identifier: 'REPLY_ACTION'
|
||||
});
|
||||
|
||||
|
||||
const category = new NotificationCategory({
|
||||
identifier: 'SOME_CATEGORY',
|
||||
actions: [upvoteAction, replyAction]
|
||||
});
|
||||
|
||||
Notifications.setCategories([category]);
|
||||
}
|
||||
|
||||
sendLocalNotification() {
|
||||
Notifications.postLocalNotification({
|
||||
body: 'Local notificiation!',
|
||||
title: 'Local Notification Title',
|
||||
sound: 'chime.aiff',
|
||||
category: 'SOME_CATEGORY',
|
||||
link: 'localNotificationLink',
|
||||
});
|
||||
}
|
||||
|
||||
removeAllDeliveredNotifications() {
|
||||
Notifications.removeAllDeliveredNotifications();
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const initialNotification = await Notifications.getInitialNotification();
|
||||
if (initialNotification) {
|
||||
this.setState({notifications: [initialNotification, ...this.state.notifications]});
|
||||
}
|
||||
}
|
||||
|
||||
renderNotification(notification) {
|
||||
return (
|
||||
<View style={{backgroundColor: 'lightgray', margin: 10}}>
|
||||
<Text>{`Title: ${notification.title}`}</Text>
|
||||
<Text>{`Body: ${notification.body}`}</Text>
|
||||
<Text>{`Extra Link Param: ${notification.payload.link}`}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderOpenedNotification(notification) {
|
||||
return (
|
||||
<View style={{backgroundColor: 'lightgray', margin: 10}}>
|
||||
<Text>{`Title: ${notification.title}`}</Text>
|
||||
<Text>{`Body: ${notification.body}`}</Text>
|
||||
<Text>{`Notification Clicked: ${notification.payload.link}`}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const notifications = this.state.notifications.map((notification, idx) =>
|
||||
(
|
||||
<View key={`notification_${idx}`}>
|
||||
{this.renderNotification(notification)}
|
||||
</View>
|
||||
));
|
||||
const openedNotifications = this.state.openedNotifications.map((notification, idx) =>
|
||||
(
|
||||
<View key={`notification_${idx}`}>
|
||||
{this.renderOpenedNotification(notification)}
|
||||
</View>
|
||||
));
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Button title={'Request permissions'} onPress={this.requestPermissions} testID={'requestPermissions'} />
|
||||
<Button title={'Send local notification'} onPress={this.sendLocalNotification} testID={'sendLocalNotification'} />
|
||||
<Button title={'Remove all delivered notifications'} onPress={this.removeAllDeliveredNotifications} />
|
||||
{notifications}
|
||||
{openedNotifications}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
instructions: {
|
||||
textAlign: 'center',
|
||||
color: '#333333',
|
||||
marginBottom: 5,
|
||||
},
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('NotificationsExampleApp', () => NotificationsExampleApp);
|
||||
@@ -276,7 +276,7 @@
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
D84861172267695100E9103D /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
D85498C21D97B31100DEEE06 /* RNNotifications.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNNotifications.xcodeproj; path = ../../RNNotifications/RNNotifications.xcodeproj; sourceTree = "<group>"; };
|
||||
D85498C21D97B31100DEEE06 /* RNNotifications.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNNotifications.xcodeproj; path = ../../lib/ios/RNNotifications.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -431,6 +431,7 @@
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */,
|
||||
50F1F0A022CE3B0600FD5829 /* RCTNetwork.xcodeproj */,
|
||||
D85498C21D97B31100DEEE06 /* RNNotifications.xcodeproj */,
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */,
|
||||
@@ -531,6 +532,10 @@
|
||||
ProductGroup = 50F1F08622CE3A9F00FD5829 /* Products */;
|
||||
ProjectRef = 50F1F08522CE3A9F00FD5829 /* RCTActionSheet.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 50CBD3A322F2556900142352 /* Products */;
|
||||
ProjectRef = 50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 50F1F09022CE3ABE00FD5829 /* Products */;
|
||||
ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
|
||||
@@ -866,7 +871,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-notifications/lib/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = NotificationsExampleApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
@@ -891,7 +896,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-notifications/lib/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = NotificationsExampleApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
BlueprintIdentifier = "508CE7C722D12B2600357815"
|
||||
BuildableName = "RNNotificationsTests.xctest"
|
||||
BlueprintName = "RNNotificationsTests"
|
||||
ReferencedContainer = "container:../../RNNotifications/RNNotifications.xcodeproj">
|
||||
ReferencedContainer = "container:../../lib/ios/RNNotifications.xcodeproj">
|
||||
</BuildableReference>
|
||||
</CodeCoverageTargets>
|
||||
<Testables>
|
||||
@@ -81,7 +81,7 @@
|
||||
BlueprintIdentifier = "508CE7C722D12B2600357815"
|
||||
BuildableName = "RNNotificationsTests.xctest"
|
||||
BlueprintName = "RNNotificationsTests"
|
||||
ReferencedContainer = "container:../../RNNotifications/RNNotifications.xcodeproj">
|
||||
ReferencedContainer = "container:../../lib/ios/RNNotifications.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
require('./example/index');
|
||||
@@ -1,15 +1,44 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
Object findReactNativePackageJson() {
|
||||
def searchPath = 'node_modules/react-native/package.json'
|
||||
def projectDir = project.projectDir.toString() + '/'
|
||||
def rnPackageJsonFile = new File(projectDir + searchPath)
|
||||
while (!rnPackageJsonFile.exists()) {
|
||||
searchPath = '../' + searchPath
|
||||
rnPackageJsonFile = new File(projectDir + searchPath)
|
||||
}
|
||||
return rnPackageJsonFile
|
||||
}
|
||||
|
||||
String resolveFlavor() {
|
||||
def packageSlurper = new JsonSlurper()
|
||||
def rnPackageJsonFile = findReactNativePackageJson()
|
||||
def reactNativePackageJson = packageSlurper.parseText(rnPackageJsonFile.text)
|
||||
def reactNativeVersion = reactNativePackageJson.version
|
||||
|
||||
List versionComponents = reactNativeVersion.tokenize('.')
|
||||
|
||||
if (versionComponents[1].toInteger() < 60) {
|
||||
return "reactNative59"
|
||||
} else {
|
||||
return "reactNative60"
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
@@ -19,6 +48,7 @@ android {
|
||||
debuggable true
|
||||
}
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.all { t ->
|
||||
reports {
|
||||
@@ -52,6 +82,14 @@ android {
|
||||
dimension "RNNotifications.reactNativeVersion"
|
||||
}
|
||||
}
|
||||
|
||||
def flavor = resolveFlavor()
|
||||
variantFilter { variant ->
|
||||
def names = variant.flavors*.name
|
||||
if (!names.contains(flavor)) {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -6,6 +6,5 @@ public interface Defs {
|
||||
String TOKEN_RECEIVED_EVENT_NAME = "remoteNotificationsRegistered";
|
||||
|
||||
String NOTIFICATION_RECEIVED_EVENT_NAME = "notificationReceived";
|
||||
String NOTIFICATION_RECEIVED_FOREGROUND_EVENT_NAME = "notificationReceivedInForeground";
|
||||
String NOTIFICATION_OPENED_EVENT_NAME = "notificationOpened";
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.wix.reactnativenotifications.core.AppLifecycleFacadeHolder;
|
||||
import com.wix.reactnativenotifications.core.InitialNotificationHolder;
|
||||
@@ -40,7 +41,7 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "WixRNNotifications";
|
||||
return "RNBridgeModule";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,6 +107,10 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setCategories(ReadableArray categories) {
|
||||
|
||||
}
|
||||
|
||||
public void cancelDeliveredNotification(String tag, int notificationId) {
|
||||
IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
|
||||
notificationsDrawer.onNotificationClearRequest(tag, notificationId);
|
||||
@@ -23,7 +23,6 @@ import com.wix.reactnativenotifications.core.ProxyService;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME;
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_FOREGROUND_EVENT_NAME;
|
||||
|
||||
public class PushNotification implements IPushNotification {
|
||||
|
||||
@@ -64,9 +63,6 @@ public class PushNotification implements IPushNotification {
|
||||
public void onReceived() throws InvalidNotificationException {
|
||||
postNotification(null);
|
||||
notifyReceivedToJS();
|
||||
if (mAppLifecycleFacade.isAppVisible()) {
|
||||
notifiyReceivedForegroundNotificationToJS();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,10 +195,6 @@ public class PushNotification implements IPushNotification {
|
||||
mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
|
||||
}
|
||||
|
||||
private void notifiyReceivedForegroundNotificationToJS() {
|
||||
mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_FOREGROUND_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
|
||||
}
|
||||
|
||||
private void notifyOpenedToJS() {
|
||||
mJsIOHelper.sendEventToJS(NOTIFICATION_OPENED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
|
||||
}
|
||||
@@ -6,16 +6,6 @@ public class PushNotificationProps {
|
||||
|
||||
protected Bundle mBundle;
|
||||
|
||||
public PushNotificationProps() {
|
||||
mBundle = new Bundle();
|
||||
}
|
||||
|
||||
public PushNotificationProps(String title, String body) {
|
||||
mBundle = new Bundle();
|
||||
mBundle.putString("title", title);
|
||||
mBundle.putString("body", body);
|
||||
}
|
||||
|
||||
public PushNotificationProps(Bundle bundle) {
|
||||
mBundle = bundle;
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import com.google.android.gms.tasks.OnSuccessListener;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.iid.InstanceIdResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.LOGTAG;
|
||||
import static com.wix.reactnativenotifications.Defs.TOKEN_RECEIVED_EVENT_NAME;
|
||||
|
||||
@@ -86,6 +88,9 @@ public class FcmToken implements IFcmToken {
|
||||
|
||||
// Note: Cannot assume react-context exists cause this is an async dispatched service.
|
||||
if (reactContext != null && reactContext.hasActiveCatalystInstance()) {
|
||||
HashMap<String, String> h = new HashMap<String, String>() {{
|
||||
put("deviceToken",sToken);
|
||||
}};
|
||||
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(TOKEN_RECEIVED_EVENT_NAME, sToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.wix.reactnativenotifications;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
public abstract class NotificationManagerCompatFacade {
|
||||
public static NotificationManagerCompat from(@NonNull Context context) {
|
||||
return NotificationManagerCompat.from(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.wix.reactnativenotifications;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
public abstract class NotificationManagerCompatFacade {
|
||||
public static NotificationManagerCompat from(@NonNull Context context) {
|
||||
return NotificationManagerCompat.from(context);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ allprojects {
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
0
android/gradlew → lib/android/gradlew
vendored
0
android/gradlew → lib/android/gradlew
vendored
@@ -10,7 +10,7 @@
|
||||
@end
|
||||
|
||||
@interface RCTConvert (UNNotificationRequest)
|
||||
+ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSString*)notificationId;
|
||||
+ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSNumber*)notificationId;
|
||||
@end
|
||||
|
||||
@interface RCTConvert (UNNotification)
|
||||
@@ -1,13 +1,5 @@
|
||||
#import "RCTConvert+RNNotifications.h"
|
||||
|
||||
|
||||
@implementation RCTConvert (UIUserNotificationActivationMode)
|
||||
RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
|
||||
@"foreground": @(UIUserNotificationActivationModeForeground),
|
||||
@"background": @(UIUserNotificationActivationModeBackground)
|
||||
}), UIUserNotificationActivationModeForeground, integerValue)
|
||||
@end
|
||||
|
||||
@implementation RCTConvert (UNNotificationActionOptions)
|
||||
|
||||
+ (UNNotificationActionOptions)UNUserNotificationActionOptions:(id)json {
|
||||
@@ -63,7 +55,7 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
|
||||
|
||||
@implementation RCTConvert (UNNotificationRequest)
|
||||
|
||||
+ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSString*)notificationId
|
||||
+ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSNumber*)notificationId
|
||||
{
|
||||
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
|
||||
|
||||
@@ -76,7 +68,7 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
|
||||
if ([RCTConvert BOOL:details[@"silent"]]) {
|
||||
content.sound = nil;
|
||||
}
|
||||
content.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]] ?: @{};
|
||||
content.userInfo = [RCTConvert NSDictionary:details] ?: @{};
|
||||
content.categoryIdentifier = [RCTConvert NSString:details[@"category"]];
|
||||
|
||||
NSDate *triggerDate = [RCTConvert NSDate:details[@"fireDate"]];
|
||||
@@ -92,7 +84,7 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
|
||||
repeats:NO];
|
||||
}
|
||||
|
||||
return [UNNotificationRequest requestWithIdentifier:notificationId
|
||||
return [UNNotificationRequest requestWithIdentifier:[NSString stringWithFormat:@"%@", notificationId]
|
||||
content:content trigger:trigger];
|
||||
}
|
||||
|
||||
@@ -117,7 +109,8 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
|
||||
formattedNotification[@"body"] = RCTNullIfNil(content.body);
|
||||
formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
|
||||
formattedNotification[@"thread"] = RCTNullIfNil(content.threadIdentifier);
|
||||
[formattedNotification addEntriesFromDictionary:RCTNullIfNil(RCTJSONClean(content.userInfo))];
|
||||
|
||||
[formattedNotification addEntriesFromDictionary:[NSDictionary dictionaryWithDictionary:RCTNullIfNil(RCTJSONClean(content.userInfo))]];
|
||||
|
||||
return formattedNotification;
|
||||
}
|
||||
@@ -32,8 +32,12 @@ RCT_EXPORT_MODULE();
|
||||
|
||||
#pragma mark - JS interface
|
||||
|
||||
RCT_EXPORT_METHOD(requestPermissionsWithCategories:(NSArray *)json) {
|
||||
[_commandsHandler requestPermissionsWithCategories:json];
|
||||
RCT_EXPORT_METHOD(requestPermissions) {
|
||||
[_commandsHandler requestPermissions];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setCategories:(NSArray *)categories) {
|
||||
[_commandsHandler setCategories:categories];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
|
||||
@@ -56,16 +60,16 @@ RCT_EXPORT_METHOD(registerPushKit) {
|
||||
[_commandsHandler registerPushKit];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getBadgesCount:(RCTResponseSenderBlock)callback) {
|
||||
[_commandsHandler getBadgesCount:callback];
|
||||
RCT_EXPORT_METHOD(getBadgeCount:(RCTResponseSenderBlock)callback) {
|
||||
[_commandsHandler getBadgeCount:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setBadgesCount:(int)count) {
|
||||
[_commandsHandler setBadgesCount:count];
|
||||
RCT_EXPORT_METHOD(setBadgeCount:(int)count) {
|
||||
[_commandsHandler setBadgeCount:count];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification withId:(NSString *)notificationId) {
|
||||
[_commandsHandler sendLocalNotification:notification withId:notificationId];
|
||||
RCT_EXPORT_METHOD(postLocalNotification:(NSDictionary *)notification withId:(nonnull NSNumber *)notificationId) {
|
||||
[_commandsHandler postLocalNotification:notification withId:notificationId];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId) {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user