Commit 8ef5e0d2 authored by Bess's avatar Bess Committed by GitHub

Merge pull request #1 from wix/v3

V3 merge
parents 77f672cd 6fe705ff
*/node_modules
*.log
......@@ -2,7 +2,7 @@
"parser": "babel-eslint",
"env": {
"node": true,
"mocha": true,
"jest": true,
"es6": true
},
"extends": "eslint:recommended",
......@@ -18,7 +18,7 @@
"no-trailing-spaces": "error",
"quotes": [
"error",
"double"
"single"
],
"semi": [
"error",
......
workflow "Verify labels" {
on = "pull_request"
resolves = "Enforce PR label"
}
action "Enforce PR label" {
uses = "yogevbd/enforce-label-action@1.0.0"
secrets = ["GITHUB_TOKEN"]
env = {
VALID_LABELS = "bug,enhancement,feature,skip-changelog"
}
}
\ No newline at end of file
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- "type: accepted/enhancement"
- "user: looking for contributors"
- "📌 pinned"
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: "🏚 stale"
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
The issue has been closed for inactivity.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
daysUntilStale: 45
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# issues:
# exemptLabels:
# - confirmed
# Configuration for support-requests - https://github.com/dessant/support-requests
# Label used to mark issues as support requests
supportLabel: "type: question/stack overflow"
# Comment to post on issues marked as support requests. Add a link
# to a support page, or set to `false` to disable
supportComment: >
We use the issue tracker exclusively for bug reports and feature requests.
This issue appears to be a general usage or support question.
Instead, please ask a question on Stack Overflow with the `react-native-notifications` tag.
# Whether to close issues marked as support requests
close: true
# Whether to lock issues marked as support requests
lock: false
......@@ -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
......@@ -178,3 +182,15 @@ jspm_packages
# Optional REPL history
.node_repl_history
# Intellij
*.iml
coverage/
package-lock.json
.history
# Typescript build
lib/dist/
module.exports = {
template: {
commit: ({message, url, author, name}) => `- [${message}](${url}) - ${author ? `@${author}` : name}`,
issue: "- {{name}} [{{text}}]({{url}})",
label: "[**{{label}}**]",
noLabel: "closed",
group: "\n#### {{heading}}\n",
changelogTitle: "# Changelog\n\n",
release: "## {{release}} ({{date}})\n{{body}}",
releaseSeparator: "\n---\n\n"
},
groupBy: {
"Enhancements:": ["enhancement", "internal"],
"Bug Fixes:": ["bug"],
"Features": ["feature"]
},
ignoreIssuesWith: [
"skip-changelog"
],
ignoreTagsWith: [
"snapshot"
],
dataSource: "prs",
changelogFilename: "CHANGELOG.gren.md",
tags: "all",
override: true,
generate: true
}
\ No newline at end of file
example/
test/
RNNotifications/DerivedData
node_modules/
website/
docs/
docs_old/
scripts/
e2e/
.eslintrc
*.yml
coverage/
.history
android/.idea
android/build/
.idea
.history/
.github/
\ No newline at end of file
language: node_js
osx_image: xcode10.1
node_js:
- "7"
- "10"
# Changelog
## 3.0.0-beta.1 (07/10/2019)
*No changelog for this release.*
---
## 3.0.0-beta.0 (02/10/2019)
#### Bug Fixes:
- Remove vibrate permissions maxSdkVersion, fix example project on android [#388](https://github.com/wix/react-native-notifications/pull/388)
---
## 2.1.3 (22/09/2019)
#### Enhancements:
- Autogenerate changelog using github-release-notes [#382](https://github.com/wix/react-native-notifications/pull/382)
#### Bug Fixes:
- Fixing white square icon and annotation error [#379](https://github.com/wix/react-native-notifications/pull/379)
---
## 3.0.0-alpha.0 (15/09/2019)
*No changelog for this release.*
---
## 2.1.0 (14/09/2019)
#### Enhancements:
- React Native 0.60 Support [#375](https://github.com/wix/react-native-notifications/pull/375)
- New api changes ios [#342](https://github.com/wix/react-native-notifications/pull/342)
---
## v1.4.0 (18/04/2019)
*No changelog for this release.*
---
## v1.1.17 (26/10/2017)
*No changelog for this release.*
---
## v1.1.12 (13/07/2017)
*No changelog for this release.*
# Changelog
# 2.1.0
## Added
* react-native 0.60 Support
### Breaking Change
This version requires an additional installation step in order to identify the correct build flavor on android, as described in our [Installation doc](https://github.com/wix/react-native-notifications/blob/master/docs/installation.md#step-5-rnnotifications-and-react-native-version).
# 2.0.6
## Fixed
### Android
* Resolve intent by extra key and not by `google.message_id` string, Addresses #296. [#5056657](https://github.com/wix/react-native-notifications/pull/358/commits/5056657a6b3041b0c272357afcded42e59b83433) by [yogevbd](https://github.com/yogevbd)
# 2.0.5
## Fixed
### Android
* Reverted #349, This caused our e2e tests to fail, therefor we reverted this PR and will resolve this issue in the next version [#0b70828](https://github.com/wix/react-native-notifications/pull/357/commits/0b70828ca3e1f4e00817a32d6327381b4605c75c) by [yogevbd](https://github.com/yogevbd)
# 2.0.4
## Fixed
* Fix missing badge in silent notification payload with no aps.alert [#21c684d](https://github.com/wix/react-native-notifications/commit/21c684dbb7f632644747fa884c1b3f2bfd87f0a5) by [yogevbd](https://github.com/yogevbd)
Moved our builds to CircleCI and added iOS unit and e2e tests coverage.
# 2.0.3
## Fixed
### Android
* Remove verify notification [#57190f7](https://github.com/wix/react-native-notifications/commit/57190f7ed239022da28f62cb6e4d04e5fd5d48d1) by [yogevbd](https://github.com/yogevbd)
* Bring native unit tests back to life [#11f370b](https://github.com/wix/react-native-notifications/commit/11f370b380c4f9dd0365cc4866114722fa70a393) by [yogevbd](https://github.com/yogevbd)
## Fixed
### iOS
* Fix iOS build on RN0.59 [#b90ea92](https://github.com/wix/react-native-notifications/commit/b90ea920b195a80bc218e15f58222af1701bf79f) by [lionerez1](https://github.com/lionerez1)
### Breaking change
* Updated the android [installation setup guide](https://github.com/wix/react-native-notifications/blob/master/docs/installation.md).
Make sure settings gradle imports from `'../node_modules/react-native-notifications/android/app'` and not `'../node_modules/react-native-notifications/android'`
```gradle
include ':reactnativenotifications'
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
```
* @yogevbd
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"]
# React Native Notifications [![Build Status](https://travis-ci.org/wix/react-native-notifications.svg)](https://travis-ci.org/wix/react-native-notifications)
# 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.
......
@import UIKit;
#import <React/RCTBridgeModule.h>
#import <PushKit/PushKit.h>
@interface RNNotifications : NSObject <RCTBridgeModule>
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken;
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
+ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
+ (void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification;
+ (void)handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler;
+ (void)handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler;
@end
This diff is collapsed.
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D85B37451CC05A0900DE9EB6 /* RNNotificationsBridgeQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D85B37441CC05A0900DE9EB6 /* RNNotificationsBridgeQueue.m */; };
D8A2F7551CB57F1A002CC8F5 /* RNNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = D8A2F7541CB57F1A002CC8F5 /* RNNotifications.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRNNotifications.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNNotifications.a; sourceTree = BUILT_PRODUCTS_DIR; };
D85B37441CC05A0900DE9EB6 /* RNNotificationsBridgeQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotificationsBridgeQueue.m; sourceTree = "<group>"; };
D85B37461CC05A1200DE9EB6 /* RNNotificationsBridgeQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNotificationsBridgeQueue.h; sourceTree = "<group>"; };
D8A2F7541CB57F1A002CC8F5 /* RNNotifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotifications.m; sourceTree = "<group>"; };
D8A2F7561CB57F28002CC8F5 /* RNNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNotifications.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRNNotifications.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
D85B37461CC05A1200DE9EB6 /* RNNotificationsBridgeQueue.h */,
D85B37441CC05A0900DE9EB6 /* RNNotificationsBridgeQueue.m */,
D8A2F7561CB57F28002CC8F5 /* RNNotifications.h */,
D8A2F7541CB57F1A002CC8F5 /* RNNotifications.m */,
134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RNNotifications */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNotifications" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RNNotifications;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRNNotifications.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNotifications" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RNNotifications */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D8A2F7551CB57F1A002CC8F5 /* RNNotifications.m in Sources */,
D85B37451CC05A0900DE9EB6 /* RNNotificationsBridgeQueue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../example/node_modules/react-native/React/**",
"$(SRCROOT)/../../react-native/React/**",
"$(SRCROOT)/../../../React/**",
);
LIBRARY_SEARCH_PATHS = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNNotifications;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../example/node_modules/react-native/React/**",
"$(SRCROOT)/../../react-native/React/**",
"$(SRCROOT)/../../../React/**",
);
LIBRARY_SEARCH_PATHS = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNNotifications;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNotifications" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNotifications" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}
#import <Foundation/Foundation.h>
@interface RNNotificationsBridgeQueue : NSObject
@property BOOL jsIsReady;
@property NSDictionary* openedRemoteNotification;
@property NSDictionary* openedLocalNotification;
+ (nonnull instancetype)sharedInstance;
- (void)postAction:(NSDictionary *)action withCompletionKey:(NSString *)completionKey andCompletionHandler:(void (^)())completionHandler;
- (void)postNotification:(NSDictionary *)notification;
- (void)consumeActionsQueue:(void (^)(NSDictionary *))block;
- (void)consumeNotificationsQueue:(void (^)(NSDictionary *))block;
- (void)completeAction:(NSString *)completionKey;
@end
\ No newline at end of file
#import "RNNotificationsBridgeQueue.h"
@implementation RNNotificationsBridgeQueue
NSMutableArray<NSDictionary *>* actionsQueue;
NSMutableArray<NSDictionary *>* notificationsQueue;
NSMutableDictionary* actionCompletionHandlers;
+ (nonnull instancetype)sharedInstance {
static RNNotificationsBridgeQueue* sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
- (instancetype)init
{
actionsQueue = [NSMutableArray new];
notificationsQueue = [NSMutableArray new];
actionCompletionHandlers = [NSMutableDictionary new];
self.jsIsReady = NO;
return self;
}
- (void)postNotification:(NSDictionary *)notification
{
if (!notificationsQueue) return;
[notificationsQueue insertObject:notification atIndex:0];
}
- (NSDictionary *)dequeueSingleNotification
{
if (!notificationsQueue || notificationsQueue.count == 0) return nil;
NSDictionary* notification = [notificationsQueue lastObject];
[notificationsQueue removeLastObject];
return notification;
}
- (void)consumeNotificationsQueue:(void (^)(NSDictionary *))block
{
NSDictionary* notification;
while ((notification = [self dequeueSingleNotification]) != nil) {
block(notification);
}
notificationsQueue = nil;
}
- (void)postAction:(NSDictionary *)action withCompletionKey:(NSString *)completionKey andCompletionHandler:(void (^)())completionHandler
{
// store completion handler
actionCompletionHandlers[completionKey] = completionHandler;
if (!actionsQueue) return;
[actionsQueue insertObject:action atIndex:0];
}
- (NSDictionary *)dequeueSingleAction
{
if (!actionsQueue || actionsQueue.count == 0) return nil;
NSDictionary* action = [actionsQueue lastObject];
[actionsQueue removeLastObject];
return action;
}
- (void)consumeActionsQueue:(void (^)(NSDictionary *))block
{
NSDictionary* lastActionInfo;
while ((lastActionInfo = [self dequeueSingleAction]) != nil) {
block(lastActionInfo);
}
actionsQueue = nil;
}
- (void)completeAction:(NSString *)completionKey
{
void (^completionHandler)() = (void (^)())[actionCompletionHandlers valueForKey:completionKey];
if (completionHandler) {
completionHandler();
[actionCompletionHandlers removeObjectForKey:completionKey];
}
}
@end
\ No newline at end of file
package com.wix.reactnativenotifications;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationManagerCompat;
public abstract class NotificationManagerCompatFacade {
public static NotificationManagerCompat from(@NonNull Context context) {
return NotificationManagerCompat.from(context);
}
}
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);
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// Google's GCM.
compile 'com.google.android.gms:play-services-gcm:15.0.1'
compile 'com.facebook.react:react-native:+'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.+'
testCompile 'org.robolectric:robolectric:3.1.4'
}
This diff is collapsed.
package com.wix.reactnativenotifications;
import android.app.Application;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class RNNotificationsPackage implements ReactPackage {
private final Application mApplication;
public RNNotificationsPackage(Application application) {
mApplication = application;
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNNotificationsModule(mApplication, reactContext));
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
package com.wix.reactnativenotifications.gcm;
import android.content.Intent;
import com.google.android.gms.iid.InstanceIDListenerService;
/**
* Instance-ID + token refreshing handling service. Contacts the GCM to fetch the updated token.
*
* @author amitd
*/
public class GcmInstanceIdListenerService extends InstanceIDListenerService {
@Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
// Google recommends running this from an intent service.
Intent intent = new Intent(this, GcmInstanceIdRefreshHandlerService.class);
startService(intent);
}
}
package com.wix.reactnativenotifications.gcm;
import android.content.Context;
public interface INotificationsGcmApplication {
IGcmToken getGcmToken(Context context);
}
module.exports = function (api) {
api && api.cache(false);
return {
presets: [
'module:metro-react-native-babel-preset'
],
plugins: [
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-export-default-from'
]
};
};
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
---
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.getBadgesCount((count) => console.log(count));
```
Set to specific number:
```javascript
Notifications.ios.setBadgesCount(2);
```
Clear badges icon:
```javascript
Notifications.ios.setBadgesCount(0);
```
---
id: android-api
title: Android Specific Commands
sidebar_label: Android specific
---
## refreshToken()
Request a new token for sending push notifications.
```js
Notifications.android.refreshToken();
```
---
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();
```
---
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
---
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'
```
---
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.
The 2nd is to do some platform specific setup so as to be able to work with Apple and Google's services for push notifications.
Start by running this:
```
$ npm install react-native-notifications --save
```
Then, [Manually link](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking) the library to your Xcode project.
To enable notifications support 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
---
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();
```
## removeAllDeliveredNotifications()
Remove all delivered notifications from Notification Center
```js
Notifications.ios.removeAllDeliveredNotifications();
```
## 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
---
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));
});
```
---
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,10 +12,10 @@ Triggering local notifications is fully compatible with React Native `PushNotifi
Example:
```javascript
let localNotification = NotificationsIOS.localNotification({
alertBody: "Local notificiation!",
alertTitle: "Local Notification Title",
soundName: "chime.aiff",
let localNotification = Notifications.postLocalNotification({
body: "Local notificiation!",
title: "Local Notification Title",
sound: "chime.aiff",
silent: false,
category: "SOME_CATEGORY",
userInfo: { }
......@@ -22,46 +25,46 @@ let localNotification = NotificationsIOS.localNotification({
Notification object contains:
- **`fireDate`**- The date and time when the system should deliver the notification (optinal - default is immidiate dispatch).
- `alertBody`- The message displayed in the notification alert.
- `alertTitle`- The title of the notification, displayed in the notifications center.
- `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.
- `soundName`- 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.
- `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)`.
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({
alertBody: "Local notificiation!",
alertTitle: "Local Notification Title",
soundName: "chime.aiff",
let someLocalNotification = Notifications.postLocalNotification({
body: "Local notificiation!",
title: "Local Notification Title",
sound: "chime.aiff",
category: "SOME_CATEGORY",
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"
......
---
id: notification-object
title: Notification object
sidebar_label: Notification
---
Contains the payload data.
- **`message`**- 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).
- **`data`**- returns the data payload (additional info) of the notification.
Example:
```js
Notifications.events().registerNotificationReceived((notification: Notification, completion: (response: NotificationCompletion) => void) => {
// Prints the notification payload
console.log(JSON.stringify(notification.data));
completion({alert: false, sound: false, badge: false});
});
```
\ No newline at end of file
---
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.
# 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);
}
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);
});
```
## <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.
......@@ -91,33 +91,31 @@ After [preparing your app to receive VoIP push notifications](https://developer.
#import <PushKit/PushKit.h>
```
And the following methods:
### Listen to PushKit notifications
On receiving PushKit notification, a `pushKitNotificationReceived` event will be fired with the notification payload.
```objective-c
// PushKit API Support
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
{
[RNNotifications didUpdatePushCredentials:credentials forType:type];
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
[RNNotifications didReceiveRemoteNotification:payload.dictionaryPayload];
}
```
#import "RNNotifications.h"
#import <PushKit/PushKit.h>
```
In your ReactNative code, add event handler for `pushKitRegistered` event and call to `registerPushKit()`:
```javascript
constructor() {
NotificationsIOS.addEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
NotificationsIOS.registerPushKit();
NotificationsIOS.addEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
NotificationsIOS.addEventListener('pushKitNotificationReceived', this.onPushKitNotificationReceived.bind(this));
NotificationsIOS.registerPushKit();
}
onPushKitRegistered(deviceToken) {
console.log("PushKit Token Received: " + deviceToken);
}
onPushKitNotificationReceived(notification) {
console.log('PushKit notification Received: ' + JSON.stringify(notification));
}
componentWillUnmount() {
// Don't forget to remove the event listeners to prevent memory leaks!
NotificationsIOS.removeEventListener('pushKitRegistered', onPushKitRegistered(this));
......@@ -150,22 +148,7 @@ 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.
In order to support interactive notifications, firstly add the following methods to `appDelegate.m` file:
```objective-c
// Required for the notification actions.
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler
{
[RNNotifications handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler
{
[RNNotifications handleActionWithIdentifier:identifier forRemoteNotification:userInfo withResponseInfo:responseInfo completionHandler:completionHandler];
}
```
Then, follow the basic workflow of adding interactive notifications to your app:
Follow the basic workflow of adding interactive notifications to your app:
1. Config the actions.
2. Group actions together into categories.
......@@ -182,26 +165,18 @@ import NotificationsIOS, { NotificationAction, NotificationCategory } from 'reac
let upvoteAction = new NotificationAction({
activationMode: "background",
title: String.fromCodePoint(0x1F44D),
identifier: "UPVOTE_ACTION"
}, (action, completed) => {
console.log("ACTION RECEIVED");
console.log(JSON.stringify(action));
// You must call to completed(), otherwise the action will not be triggered
completed();
identifier: "UPVOTE_ACTION",
textInput: {
buttonTitle: 'title',
placeholder: 'placeholder text'
}
});
let replyAction = new NotificationAction({
activationMode: "background",
title: "Reply",
behavior: "textInput",
authenticationRequired: true,
identifier: "REPLY_ACTION"
}, (action, completed) => {
console.log("ACTION RECEIVED");
console.log(action);
completed();
});
```
......@@ -212,8 +187,7 @@ We will group `upvote` action and `reply` action into a single category: `EXAMPL
```javascript
let exampleCategory = new NotificationCategory({
identifier: "EXAMPLE_CATEGORY",
actions: [upvoteAction, replyAction],
context: "default"
actions: [upvoteAction, replyAction]
});
```
......@@ -230,8 +204,8 @@ Notification payload should look like this:
```javascript
{
aps: {
// ... (alert, sound, badge, etc)
category: "EXAMPLE_CATEGORY"
// ... (alert, sound, badge, etc)
category: "EXAMPLE_CATEGORY"
}
}
```
......@@ -245,9 +219,7 @@ The [example app](https://github.com/wix/react-native-notifications/tree/master/
- `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.
- `behavior` - Indicating additional behavior that the action supports.
- `default` - No additional behavior.
- `textInput` - When button is tapped, the action opens a text input. the text will be delivered to your action callback.
- `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.
......@@ -255,9 +227,11 @@ The [example app](https://github.com/wix/react-native-notifications/tree/master/
- `identifier` - The name of the action group (must be unique).
- `actions` - An array of `NotificationAction` objects, which related to this category.
- `context` - Indicating the amount of space available for displaying actions in a notification.
- `default` (default) - Displayes up to 4 actions (full UI).
- `minimal` - Displays up tp 2 actions (minimal UI).
### `TextInput` Payload
- `buttonTitle` - Title of the `send` button.
- `placeholder` - Placeholder for the `textInput`.
#### Get and set application icon badges count (iOS only)
......
......@@ -7,7 +7,7 @@ The 2nd is to do some platform specific setup so as to be able to work with Appl
Start by running this:
```
$ npm install react-native-notifications --save
$ npm install react-native-notifications@^2.0.6 --save
```
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/2000px-Apple_logo_black.svg.png" width=30/> iOS
......@@ -20,17 +20,24 @@ Then, to enable notifications support add the following line at the top of your
#import "RNNotifications.h"
```
And the following methods to support registration and receiving notifications:
Start monitor notifications in: `application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions`
```objective-c
// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RNNotifications didRegisterUserNotificationSettings:notificationSettings];
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[RNNotifications startMonitorNotifications]; // -> Add this line
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
```
And add the following methods to support registration:
```objective-c
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
......@@ -38,16 +45,6 @@ And the following methods to support registration and receiving notifications:
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for the notification event.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification {
[RNNotifications didReceiveRemoteNotification:notification];
}
// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNNotifications didReceiveLocalNotification:notification];
}
```
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
......@@ -57,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')
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`:
......@@ -91,27 +88,99 @@ import com.wix.reactnativenotifications.RNNotificationsPackage;
> 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 GCM service](https://developers.google.com/cloud-messaging/gcm) (now integrated into Firebase). The following installation steps are a TL;DR of [Google's GCM setup guide](https://developers.google.com/cloud-messaging/android/client). You can follow them to get GCM integrated quickly, but we recommend that you will in the very least have a peek at the guide's overview.
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 GCM
#### Step #1: Subscribe to Google's FCM
To set GCM in your app, you must first create a Google API-project and obtain a **Sender ID** and a **Server API Key**. 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://developers.google.com/mobile/add); Use [this tutorial](https://code.tutsplus.com/tutorials/how-to-get-started-with-push-notifications-on-android--cms-25870) for insturctions.
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);
Alternatively, follow [Google's complete guide](https://developers.google.com/cloud-messaging/android/client#create-an-api-project).
#### Step #2: Add Sender ID to Manifest File
#### Step #2: Copy google-services.json
Once obtained, bundle the Sender ID onto your main `manifest.xml` file:
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
<manifest>
...
<application>
...
// Replace '1234567890' with your sender ID.
// IMPORTANT: Leave the trailing \0 intact!!!
<meta-data android:name="com.wix.reactnativenotifications.gcmSenderId" android:value="1234567890\0"/>
</application>
</manifest>
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: RNNotifications and React Native version
<B>This step is required only for `react-native-notifications` version `2.1.0` and above.</B> <Br>
react-native-notifications supports multiple React Native versions. Target the React Native version required by your project by specifying the RNN build flavor in `android/app/build.gradle`.
```diff
android {
...
defaultConfig {
applicationId "com.yourproject"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
+ missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!
versionCode 1
versionName "1.0"
...
}
...
}
```
!>Important note about `missingDimensionStrategy`<Br>
>`reactNative59` - RN 0.59.x and below<Br>
>`reactNative60` - RN 0.60.0 and above
Now we need to instruct gradle how to build that flavor. To do so here two solutions:
#### 5.1 Build app with gradle command
**prefered solution** The RNNotification flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .
```
"scripts": {
...
"android": "cd ./android && ./gradlew app:assembleDebug && ./gradlew installDebug"
}
```
Now run `npm run android` to build your application
#### 5.2 Ignore other RNN flavors
If you don't want to run `npm run android` and want to keep the default `react-native run-android` command, you need to specify to graddle to ignore the other flavors RNNotifications provides.
To do so edit `android/build.gradle` and add:
```diff
+subprojects { subproject ->
+ afterEvaluate {
+ if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
+ android {
+ variantFilter { variant ->
+ def names = variant.flavors*.name
+ if (names.contains("reactNative59")) {
+ setIgnore(true)
+ }
+ }
+ }
+ }
+ }
+}
```
**Note**: As more build variants come available in the future, you will need to adjust the list (`names.contains("reactNative59")`). This is why we recommend the first solution.
\ No newline at end of file
# 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).
......@@ -5,40 +5,35 @@
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 `notificationReceivedForeground` event will be fired.
2. **Background:** When the app is running in a background state; in this case, a `notificationReceivedBackground` event will be fired.
1. **Forground:** When the app is running and is used by the user right now; in this case, a `notificationReceivedForeground` 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.
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() {
this._boundOnNotificationReceivedForeground = this.onNotificationReceivedForeground.bind(this);
this._boundOnNotificationReceivedBackground = this.onNotificationReceivedBackground.bind(this);
this._boundOnNotificationOpened = this.onNotificationOpened.bind(this);
NotificationsIOS.addEventListener('notificationReceivedForeground', this._boundOnNotificationReceivedForeground);
NotificationsIOS.addEventListener('notificationReceivedBackground', this._boundOnNotificationReceivedBackground);
NotificationsIOS.addEventListener('notificationOpened', this._boundOnNotificationOpened);
}
onNotificationReceivedForeground(notification) {
onNotificationReceivedForeground(notification, completion) {
completion({alert: true, sound: false, badge: false});
console.log("Notification Received - Foreground", notification);
}
onNotificationReceivedBackground(notification) {
console.log("Notification Received - Background", notification);
}
onNotificationOpened(notification) {
onNotificationOpened(notification, completion, action) {
console.log("Notification opened by device user", notification);
console.log(`Notification opened with an action identifier: ${action.identifier} and response text: ${action.text}`, notification);
completion();
}
componentWillUnmount() {
// Don't forget to remove the event listeners to prevent memory leaks!
NotificationsIOS.removeEventListener('notificationReceivedForeground', this._boundOnNotificationReceivedForeground);
NotificationsIOS.removeEventListener('notificationReceivedBackground', this._boundOnNotificationReceivedBackground);
NotificationsIOS.removeEventListener('notificationOpened', this._boundOnNotificationOpened);
}
```
......@@ -54,12 +49,6 @@ When you receive a push notification, you'll get an instance of `IOSNotification
- **`getData()`**- returns the data payload (additional info) of the notification.
- **`getType()`**- returns `managed` for managed notifications, otherwise returns `regular`.
### Background Queue (Important - please read!)
When a push notification is opened but the app is not running, the application will be in a **cold launch** state, until the JS engine is up and ready to handle the notification.
The application will collect the events (notifications, actions, etc.) that happend during the cold launch for you.
When your app is ready (most of the time it's after the call to `requestPermissions()`), just call to `NotificationsIOS.consumeBackgroundQueue();` in order to consume the background queue. For more info see `index.ios.js` in the example app.
## <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/APK_format_icon.png/768px-APK_format_icon.png" width=30/> Android
......
# 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.
const Utils = require('./Utils');
const {elementByLabel} = Utils;
describe('Notifications', () => {
beforeEach(async () => {
await device.relaunchApp({delete: true, permissions: {notifications: 'YES'}});
});
describe('Foreground', () => {
it('Should receive notification', async () => {
await device.sendUserNotification(createNotification({link: 'foreground/notification'}));
await linkShouldBeVisible('foreground/notification');
});
it('Should open notification', async () => {
await device.sendUserNotification(createNotification({link: 'foreground/notification/click', showAlert: true}));
await expect(elementByLabel('Notification Clicked: foreground/notification/click')).toBeVisible();
});
});
describe('Background', () => {
it('Should open notification', async () => {
await device.sendToHome();
await expect(elementByLabel('Notification Clicked: background/notification')).toBeNotVisible();
await device.launchApp({newInstance: false, userNotification: createNotification({link: 'background/notification'})});
await expect(elementByLabel('Notification Clicked: background/notification')).toBeVisible();
});
});
describe('Dead state', () => {
it('Should receive notification', async () => {
await device.launchApp({newInstance: true, userNotification: createNotification({link: 'deadState/notification'})});
await linkShouldBeVisible('deadState/notification');
});
});
async function linkShouldBeVisible(link) {
return await expect(elementByLabel(`Extra Link Param: ${link}`)).toBeVisible();
}
});
function createNotification({link, showAlert}) {
return {
trigger: {
type: 'push'
},
title: 'From push',
subtitle: 'Subtitle',
body: 'Body',
badge: 1,
payload: {
link,
showAlert
}
};
}
module.exports = {
elementByLabel: (label) => {
return element(by.text(label));
},
elementById: (id) => {
return element(by.id(id));
},
tapBackIos: () => {
try {
return element(by.traits(['button']).and(by.label('Back'))).atIndex(0).tap();
} catch (err) {
return element(by.type('_UIModernBarButton').and(by.label('Back'))).tap();
}
},
sleep: ms => new Promise(res => setTimeout(res, ms))
};
{
"setupTestFrameworkScriptFile" : "./init.js",
"testEnvironment": "node",
"bail": true,
"verbose": true
}
const detox = require('detox');
const config = require('../package.json').detox;
const exec = require('shell-utils').exec;
const adapter = require('detox/runners/jest/adapter');
jest.setTimeout(300000);
jasmine.getEnv().addReporter(adapter);
beforeAll(async () => {
await detox.init(config, {launchApp: false});
disableAndroidEmulatorAnimations();
});
afterAll(async () => {
await adapter.afterAll();
await detox.cleanup();
});
beforeEach(async () => {
await adapter.beforeEach();
});
function disableAndroidEmulatorAnimations() {
if (device.getPlatform() === 'android') {
const deviceId = device._deviceId;
exec.execAsync(`adb -s ${deviceId} shell settings put global window_animation_scale 0.0`);
exec.execAsync(`adb -s ${deviceId} shell settings put global transition_animation_scale 0.0`);
exec.execAsync(`adb -s ${deviceId} shell settings put global animator_duration_scale 0.0`);
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 16
compileSdkVersion = 28
targetSdkVersion = 26
supportLibVersion = "28.0.3"
}
repositories {
google()
mavenLocal()
......@@ -8,7 +15,8 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.google.gms:google-services:4.0.1'
}
}
......@@ -21,8 +29,9 @@ allprojects {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
url "$rootDir/../../node_modules/react-native/android"
}
maven { url "$rootDir/../../node_modules/jsc-android/dist" }
}
}
......
......@@ -15,4 +15,7 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
\ No newline at end of file
# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true
\ No newline at end of file
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
/build
google-services.json
\ No newline at end of file
apply plugin: 'com.android.application'
apply plugin: "com.android.application"
project.ext.react = [
root : "../../../",
entryFile: "index.js",
bundleAssetName: "index.bundle",
bundleInAlpha: true,
bundleInBeta: true
]
apply from: "../../../node_modules/react-native/react.gradle"
android {
compileSdkVersion 26
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.wix.reactnativenotifications.app"
minSdkVersion 19
targetSdkVersion 26
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
......@@ -21,26 +30,33 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
packagingOptions {
pickFirst '**/libjsc.so'
pickFirst '**/libc++_shared.so'
}
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion "26.1.0"
}
}
resolutionStrategy {
force 'org.webkit:android-jsc:r236355'
}
}
dependencies {
// compile fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.facebook.react:react-native:+'
implementation 'org.webkit:android-jsc-intl:+'
implementation project(':react-native-notifications')
testImplementation'junit:junit:4.12'
}
apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
......@@ -9,11 +9,9 @@
android:name=".MainApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<meta-data
android:name="com.wix.reactnativenotifications.gcmSenderId"
android:value="434691868895\0"/>
<activity
android:name=".MainActivity"
......
package com.wix.reactnativenotifications.app;
import android.os.Build;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.Toolbar;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactRootView;
import static android.os.Build.VERSION.SDK_INT;
public class MainActivity extends ReactActivity {
private ReactRootView mReactRootView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup layout;
if (SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
layout = (ViewGroup) getLayoutInflater().inflate(R.layout.activity_main, null);
Toolbar toolbar = layout.findViewById(R.id.toolbar);
setActionBar(toolbar);
} else {
layout = (ViewGroup) getLayoutInflater().inflate(R.layout.activity_main_prelollipop, null);
}
mReactRootView = new ReactRootView(this);
layout.addView(mReactRootView);
setContentView(layout);
startReactApplication();
}
private void startReactApplication() {
mReactRootView.startReactApplication(getReactInstanceManager(), "WixRNNotifications", null);
protected String getMainComponentName() {
return "NotificationsExampleApp";
}
}
......@@ -6,12 +6,18 @@ import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.wix.reactnativenotifications.RNNotificationsPackage;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
}
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
......@@ -24,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";
}
};
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.wix.reactnativenotifications.app.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
>
<android.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.wix.reactnativenotifications.app.MainActivity">
</android.support.design.widget.CoordinatorLayout>
#!/usr/bin/python
from urllib2 import *
import json
import sys
if len(sys.argv) < 2:
print 'Error: missing token argument'
sys.exit(1)
API_KEY = 'AIzaSyBVtqdO_SgPVhhXnyNGC_VXSbIX-fxk1YY'
TOKEN = sys.argv[1]
data = {
"to": TOKEN,
"data" : {
"body": "SUCCESS! Sent from script :)",
"title": "Wix Example Project"
}
}
dataJson = json.dumps(data)
request = Request(
'https://gcm-http.googleapis.com/gcm/send',
dataJson,
{
"Authorization" : "key="+API_KEY,
"Content-type" : "application/json"
}
)
print "Sending notification..."
print urlopen(request).read()
include ':myapplication'
include ':react-native-notifications'
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android')
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../../lib/android/app')
\ No newline at end of file
'use strict';
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
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>
</View>
)
}
async onCheckPermissions() {
const hasPermissions = await NotificationsAndroid.isRegisteredForRemoteNotifications();
if (hasPermissions) {
alert('Yay! You have permissions');
} else {
alert('Boo! You don\'t have permissions');
}
}
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);
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import {
AppRegistry,
StyleSheet,
Text,
View
} 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"
}, (action, completed) => {
NotificationsIOS.log("ACTION RECEIVED");
NotificationsIOS.log(JSON.stringify(action));
completed();
});
let replyAction = new NotificationAction({
activationMode: "background",
title: "Reply",
behavior: "textInput",
authenticationRequired: true,
identifier: "REPLY_ACTION"
}, (action, completed) => {
console.log("ACTION RECEIVED");
console.log(action);
completed();
});
let cat = new NotificationCategory({
identifier: "SOME_CATEGORY",
actions: [upvoteAction, replyAction],
context: "default"
});
class NotificationsExampleApp extends Component {
constructor() {
super();
NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
NotificationsIOS.requestPermissions([cat]);
NotificationsIOS.consumeBackgroundQueue();
NotificationsIOS.addEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
NotificationsIOS.registerPushKit();
NotificationsIOS.addEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
NotificationsIOS.addEventListener('notificationReceivedBackground', this.onNotificationReceivedBackground.bind(this));
NotificationsIOS.addEventListener('notificationOpened', this.onNotificationOpened.bind(this));
}
onPushRegistered(deviceToken) {
console.log("Device Token Received: " + deviceToken);
}
onPushKitRegistered(deviceToken) {
console.log("PushKit Token Received: " + deviceToken);
}
onNotificationReceivedForeground(notification) {
console.log("Notification Received Foreground: " + JSON.stringify(notification));
}
onNotificationReceivedBackground(notification) {
NotificationsIOS.log("Notification Received Background: " + JSON.stringify(notification));
let localNotification = NotificationsIOS.localNotification({
alertBody: "Received background notificiation!",
alertTitle: "Local Notification Title",
alertAction: "Click here to open",
soundName: "chime.aiff",
category: "SOME_CATEGORY",
userInfo: notification.getData()
});
// if you want to fire the local notification 10 seconds later,
// add the following line to the notification payload:
// fireDate: new Date(Date.now() + (10 * 1000)).toISOString()
// NotificationsIOS.backgroundTimeRemaining(time => NotificationsIOS.log("remaining background time: " + time));
// NotificationsIOS.cancelLocalNotification(localNotification);
}
onNotificationOpened(notification) {
console.log("Notification Opened: " + JSON.stringify(notification));
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native Notifications Demo App!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
componentWillUnmount() {
NotificationsIOS.removeEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
NotificationsIOS.removeEventListener('notificationReceivedBackground', this.onNotificationReceivedBackground.bind(this));
NotificationsIOS.removeEventListener('notificationOpened', this.onNotificationOpened.bind(this));
NotificationsIOS.removeEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
NotificationsIOS.removeEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
// NotificationsIOS.resetCategories();
}
_onNotification(notification) {
AlertIOS.alert(
'Notification Received',
'Alert message: ' + notification.getMessage(),
[{
text: 'Dismiss',
onPress: null,
}]
);
}
}
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);
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.data.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.data.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.data.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);
......@@ -6,6 +6,20 @@
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3D3C04B91DE3340900C268FA"
BuildableName = "libyoga.a"
BlueprintName = "yoga"
ReferencedContainer = "container:../../node_modules/react-native/React/React.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
......@@ -17,7 +31,7 @@
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
BuildableName = "libReact.a"
BlueprintName = "React"
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
ReferencedContainer = "container:../../node_modules/react-native/React/React.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
......@@ -40,9 +54,36 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "YES"
shouldUseLaunchSchemeArgsEnv = "NO">
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "NotificationsExampleApp.app"
BlueprintName = "NotificationsExampleApp"
ReferencedContainer = "container:NotificationsExampleApp.xcodeproj">
</BuildableReference>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "508CE7C722D12B2600357815"
BuildableName = "RNNotificationsTests.xctest"
BlueprintName = "RNNotificationsTests"
ReferencedContainer = "container:../../lib/ios/RNNotifications.xcodeproj">
</BuildableReference>
</CodeCoverageTargets>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "508CE7C722D12B2600357815"
BuildableName = "RNNotificationsTests.xctest"
BlueprintName = "RNNotificationsTests"
ReferencedContainer = "container:../../lib/ios/RNNotifications.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
......@@ -53,6 +94,13 @@
ReferencedContainer = "container:NotificationsExampleApp.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "TEST_ENABLED"
value = "YES"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
......@@ -60,7 +108,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
require('./example/index');
\ No newline at end of file
This diff is collapsed.
connection.project.dir=
eclipse.preferences.version=1
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment