This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,74 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
type Permissions = {|
alert: boolean,
badge: boolean,
sound: boolean,
|};
type Notification = {|
+alertTitle?: ?string,
// Actual type: string | number
+fireDate?: ?number,
+alertBody?: ?string,
+alertAction?: ?string,
+userInfo?: ?Object,
+category?: ?string,
// Actual type: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute'
+repeatInterval?: ?string,
+applicationIconBadgeNumber?: ?number,
+isSilent?: ?boolean,
|};
export interface Spec extends TurboModule {
+getConstants: () => {...};
+onFinishRemoteNotification: (
notificationId: string,
/**
* Type:
* 'UIBackgroundFetchResultNewData' |
* 'UIBackgroundFetchResultNoData' |
* 'UIBackgroundFetchResultFailed'
*/
fetchResult: string,
) => void;
+setApplicationIconBadgeNumber: (num: number) => void;
+getApplicationIconBadgeNumber: (callback: (num: number) => void) => void;
+requestPermissions: (permission: {|
+alert: boolean,
+badge: boolean,
+sound: boolean,
|}) => Promise<Permissions>;
+abandonPermissions: () => void;
+checkPermissions: (callback: (permissions: Permissions) => void) => void;
+presentLocalNotification: (notification: Notification) => void;
+scheduleLocalNotification: (notification: Notification) => void;
+cancelAllLocalNotifications: () => void;
+cancelLocalNotifications: (userInfo: Object) => void;
+getInitialNotification: () => Promise<?Notification>;
+getScheduledLocalNotifications: (
callback: (notification: Notification) => void,
) => void;
+removeAllDeliveredNotifications: () => void;
+removeDeliveredNotifications: (identifiers: Array<string>) => void;
+getDeliveredNotifications: (
callback: (notification: Array<Notification>) => void,
) => void;
+addListener: (eventType: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>(
'PushNotificationManager',
): ?Spec);

View File

@ -0,0 +1,518 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
import NativePushNotificationManagerIOS from './NativePushNotificationManagerIOS';
const invariant = require('invariant');
const PushNotificationEmitter = new NativeEventEmitter(
NativePushNotificationManagerIOS,
);
const _notifHandlers = new Map();
const DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
const NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
const NOTIF_REGISTRATION_ERROR_EVENT = 'remoteNotificationRegistrationError';
const DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
export type ContentAvailable = 1 | null | void;
export type FetchResult = {
NewData: string,
NoData: string,
ResultFailed: string,
...
};
/**
* An event emitted by PushNotificationIOS.
*/
export type PushNotificationEventName = $Keys<{
/**
* Fired when a remote notification is received. The handler will be invoked
* with an instance of `PushNotificationIOS`.
*/
notification: string,
/**
* Fired when a local notification is received. The handler will be invoked
* with an instance of `PushNotificationIOS`.
*/
localNotification: string,
/**
* Fired when the user registers for remote notifications. The handler will be
* invoked with a hex string representing the deviceToken.
*/
register: string,
/**
* 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 {message: string, code: number, details: any}.
*/
registrationError: string,
...
}>;
/**
*
* Handle push notifications for your app, including permission handling and
* icon badge number.
*
* See https://reactnative.dev/docs/pushnotificationios.html
*/
class PushNotificationIOS {
_data: Object;
_alert: string | Object;
_sound: string;
_category: string;
_contentAvailable: ContentAvailable;
_badgeCount: number;
_notificationId: string;
_isRemote: boolean;
_remoteNotificationCompleteCallbackCalled: boolean;
_threadID: string;
static FetchResult: FetchResult = {
NewData: 'UIBackgroundFetchResultNewData',
NoData: 'UIBackgroundFetchResultNoData',
ResultFailed: 'UIBackgroundFetchResultFailed',
};
/**
* Schedules the localNotification for immediate presentation.
*
* See https://reactnative.dev/docs/pushnotificationios.html#presentlocalnotification
*/
static presentLocalNotification(details: Object) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.presentLocalNotification(details);
}
/**
* Schedules the localNotification for future presentation.
*
* See https://reactnative.dev/docs/pushnotificationios.html#schedulelocalnotification
*/
static scheduleLocalNotification(details: Object) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.scheduleLocalNotification(details);
}
/**
* Cancels all scheduled localNotifications.
*
* See https://reactnative.dev/docs/pushnotificationios.html#cancelalllocalnotifications
*/
static cancelAllLocalNotifications() {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.cancelAllLocalNotifications();
}
/**
* Remove all delivered notifications from Notification Center.
*
* See https://reactnative.dev/docs/pushnotificationios.html#removealldeliverednotifications
*/
static removeAllDeliveredNotifications(): void {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.removeAllDeliveredNotifications();
}
/**
* Provides you with a list of the apps notifications that are still displayed in Notification Center.
*
* See https://reactnative.dev/docs/pushnotificationios.html#getdeliverednotifications
*/
static getDeliveredNotifications(
callback: (notifications: Array<Object>) => void,
): void {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.getDeliveredNotifications(callback);
}
/**
* Removes the specified notifications from Notification Center
*
* See https://reactnative.dev/docs/pushnotificationios.html#removedeliverednotifications
*/
static removeDeliveredNotifications(identifiers: Array<string>): void {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.removeDeliveredNotifications(identifiers);
}
/**
* Sets the badge number for the app icon on the home screen.
*
* See https://reactnative.dev/docs/pushnotificationios.html#setapplicationiconbadgenumber
*/
static setApplicationIconBadgeNumber(number: number) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.setApplicationIconBadgeNumber(number);
}
/**
* Gets the current badge number for the app icon on the home screen.
*
* See https://reactnative.dev/docs/pushnotificationios.html#getapplicationiconbadgenumber
*/
static getApplicationIconBadgeNumber(callback: Function) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.getApplicationIconBadgeNumber(callback);
}
/**
* Cancel local notifications.
*
* See https://reactnative.dev/docs/pushnotificationios.html#cancellocalnotification
*/
static cancelLocalNotifications(userInfo: Object) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.cancelLocalNotifications(userInfo);
}
/**
* Gets the local notifications that are currently scheduled.
*
* See https://reactnative.dev/docs/pushnotificationios.html#getscheduledlocalnotifications
*/
static getScheduledLocalNotifications(callback: Function) {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.getScheduledLocalNotifications(callback);
}
/**
* Attaches a listener to remote or local notification events while the app
* is running in the foreground or the background.
*
* See https://reactnative.dev/docs/pushnotificationios.html#addeventlistener
*/
static addEventListener(type: PushNotificationEventName, handler: Function) {
invariant(
type === 'notification' ||
type === 'register' ||
type === 'registrationError' ||
type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
);
let listener;
if (type === 'notification') {
listener = PushNotificationEmitter.addListener(
DEVICE_NOTIF_EVENT,
notifData => {
handler(new PushNotificationIOS(notifData));
},
);
} else if (type === 'localNotification') {
listener = PushNotificationEmitter.addListener(
DEVICE_LOCAL_NOTIF_EVENT,
notifData => {
handler(new PushNotificationIOS(notifData));
},
);
} else if (type === 'register') {
listener = PushNotificationEmitter.addListener(
NOTIF_REGISTER_EVENT,
registrationInfo => {
handler(registrationInfo.deviceToken);
},
);
} else if (type === 'registrationError') {
listener = PushNotificationEmitter.addListener(
NOTIF_REGISTRATION_ERROR_EVENT,
errorInfo => {
handler(errorInfo);
},
);
}
_notifHandlers.set(type, listener);
}
/**
* Removes the event listener. Do this in `componentWillUnmount` to prevent
* memory leaks.
*
* See https://reactnative.dev/docs/pushnotificationios.html#removeeventlistener
*/
static removeEventListener(
type: PushNotificationEventName,
handler: Function,
) {
invariant(
type === 'notification' ||
type === 'register' ||
type === 'registrationError' ||
type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
);
const listener = _notifHandlers.get(type);
if (!listener) {
return;
}
listener.remove();
_notifHandlers.delete(type);
}
/**
* Requests notification permissions from iOS, prompting the user's
* dialog box. By default, it will request all notification permissions, but
* a subset of these can be requested by passing a map of requested
* permissions.
*
* See https://reactnative.dev/docs/pushnotificationios.html#requestpermissions
*/
static requestPermissions(permissions?: {
alert?: boolean,
badge?: boolean,
sound?: boolean,
...
}): Promise<{
alert: boolean,
badge: boolean,
sound: boolean,
...
}> {
let requestedPermissions = {
alert: true,
badge: true,
sound: true,
};
if (permissions) {
requestedPermissions = {
alert: !!permissions.alert,
badge: !!permissions.badge,
sound: !!permissions.sound,
};
}
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
return NativePushNotificationManagerIOS.requestPermissions(
requestedPermissions,
);
}
/**
* Unregister for all remote notifications received via Apple Push Notification service.
*
* See https://reactnative.dev/docs/pushnotificationios.html#abandonpermissions
*/
static abandonPermissions() {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.abandonPermissions();
}
/**
* See what push permissions are currently enabled. `callback` will be
* invoked with a `permissions` object.
*
* See https://reactnative.dev/docs/pushnotificationios.html#checkpermissions
*/
static checkPermissions(callback: Function) {
invariant(typeof callback === 'function', 'Must provide a valid callback');
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.checkPermissions(callback);
}
/**
* This method returns a promise that resolves to either the notification
* object if the app was launched by a push notification, or `null` otherwise.
*
* See https://reactnative.dev/docs/pushnotificationios.html#getinitialnotification
*/
static getInitialNotification(): Promise<?PushNotificationIOS> {
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
return NativePushNotificationManagerIOS.getInitialNotification().then(
notification => {
return notification && new PushNotificationIOS(notification);
},
);
}
/**
* You will never need to instantiate `PushNotificationIOS` yourself.
* Listening to the `notification` event and invoking
* `getInitialNotification` is sufficient
*
*/
constructor(nativeNotif: Object) {
this._data = {};
this._remoteNotificationCompleteCallbackCalled = false;
this._isRemote = nativeNotif.remote;
if (this._isRemote) {
this._notificationId = nativeNotif.notificationId;
}
if (nativeNotif.remote) {
// Extract data from Apple's `aps` dict as defined:
// https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
Object.keys(nativeNotif).forEach(notifKey => {
const notifVal = nativeNotif[notifKey];
if (notifKey === 'aps') {
this._alert = notifVal.alert;
this._sound = notifVal.sound;
this._badgeCount = notifVal.badge;
this._category = notifVal.category;
this._contentAvailable = notifVal['content-available'];
this._threadID = notifVal['thread-id'];
} else {
this._data[notifKey] = notifVal;
}
});
} else {
// Local notifications aren't being sent down with `aps` dict.
this._badgeCount = nativeNotif.applicationIconBadgeNumber;
this._sound = nativeNotif.soundName;
this._alert = nativeNotif.alertBody;
this._data = nativeNotif.userInfo;
this._category = nativeNotif.category;
}
}
/**
* This method is available for remote notifications that have been received via:
* `application:didReceiveRemoteNotification:fetchCompletionHandler:`
*
* See https://reactnative.dev/docs/pushnotificationios.html#finish
*/
finish(fetchResult: string) {
if (
!this._isRemote ||
!this._notificationId ||
this._remoteNotificationCompleteCallbackCalled
) {
return;
}
this._remoteNotificationCompleteCallbackCalled = true;
invariant(
NativePushNotificationManagerIOS,
'PushNotificationManager is not available.',
);
NativePushNotificationManagerIOS.onFinishRemoteNotification(
this._notificationId,
fetchResult,
);
}
/**
* An alias for `getAlert` to get the notification's main message string
*/
getMessage(): ?string | ?Object {
// alias because "alert" is an ambiguous name
return this._alert;
}
/**
* Gets the sound string from the `aps` object
*
* See https://reactnative.dev/docs/pushnotificationios.html#getsound
*/
getSound(): ?string {
return this._sound;
}
/**
* Gets the category string from the `aps` object
*
* See https://reactnative.dev/docs/pushnotificationios.html#getcategory
*/
getCategory(): ?string {
return this._category;
}
/**
* Gets the notification's main message from the `aps` object
*
* See https://reactnative.dev/docs/pushnotificationios.html#getalert
*/
getAlert(): ?string | ?Object {
return this._alert;
}
/**
* Gets the content-available number from the `aps` object
*
* See https://reactnative.dev/docs/pushnotificationios.html#getcontentavailable
*/
getContentAvailable(): ContentAvailable {
return this._contentAvailable;
}
/**
* Gets the badge count number from the `aps` object
*
* See https://reactnative.dev/docs/pushnotificationios.html#getbadgecount
*/
getBadgeCount(): ?number {
return this._badgeCount;
}
/**
* Gets the data object on the notif
*
* See https://reactnative.dev/docs/pushnotificationios.html#getdata
*/
getData(): ?Object {
return this._data;
}
/**
* Gets the thread ID on the notif
*
* See https://reactnative.dev/docs/pushnotificationios.html#getthreadid
*/
getThreadID(): ?string {
return this._threadID;
}
}
module.exports = PushNotificationIOS;

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTEventEmitter.h>
extern NSString *const RCTRemoteNotificationReceived;
@interface RCTPushNotificationManager : RCTEventEmitter
typedef void (^RCTRemoteNotificationCallback)(UIBackgroundFetchResult result);
#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC
+ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler;
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification;
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
#endif
@end

View File

@ -0,0 +1,574 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTPushNotificationManager.h>
#import <UserNotifications/UserNotifications.h>
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUtils.h>
#import "RCTPushNotificationPlugins.h"
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
static NSString *const kLocalNotificationReceived = @"LocalNotificationReceived";
static NSString *const kRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
static NSString *const kRemoteNotificationRegistrationFailed = @"RemoteNotificationRegistrationFailed";
static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
#if !TARGET_OS_TV
@implementation RCTConvert (NSCalendarUnit)
RCT_ENUM_CONVERTER(NSCalendarUnit,
(@{
@"year": @(NSCalendarUnitYear),
@"month": @(NSCalendarUnitMonth),
@"week": @(NSCalendarUnitWeekOfYear),
@"day": @(NSCalendarUnitDay),
@"hour": @(NSCalendarUnitHour),
@"minute": @(NSCalendarUnitMinute)
}),
0,
integerValue)
@end
@interface RCTPushNotificationManager () <NativePushNotificationManagerIOSSpec>
@property (nonatomic, strong) NSMutableDictionary *remoteNotificationCallbacks;
@end
@implementation RCTConvert (UILocalNotification)
+ (UILocalNotification *)UILocalNotification:(id)json
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
BOOL isSilent = [RCTConvert BOOL:details[@"isSilent"]];
UILocalNotification *notification = [UILocalNotification new];
notification.alertTitle = [RCTConvert NSString:details[@"alertTitle"]];
notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
notification.category = [RCTConvert NSString:details[@"category"]];
notification.repeatInterval = [RCTConvert NSCalendarUnit:details[@"repeatInterval"]];
if (details[@"applicationIconBadgeNumber"]) {
notification.applicationIconBadgeNumber = [RCTConvert NSInteger:details[@"applicationIconBadgeNumber"]];
}
if (!isSilent) {
notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
}
return notification;
}
RCT_ENUM_CONVERTER(UIBackgroundFetchResult, (@{
@"UIBackgroundFetchResultNewData": @(UIBackgroundFetchResultNewData),
@"UIBackgroundFetchResultNoData": @(UIBackgroundFetchResultNoData),
@"UIBackgroundFetchResultFailed": @(UIBackgroundFetchResultFailed),
}), UIBackgroundFetchResultNoData, integerValue)
@end
#else
@interface RCTPushNotificationManager () <NativePushNotificationManagerIOS>
@end
#endif //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
@implementation RCTPushNotificationManager
#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC
static NSDictionary *RCTFormatLocalNotification(UILocalNotification *notification)
{
NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];
if (notification.fireDate) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
formattedLocalNotification[@"fireDate"] = fireDateString;
}
formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
formattedLocalNotification[@"applicationIconBadgeNumber"] = @(notification.applicationIconBadgeNumber);
formattedLocalNotification[@"category"] = RCTNullIfNil(notification.category);
formattedLocalNotification[@"soundName"] = RCTNullIfNil(notification.soundName);
formattedLocalNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(notification.userInfo));
formattedLocalNotification[@"remote"] = @NO;
return formattedLocalNotification;
}
API_AVAILABLE(ios(10.0))
static NSDictionary *RCTFormatUNNotification(UNNotification *notification)
{
NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary];
UNNotificationContent *content = notification.request.content;
formattedNotification[@"identifier"] = notification.request.identifier;
if (notification.date) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *dateString = [formatter stringFromDate:notification.date];
formattedNotification[@"date"] = dateString;
}
formattedNotification[@"title"] = RCTNullIfNil(content.title);
formattedNotification[@"body"] = RCTNullIfNil(content.body);
formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));
return formattedNotification;
}
#endif //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
RCT_EXPORT_MODULE()
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleLocalNotificationReceived:)
name:kLocalNotificationReceived
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationReceived:)
name:RCTRemoteNotificationReceived
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationsRegistered:)
name:kRemoteNotificationsRegistered
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationRegistrationError:)
name:kRemoteNotificationRegistrationFailed
object:nil];
}
- (void)stopObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (NSArray<NSString *> *)supportedEvents
{
return @[@"localNotificationReceived",
@"remoteNotificationReceived",
@"remoteNotificationsRegistered",
@"remoteNotificationRegistrationError"];
}
+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
{
}
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSMutableString *hexString = [NSMutableString string];
NSUInteger deviceTokenLength = deviceToken.length;
const unsigned char *bytes = reinterpret_cast<const unsigned char *>(deviceToken.bytes);
for (NSUInteger i = 0; i < deviceTokenLength; i++) {
[hexString appendFormat:@"%02x", bytes[i]];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kRemoteNotificationsRegistered
object:self
userInfo:@{@"deviceToken" : [hexString copy]}];
}
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[[NSNotificationCenter defaultCenter] postNotificationName:kRemoteNotificationRegistrationFailed
object:self
userInfo:@{@"error": error}];
}
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
{
NSDictionary *userInfo = @{@"notification": notification};
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
object:self
userInfo:userInfo];
}
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler
{
NSDictionary *userInfo = @{@"notification": notification, @"completionHandler": completionHandler};
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
object:self
userInfo:userInfo];
}
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:kLocalNotificationReceived
object:self
userInfo:RCTFormatLocalNotification(notification)];
}
- (void)handleLocalNotificationReceived:(NSNotification *)notification
{
[self sendEventWithName:@"localNotificationReceived" body:notification.userInfo];
}
- (void)handleRemoteNotificationReceived:(NSNotification *)notification
{
NSMutableDictionary *remoteNotification = [NSMutableDictionary dictionaryWithDictionary:notification.userInfo[@"notification"]];
RCTRemoteNotificationCallback completionHandler = notification.userInfo[@"completionHandler"];
NSString *notificationId = [[NSUUID UUID] UUIDString];
remoteNotification[@"notificationId"] = notificationId;
remoteNotification[@"remote"] = @YES;
if (completionHandler) {
if (!self.remoteNotificationCallbacks) {
// Lazy initialization
self.remoteNotificationCallbacks = [NSMutableDictionary dictionary];
}
self.remoteNotificationCallbacks[notificationId] = completionHandler;
}
[self sendEventWithName:@"remoteNotificationReceived" body:remoteNotification];
}
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
{
[self sendEventWithName:@"remoteNotificationsRegistered" body:notification.userInfo];
}
- (void)handleRemoteNotificationRegistrationError:(NSNotification *)notification
{
NSError *error = notification.userInfo[@"error"];
NSDictionary *errorDetails = @{
@"message": error.localizedDescription,
@"code": @(error.code),
@"details": error.userInfo,
};
[self sendEventWithName:@"remoteNotificationRegistrationError" body:errorDetails];
}
RCT_EXPORT_METHOD(onFinishRemoteNotification:(NSString *)notificationId fetchResult:(NSString *)fetchResult) {
UIBackgroundFetchResult result = [RCTConvert UIBackgroundFetchResult:fetchResult];
RCTRemoteNotificationCallback completionHandler = self.remoteNotificationCallbacks[notificationId];
if (!completionHandler) {
RCTLogError(@"There is no completion handler with notification id: %@", notificationId);
return;
}
completionHandler(result);
[self.remoteNotificationCallbacks removeObjectForKey:notificationId];
}
/**
* Update the application icon badge number on the home screen
*/
RCT_EXPORT_METHOD(setApplicationIconBadgeNumber:(double)number)
{
RCTSharedApplication().applicationIconBadgeNumber = number;
}
/**
* Get the current application icon badge number on the home screen
*/
RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback)
{
callback(@[@(RCTSharedApplication().applicationIconBadgeNumber)]);
}
RCT_EXPORT_METHOD(requestPermissions:(JS::NativePushNotificationManagerIOS::SpecRequestPermissionsPermission &)permissions
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
if (RCTRunningInAppExtension()) {
reject(kErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension"));
return;
}
// Add a listener to make sure that startObserving has been called
[self addListener:@"remoteNotificationsRegistered"];
UIUserNotificationType types = UIUserNotificationTypeNone;
if (permissions.alert()) {
types |= UIUserNotificationTypeAlert;
}
if (permissions.badge()) {
types |= UIUserNotificationTypeBadge;
}
if (permissions.sound()) {
types |= UIUserNotificationTypeSound;
}
[UNUserNotificationCenter.currentNotificationCenter
requestAuthorizationWithOptions:types
completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (error != NULL) {
reject(@"-1", @"Error - Push authorization request failed.", error);
} else {
[RCTSharedApplication() registerForRemoteNotifications];
[UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
resolve(RCTPromiseResolveValueForUNNotificationSettings(settings));
}];
}
}];
}
RCT_EXPORT_METHOD(abandonPermissions)
{
[RCTSharedApplication() unregisterForRemoteNotifications];
}
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
{
if (RCTRunningInAppExtension()) {
callback(@[RCTSettingsDictForUNNotificationSettings(NO, NO, NO)]);
return;
}
[UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
callback(@[RCTPromiseResolveValueForUNNotificationSettings(settings)]);
}];
}
static inline NSDictionary *RCTPromiseResolveValueForUNNotificationSettings(UNNotificationSettings* _Nonnull settings) {
return RCTSettingsDictForUNNotificationSettings(settings.alertSetting == UNNotificationSettingEnabled,
settings.badgeSetting == UNNotificationSettingEnabled,
settings.soundSetting == UNNotificationSettingEnabled);
}
static inline NSDictionary *RCTSettingsDictForUNNotificationSettings(BOOL alert, BOOL badge, BOOL sound) {
return @{@"alert": @(alert), @"badge": @(badge), @"sound": @(sound)};
}
RCT_EXPORT_METHOD(presentLocalNotification:(JS::NativePushNotificationManagerIOS::Notification &)notification)
{
NSMutableDictionary *notificationDict = [NSMutableDictionary new];
notificationDict[@"alertTitle"] = notification.alertTitle();
notificationDict[@"alertBody"] = notification.alertBody();
notificationDict[@"alertAction"] = notification.alertAction();
notificationDict[@"userInfo"] = notification.userInfo();
notificationDict[@"category"] = notification.category();
notificationDict[@"repeatInterval"] = notification.repeatInterval();
if (notification.fireDate()) {
notificationDict[@"fireDate"] = @(*notification.fireDate());
}
if (notification.applicationIconBadgeNumber()) {
notificationDict[@"applicationIconBadgeNumber"] = @(*notification.applicationIconBadgeNumber());
}
if (notification.isSilent()) {
notificationDict[@"isSilent"] = @(*notification.isSilent());
}
[RCTSharedApplication() presentLocalNotificationNow:[RCTConvert UILocalNotification:notificationDict]];
}
RCT_EXPORT_METHOD(scheduleLocalNotification:(JS::NativePushNotificationManagerIOS::Notification &)notification)
{
NSMutableDictionary *notificationDict = [NSMutableDictionary new];
notificationDict[@"alertTitle"] = notification.alertTitle();
notificationDict[@"alertBody"] = notification.alertBody();
notificationDict[@"alertAction"] = notification.alertAction();
notificationDict[@"userInfo"] = notification.userInfo();
notificationDict[@"category"] = notification.category();
notificationDict[@"repeatInterval"] = notification.repeatInterval();
if (notification.fireDate()) {
notificationDict[@"fireDate"] = @(*notification.fireDate());
}
if (notification.applicationIconBadgeNumber()) {
notificationDict[@"applicationIconBadgeNumber"] = @(*notification.applicationIconBadgeNumber());
}
if (notification.isSilent()) {
notificationDict[@"isSilent"] = @(*notification.isSilent());
}
[RCTSharedApplication() scheduleLocalNotification:[RCTConvert UILocalNotification:notificationDict]];
}
RCT_EXPORT_METHOD(cancelAllLocalNotifications)
{
[RCTSharedApplication() cancelAllLocalNotifications];
}
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary<NSString *, id> *)userInfo)
{
for (UILocalNotification *notification in RCTSharedApplication().scheduledLocalNotifications) {
__block BOOL matchesAll = YES;
NSDictionary<NSString *, id> *notificationInfo = notification.userInfo;
// Note: we do this with a loop instead of just `isEqualToDictionary:`
// because we only require that all specified userInfo values match the
// notificationInfo values - notificationInfo may contain additional values
// which we don't care about.
[userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if (![notificationInfo[key] isEqual:obj]) {
matchesAll = NO;
*stop = YES;
}
}];
if (matchesAll) {
[RCTSharedApplication() cancelLocalNotification:notification];
}
}
}
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
NSMutableDictionary<NSString *, id> *initialNotification =
[self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] mutableCopy];
UILocalNotification *initialLocalNotification =
self.bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
if (initialNotification) {
initialNotification[@"remote"] = @YES;
resolve(initialNotification);
} else if (initialLocalNotification) {
resolve(RCTFormatLocalNotification(initialLocalNotification));
} else {
resolve((id)kCFNull);
}
}
RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTResponseSenderBlock)callback)
{
NSArray<UILocalNotification *> *scheduledLocalNotifications = RCTSharedApplication().scheduledLocalNotifications;
NSMutableArray<NSDictionary *> *formattedScheduledLocalNotifications = [NSMutableArray new];
for (UILocalNotification *notification in scheduledLocalNotifications) {
[formattedScheduledLocalNotifications addObject:RCTFormatLocalNotification(notification)];
}
callback(@[formattedScheduledLocalNotifications]);
}
RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllDeliveredNotifications];
}
RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeDeliveredNotificationsWithIdentifiers:identifiers];
}
RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *_Nonnull notifications) {
NSMutableArray<NSDictionary *> *formattedNotifications = [NSMutableArray new];
for (UNNotification *notification in notifications) {
[formattedNotifications addObject:RCTFormatUNNotification(notification)];
}
callback(@[formattedNotifications]);
}];
}
#else //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
RCT_EXPORT_METHOD(onFinishRemoteNotification:(NSString *)notificationId fetchResult:(NSString *)fetchResult)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(setApplicationIconBadgeNumber:(double)number)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(requestPermissions:(JS::NativePushNotificationManagerIOS::SpecRequestPermissionsPermission &)permissions
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(abandonPermissions)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(presentLocalNotification:(JS::NativePushNotificationManagerIOS::Notification &)notification)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(scheduleLocalNotification:(JS::NativePushNotificationManagerIOS::Notification &)notification)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(cancelAllLocalNotifications)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary<NSString *, id> *)userInfo)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTResponseSenderBlock)callback)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
- (NSArray<NSString *> *)supportedEvents
{
return @[];
}
#endif //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
- (std::shared_ptr<facebook::react::TurboModule>)
getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
{
return std::make_shared<facebook::react::NativePushNotificationManagerIOSSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
}
@end
Class RCTPushNotificationManagerCls(void) {
return RCTPushNotificationManager.class;
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by an internal plugin build system
*/
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
// FB Internal: FBRCTPushNotificationPlugins.h is autogenerated by the build system.
#import <React/FBRCTPushNotificationPlugins.h>
#else
// OSS-compatibility layer
#import <Foundation/Foundation.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"
#ifdef __cplusplus
extern "C" {
#endif
// RCTTurboModuleManagerDelegate should call this to resolve module classes.
Class RCTPushNotificationClassProvider(const char *name);
// Lookup functions
Class RCTPushNotificationManagerCls(void) __attribute__((used));
#ifdef __cplusplus
}
#endif
#pragma GCC diagnostic pop
#endif // RN_DISABLE_OSS_PLUGIN_HEADER

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by an internal plugin build system
*/
#ifndef RN_DISABLE_OSS_PLUGIN_HEADER
// OSS-compatibility layer
#import "RCTPushNotificationPlugins.h"
#import <string>
#import <unordered_map>
Class RCTPushNotificationClassProvider(const char *name) {
static std::unordered_map<std::string, Class (*)(void)> sCoreModuleClassMap = {
{"PushNotificationManager", RCTPushNotificationManagerCls},
};
auto p = sCoreModuleClassMap.find(name);
if (p != sCoreModuleClassMap.end()) {
auto classFunc = p->second;
return classFunc();
}
return nil;
}
#endif // RN_DISABLE_OSS_PLUGIN_HEADER

View File

@ -0,0 +1,48 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip
else
source[:tag] = "v#{version}"
end
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
folly_version = '2020.01.13.00'
Pod::Spec.new do |s|
s.name = "React-RCTPushNotification"
s.version = version
s.summary = "A library for handling push notifications for your app, including permission handling and icon badge number."
s.homepage = "https://reactnative.dev/"
s.documentation_url = "https://reactnative.dev/docs/pushnotificationios"
s.license = package["license"]
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "10.0", :tvos => "10.0" }
s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness'
s.source = source
s.source_files = "*.{m,mm}"
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
s.header_dir = "RCTPushNotification"
s.pod_target_xcconfig = {
"USE_HEADERMAP" => "YES",
"CLANG_CXX_LANGUAGE_STANDARD" => "c++14",
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Folly\""
}
s.framework = "UserNotifications"
s.dependency "FBReactNativeSpec", version
s.dependency "RCTTypeSafety", version
s.dependency "React-Core/RCTPushNotificationHeaders", version
s.dependency "ReactCommon/turbomodule/core", version
s.dependency "React-jsi", version
end