Commit f780e541 authored by Krystof Celba's avatar Krystof Celba

Add support for notification actions on iOS

parent 24f887fd
...@@ -25,6 +25,26 @@ declare module "react-native-fcm" { ...@@ -25,6 +25,26 @@ declare module "react-native-fcm" {
const Local = "local_notification"; const Local = "local_notification";
} }
export enum NotificationCategoryOption {
CustomDismissAction = 'UNNotificationCategoryOptionCustomDismissAction',
AllowInCarPlay = 'UNNotificationCategoryOptionAllowInCarPlay',
PreviewsShowTitle = 'UNNotificationCategoryOptionHiddenPreviewsShowTitle',
PreviewsShowSubtitle = 'UNNotificationCategoryOptionHiddenPreviewsShowSubtitle',
None = 'UNNotificationCategoryOptionNone'
}
export enum NotificationActionOption {
AuthenticationRequired = 'UNNotificationActionOptionAuthenticationRequired',
Destructive = 'UNNotificationActionOptionDestructive',
Foreground = 'UNNotificationActionOptionForeground',
None = 'UNNotificationActionOptionNone'
}
export enum NotificationActionType {
Default = 'UNNotificationActionTypeDefault',
TextInput = 'UNNotificationActionTypeTextInput',
}
export interface Notification { export interface Notification {
collapse_key: string; collapse_key: string;
opened_from_tray: boolean; opened_from_tray: boolean;
...@@ -44,6 +64,8 @@ declare module "react-native-fcm" { ...@@ -44,6 +64,8 @@ declare module "react-native-fcm" {
}; };
local_notification?: boolean; local_notification?: boolean;
_notificationType: string; _notificationType: string;
_actionIdentifier?: string;
_userText?: string;
finish(type?: string): void; finish(type?: string): void;
[key: string]: any; [key: string]: any;
} }
...@@ -83,6 +105,23 @@ declare module "react-native-fcm" { ...@@ -83,6 +105,23 @@ declare module "react-native-fcm" {
remove(): void; remove(): void;
} }
export interface NotificationAction {
type: NotificationActionType;
id: string;
title?: string;
textInputButtonTitle?: string;
textInputPlaceholder?: string;
options: NotificationActionOption | NotificationActionOption[];
}
export interface NotificationCategory {
id: string;
actions: NotificationAction[];
intentIdentifiers: string[];
hiddenPreviewsBodyPlaceholder?: string;
options?: NotificationCategoryOption | NotificationCategoryOption[];
}
export class FCM { export class FCM {
static requestPermissions(): Promise<void>; static requestPermissions(): Promise<void>;
static getFCMToken(): Promise<string>; static getFCMToken(): Promise<string>;
...@@ -109,6 +148,8 @@ declare module "react-native-fcm" { ...@@ -109,6 +148,8 @@ declare module "react-native-fcm" {
static enableDirectChannel(): void static enableDirectChannel(): void
static isDirectChannelEstablished(): Promise<boolean> static isDirectChannelEstablished(): Promise<boolean>
static getAPNSToken(): Promise<string> static getAPNSToken(): Promise<string>
static setNotificationCategories(categories: NotificationCategory[]): void;
} }
export default FCM; export default FCM;
......
...@@ -26,6 +26,26 @@ export const NotificationType = { ...@@ -26,6 +26,26 @@ export const NotificationType = {
Local: 'local_notification' Local: 'local_notification'
}; };
export const NotificationCategoryOption = {
CustomDismissAction: 'UNNotificationCategoryOptionCustomDismissAction',
AllowInCarPlay: 'UNNotificationCategoryOptionAllowInCarPlay',
PreviewsShowTitle: 'UNNotificationCategoryOptionHiddenPreviewsShowTitle',
PreviewsShowSubtitle: 'UNNotificationCategoryOptionHiddenPreviewsShowSubtitle',
None: 'UNNotificationCategoryOptionNone'
};
export const NotificationActionOption = {
AuthenticationRequired: 'UNNotificationActionOptionAuthenticationRequired',
Destructive: 'UNNotificationActionOptionDestructive',
Foreground: 'UNNotificationActionOptionForeground',
None: 'UNNotificationActionOptionNone',
};
export const NotificationActionType = {
Default: 'UNNotificationActionTypeDefault',
TextInput: 'UNNotificationActionTypeTextInput',
};
const RNFIRMessaging = NativeModules.RNFIRMessaging; const RNFIRMessaging = NativeModules.RNFIRMessaging;
const FCM = {}; const FCM = {};
...@@ -174,4 +194,10 @@ FCM.send = (senderId, payload) => { ...@@ -174,4 +194,10 @@ FCM.send = (senderId, payload) => {
RNFIRMessaging.send(senderId, payload); RNFIRMessaging.send(senderId, payload);
}; };
FCM.setNotificationCategories = (categories) => {
RNFIRMessaging.setNotificationCategories(categories);
}
export default FCM; export default FCM;
export {};
...@@ -131,6 +131,113 @@ RCT_ENUM_CONVERTER(UNNotificationPresentationOptions, (@{ ...@@ -131,6 +131,113 @@ RCT_ENUM_CONVERTER(UNNotificationPresentationOptions, (@{
@end @end
@implementation RCTConvert (UNNotificationAction)
typedef NS_ENUM(NSUInteger, UNNotificationActionType) {
UNNotificationActionTypeDefault,
UNNotificationActionTypeTextInput
};
+ (UNNotificationAction *) UNNotificationAction:(id)json {
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
NSString *identifier = [RCTConvert NSString: details[@"id"]];
NSString *title = [RCTConvert NSString: details[@"title"]];
UNNotificationActionOptions options = [RCTConvert UNNotificationActionOptions: details[@"options"]];
UNNotificationActionType type = [RCTConvert UNNotificationActionType:details[@"type"]];
if (type == UNNotificationActionTypeTextInput) {
NSString *textInputButtonTitle = [RCTConvert NSString: details[@"textInputButtonTitle"]];
NSString *textInputPlaceholder = [RCTConvert NSString: details[@"textInputPlaceholder"]];
return [UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:options textInputButtonTitle:textInputButtonTitle textInputPlaceholder:textInputPlaceholder];
}
return [UNNotificationAction actionWithIdentifier:identifier
title:title
options:options];
}
RCT_ENUM_CONVERTER(UNNotificationActionType, (@{
@"UNNotificationActionTypeDefault": @(UNNotificationActionTypeDefault),
@"UNNotificationActionTypeTextInput": @(UNNotificationActionTypeTextInput),
}), UNNotificationActionTypeDefault, integerValue)
RCT_MULTI_ENUM_CONVERTER(UNNotificationActionOptions, (@{
@"UNNotificationActionOptionAuthenticationRequired": @(UNNotificationActionOptionAuthenticationRequired),
@"UNNotificationActionOptionDestructive": @(UNNotificationActionOptionDestructive),
@"UNNotificationActionOptionForeground": @(UNNotificationActionOptionForeground),
@"UNNotificationActionOptionNone": @(UNNotificationActionOptionNone),
}), UNNotificationActionOptionNone, integerValue)
@end
@implementation RCTConvert (UNNotificationCategory)
+ (UNNotificationCategory *) UNNotificationCategory:(id)json {
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
NSString *identifier = [RCTConvert NSString: details[@"id"]];
NSMutableArray *actions = [[NSMutableArray alloc] init];
for (NSDictionary *actionDict in details[@"actions"]) {
[actions addObject:[RCTConvert UNNotificationAction:actionDict]];
}
NSArray<NSString *> *intentIdentifiers = [RCTConvert NSStringArray:details[@"intentIdentifiers"]];
NSString *hiddenPreviewsBodyPlaceholder = [RCTConvert NSString:details[@"hiddenPreviewsBodyPlaceholder"]];
UNNotificationCategoryOptions options = [RCTConvert UNNotificationCategoryOptions: details[@"options"]];
if (hiddenPreviewsBodyPlaceholder) {
if (@available(iOS 11.0, *)) {
return [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:intentIdentifiers hiddenPreviewsBodyPlaceholder:hiddenPreviewsBodyPlaceholder options:options];
}
}
return [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:intentIdentifiers options:options];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
RCT_MULTI_ENUM_CONVERTER(UNNotificationCategoryOptions, (@{
@"UNNotificationCategoryOptionNone": @(UNNotificationCategoryOptionNone),
@"UNNotificationCategoryOptionCustomDismissAction": @(UNNotificationCategoryOptionCustomDismissAction),
@"UNNotificationCategoryOptionAllowInCarPlay": @(UNNotificationCategoryOptionAllowInCarPlay),
@"UNNotificationCategoryOptionHiddenPreviewsShowTitle": @(UNNotificationCategoryOptionHiddenPreviewsShowTitle),
@"UNNotificationCategoryOptionHiddenPreviewsShowSubtitle": @(UNNotificationCategoryOptionHiddenPreviewsShowSubtitle),
}), UNNotificationCategoryOptionNone, integerValue)
#pragma clang diagnostic pop
@end
@interface RNFIRMessagingHelper : NSObject
@property (nonatomic, retain) NSDictionary *lastNotificationResponse;
+ (nonnull instancetype) sharedInstance;
@end
@implementation RNFIRMessagingHelper
+ (nonnull instancetype)sharedInstance {
static RNFIRMessagingHelper *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
@end
@interface RNFIRMessaging () @interface RNFIRMessaging ()
@property (nonatomic, strong) NSMutableDictionary *notificationCallbacks; @property (nonatomic, strong) NSMutableDictionary *notificationCallbacks;
@end @end
...@@ -169,7 +276,15 @@ RCT_EXPORT_MODULE(); ...@@ -169,7 +276,15 @@ RCT_EXPORT_MODULE();
if (response.actionIdentifier) { if (response.actionIdentifier) {
[data setValue:response.actionIdentifier forKey:@"_actionIdentifier"]; [data setValue:response.actionIdentifier forKey:@"_actionIdentifier"];
} }
[[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:@{@"data": data, @"completionHandler": completionHandler}];
if ([response isKindOfClass:UNTextInputNotificationResponse.class]) {
[data setValue:[(UNTextInputNotificationResponse *)response userText] forKey:@"_userText"];
}
NSDictionary *userInfo = @{@"data": data, @"completionHandler": completionHandler};
[RNFIRMessagingHelper sharedInstance].lastNotificationResponse = userInfo;
[[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:userInfo];
} }
+ (void)willPresentNotification:(UNNotification *)notification withCompletionHandler:(nonnull RCTWillPresentNotificationCallback)completionHandler + (void)willPresentNotification:(UNNotification *)notification withCompletionHandler:(nonnull RCTWillPresentNotificationCallback)completionHandler
...@@ -210,6 +325,12 @@ RCT_EXPORT_MODULE(); ...@@ -210,6 +325,12 @@ RCT_EXPORT_MODULE();
return self; return self;
} }
-(void)startObserving {
if([RNFIRMessagingHelper sharedInstance].lastNotificationResponse) {
[[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:[RNFIRMessagingHelper sharedInstance].lastNotificationResponse];
}
}
RCT_EXPORT_METHOD(enableDirectChannel) RCT_EXPORT_METHOD(enableDirectChannel)
{ {
[[FIRMessaging messaging] setShouldEstablishDirectChannel:@YES]; [[FIRMessaging messaging] setShouldEstablishDirectChannel:@YES];
...@@ -416,6 +537,20 @@ RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve ...@@ -416,6 +537,20 @@ RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve
} }
} }
RCT_EXPORT_METHOD(setNotificationCategories:(NSArray *)categories)
{
if([UNUserNotificationCenter currentNotificationCenter] != nil) {
NSMutableSet *categoriesSet = [[NSMutableSet alloc] init];
for(NSDictionary *categoryDict in categories) {
UNNotificationCategory *category = [RCTConvert UNNotificationCategory:categoryDict];
[categoriesSet addObject:category];
}
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categoriesSet];
}
}
RCT_EXPORT_METHOD(setBadgeNumber: (NSInteger) number) RCT_EXPORT_METHOD(setBadgeNumber: (NSInteger) number)
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
...@@ -493,6 +628,7 @@ RCT_EXPORT_METHOD(finishNotificationResponse: (NSString *)completionHandlerId){ ...@@ -493,6 +628,7 @@ RCT_EXPORT_METHOD(finishNotificationResponse: (NSString *)completionHandlerId){
[self sendEventWithName:FCMNotificationReceived body:data]; [self sendEventWithName:FCMNotificationReceived body:data];
[RNFIRMessagingHelper sharedInstance].lastNotificationResponse = nil;
} }
- (void)sendDataMessageFailure:(NSNotification *)notification - (void)sendDataMessageFailure:(NSNotification *)notification
......
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