diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index bf8553b5e..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100755 index 000000000..27d2dae2b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +*/node_modules +*.log diff --git a/.gitignore b/.gitignore index 8c499494b..82b4d3ace 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file + +# Typescript build +lib/dist/ diff --git a/.npmignore b/.npmignore index 3edb07ad4..62b5ab7b4 100644 --- a/.npmignore +++ b/.npmignore @@ -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/ \ No newline at end of file +.history/ +.github/ \ No newline at end of file diff --git a/CHANGELOG.gren.md b/CHANGELOG.gren.md index 338ef29f4..6b184e8a6 100644 --- a/CHANGELOG.gren.md +++ b/CHANGELOG.gren.md @@ -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.* diff --git a/Dockerfile b/Dockerfile new file mode 100755 index 000000000..d369844d5 --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/README.md b/README.md index 21eeeb190..8bfe2a689 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# React Native Notifications [![CircleCI](https://circleci.com/gh/wix/react-native-notifications/tree/master.svg?style=svg)](https://circleci.com/gh/wix/react-native-notifications/tree/master) +# React Native Notifications +![npm](https://img.shields.io/npm/dw/react-native-notifications.svg) +[![Build Status](https://img.shields.io/jenkins/s/http/jenkins-oss.wixpress.com:8080/job/multi-react-native-notifications-master.svg)](https://jenkins-oss.wixpress.com/job/multi-react-native-notifications-master/) +[![npm (tag)](https://img.shields.io/npm/v/react-native-notifications/snapshot.svg)](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. diff --git a/RNNotifications/RNEventEmitter.h b/RNNotifications/RNEventEmitter.h deleted file mode 100644 index 011477d98..000000000 --- a/RNNotifications/RNEventEmitter.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -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 - -+ (void)sendEvent:(NSString *)event body:(NSDictionary *)body; - -@end diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100755 index 000000000..6711192ae --- /dev/null +++ b/docker-compose.yml @@ -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 diff --git a/docs/advanced-ios.md b/docs/advanced-ios.md new file mode 100644 index 000000000..c2e7f0dd5 --- /dev/null +++ b/docs/advanced-ios.md @@ -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). + +![Interactive Notifications](http://i.imgur.com/XrVzy9w.gif) + + +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); +``` diff --git a/docs/android-api.md b/docs/android-api.md new file mode 100755 index 000000000..9ee6f9871 --- /dev/null +++ b/docs/android-api.md @@ -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(); +``` diff --git a/docs/general-api.md b/docs/general-api.md new file mode 100755 index 000000000..0e0c17992 --- /dev/null +++ b/docs/general-api.md @@ -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(); +``` diff --git a/docs/general-events.md b/docs/general-events.md new file mode 100755 index 000000000..d1e5a55d7 --- /dev/null +++ b/docs/general-events.md @@ -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); +}); +``` \ No newline at end of file diff --git a/docs/installation-android.md b/docs/installation-android.md new file mode 100755 index 000000000..751e9240a --- /dev/null +++ b/docs/installation-android.md @@ -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 getPackages() { + return Arrays.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') +``` \ No newline at end of file diff --git a/docs/installation-ios.md b/docs/installation-ios.md new file mode 100755 index 000000000..9bf6d374a --- /dev/null +++ b/docs/installation-ios.md @@ -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]; +} \ No newline at end of file diff --git a/docs/ios-api.md b/docs/ios-api.md new file mode 100755 index 000000000..d422cdb9c --- /dev/null +++ b/docs/ios-api.md @@ -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); +``` \ No newline at end of file diff --git a/docs/ios-events.md b/docs/ios-events.md new file mode 100755 index 000000000..8a939194b --- /dev/null +++ b/docs/ios-events.md @@ -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)); +}); +``` + diff --git a/docs/localNotifications.md b/docs/localNotifications.md index 8f1d2b948..db3b6b1e7 100644 --- a/docs/localNotifications.md +++ b/docs/localNotifications.md @@ -1,7 +1,10 @@ +--- +id: localNotifications +title: Local Notifications +sidebar_label: Local Notifications +--- -# Local Notifications - -## iOS + 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). -## Android + 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" diff --git a/docs/notification-object.md b/docs/notification-object.md new file mode 100755 index 000000000..9fa404f66 --- /dev/null +++ b/docs/notification-object.md @@ -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}); +}); +``` \ No newline at end of file diff --git a/docs/notifications-events.md b/docs/notifications-events.md new file mode 100644 index 000000000..a969868f1 --- /dev/null +++ b/docs/notifications-events.md @@ -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. diff --git a/docs/subscription.md b/docs/subscription.md index ddd493e62..1b5038c6d 100644 --- a/docs/subscription.md +++ b/docs/subscription.md @@ -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. -## 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); - } - - 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.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); + }); + + 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); }); ``` - - -## 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. diff --git a/docs/advancedIos.md b/docs_old/advancedIos.md similarity index 98% rename from docs/advancedIos.md rename to docs_old/advancedIos.md index 27f69ce15..be68a9319 100644 --- a/docs/advancedIos.md +++ b/docs_old/advancedIos.md @@ -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); ``` diff --git a/docs/installation.md b/docs_old/installation.md similarity index 98% rename from docs/installation.md rename to docs_old/installation.md index 968ac9788..bf476e421 100644 --- a/docs/installation.md +++ b/docs_old/installation.md @@ -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`: diff --git a/docs_old/localNotifications.md b/docs_old/localNotifications.md new file mode 100644 index 000000000..8f1d2b948 --- /dev/null +++ b/docs_old/localNotifications.md @@ -0,0 +1,84 @@ + +# Local Notifications + +## 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). + + +## 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). diff --git a/docs/notificationsEvents.md b/docs_old/notificationsEvents.md similarity index 100% rename from docs/notificationsEvents.md rename to docs_old/notificationsEvents.md diff --git a/docs_old/subscription.md b/docs_old/subscription.md new file mode 100644 index 000000000..ddd493e62 --- /dev/null +++ b/docs_old/subscription.md @@ -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. + +## 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); +}); +``` + + +## 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. diff --git a/e2e/Notifications.test.js b/e2e/Notifications.test.js index d6ede1100..09881409d 100644 --- a/e2e/Notifications.test.js +++ b/e2e/Notifications.test.js @@ -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}) { diff --git a/example/android/myapplication/build.gradle b/example/android/myapplication/build.gradle index af1baf57e..cbfe3869d 100644 --- a/example/android/myapplication/build.gradle +++ b/example/android/myapplication/build.gradle @@ -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 { diff --git a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java index 48f4dabc7..e600962f1 100644 --- a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java +++ b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java @@ -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"; } } diff --git a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java index 110f09a93..021e42a17 100644 --- a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java +++ b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java @@ -30,7 +30,12 @@ protected List getPackages() { return Arrays.asList( new MainReactPackage(), new RNNotificationsPackage(MainApplication.this) - ); + ); + } + + @Override + protected String getJSMainModuleName() { + return "index"; } }; diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 8e11e0797..ac64752eb 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,4 +1,4 @@ include ':myapplication' include ':react-native-notifications' -project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../android/app') \ No newline at end of file +project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../lib/android/app') \ No newline at end of file diff --git a/example/index.android.js b/example/index.android.js deleted file mode 100644 index 5c7faaf0f..000000000 --- a/example/index.android.js +++ /dev/null @@ -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 ( - - Wix React Native Notifications - {this.state.initialNotification ? 'Opened from notification' : ''} - Last notification: {this.state.lastNotification ? '\n'+this.state.lastNotification.body + ` (opened at ''${this.state.notificationRxTime})` : "N/A"} - Time elapsed: {this.state.elapsed} - {"\n\n"} - this.onPostNotification()}> - Try Me! - - this.onCancelNotification()}> - Undo last - - this.onCheckPermissions()}> - Check permissions - -