This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
476 lines
18 KiB
476 lines
18 KiB
/** |
|
* Copyright (c) 2015-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
*/ |
|
|
|
#import "RCTPushNotificationManager.h" |
|
|
|
#import <UserNotifications/UserNotifications.h> |
|
|
|
#import <React/RCTBridge.h> |
|
#import <React/RCTConvert.h> |
|
#import <React/RCTEventDispatcher.h> |
|
#import <React/RCTUtils.h> |
|
|
|
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived"; |
|
|
|
static NSString *const kLocalNotificationReceived = @"LocalNotificationReceived"; |
|
static NSString *const kRemoteNotificationsRegistered = @"RemoteNotificationsRegistered"; |
|
static NSString *const kRegisterUserNotificationSettings = @"RegisterUserNotificationSettings"; |
|
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 () |
|
@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 |
|
#endif //TARGET_OS_TV |
|
|
|
@implementation RCTPushNotificationManager |
|
{ |
|
RCTPromiseResolveBlock _requestPermissionsResolveBlock; |
|
} |
|
|
|
#if !TARGET_OS_TV |
|
|
|
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; |
|
} |
|
|
|
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 |
|
|
|
RCT_EXPORT_MODULE() |
|
|
|
- (dispatch_queue_t)methodQueue |
|
{ |
|
return dispatch_get_main_queue(); |
|
} |
|
|
|
#if !TARGET_OS_TV |
|
- (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(handleRegisterUserNotificationSettings:) |
|
name:kRegisterUserNotificationSettings |
|
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 |
|
{ |
|
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) { |
|
[RCTSharedApplication() registerForRemoteNotifications]; |
|
[[NSNotificationCenter defaultCenter] postNotificationName:kRegisterUserNotificationSettings |
|
object:self |
|
userInfo:@{@"notificationSettings": notificationSettings}]; |
|
} |
|
} |
|
|
|
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken |
|
{ |
|
NSMutableString *hexString = [NSMutableString string]; |
|
NSUInteger deviceTokenLength = deviceToken.length; |
|
const unsigned char *bytes = 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]; |
|
} |
|
|
|
- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification |
|
{ |
|
if (_requestPermissionsResolveBlock == nil) { |
|
return; |
|
} |
|
|
|
UIUserNotificationSettings *notificationSettings = notification.userInfo[@"notificationSettings"]; |
|
NSDictionary *notificationTypes = @{ |
|
@"alert": @((notificationSettings.types & UIUserNotificationTypeAlert) > 0), |
|
@"sound": @((notificationSettings.types & UIUserNotificationTypeSound) > 0), |
|
@"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0), |
|
}; |
|
|
|
_requestPermissionsResolveBlock(notificationTypes); |
|
// Clean up listener added in requestPermissions |
|
[self removeListeners:1]; |
|
_requestPermissionsResolveBlock = nil; |
|
} |
|
|
|
RCT_EXPORT_METHOD(onFinishRemoteNotification:(NSString *)notificationId fetchResult:(UIBackgroundFetchResult)result) { |
|
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:(NSInteger)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:(NSDictionary *)permissions |
|
resolver:(RCTPromiseResolveBlock)resolve |
|
rejecter:(RCTPromiseRejectBlock)reject) |
|
{ |
|
if (RCTRunningInAppExtension()) { |
|
reject(kErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension")); |
|
return; |
|
} |
|
|
|
if (_requestPermissionsResolveBlock != nil) { |
|
RCTLogError(@"Cannot call requestPermissions twice before the first has returned."); |
|
return; |
|
} |
|
|
|
// Add a listener to make sure that startObserving has been called |
|
[self addListener:@"remoteNotificationsRegistered"]; |
|
_requestPermissionsResolveBlock = resolve; |
|
|
|
UIUserNotificationType types = UIUserNotificationTypeNone; |
|
if (permissions) { |
|
if ([RCTConvert BOOL:permissions[@"alert"]]) { |
|
types |= UIUserNotificationTypeAlert; |
|
} |
|
if ([RCTConvert BOOL:permissions[@"badge"]]) { |
|
types |= UIUserNotificationTypeBadge; |
|
} |
|
if ([RCTConvert BOOL:permissions[@"sound"]]) { |
|
types |= UIUserNotificationTypeSound; |
|
} |
|
} else { |
|
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound; |
|
} |
|
|
|
UIUserNotificationSettings *notificationSettings = |
|
[UIUserNotificationSettings settingsForTypes:types categories:nil]; |
|
[RCTSharedApplication() registerUserNotificationSettings:notificationSettings]; |
|
} |
|
|
|
RCT_EXPORT_METHOD(abandonPermissions) |
|
{ |
|
[RCTSharedApplication() unregisterForRemoteNotifications]; |
|
} |
|
|
|
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback) |
|
{ |
|
if (RCTRunningInAppExtension()) { |
|
callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]); |
|
return; |
|
} |
|
|
|
NSUInteger types = [RCTSharedApplication() currentUserNotificationSettings].types; |
|
callback(@[@{ |
|
@"alert": @((types & UIUserNotificationTypeAlert) > 0), |
|
@"badge": @((types & UIUserNotificationTypeBadge) > 0), |
|
@"sound": @((types & UIUserNotificationTypeSound) > 0), |
|
}]); |
|
} |
|
|
|
RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification) |
|
{ |
|
[RCTSharedApplication() presentLocalNotificationNow:notification]; |
|
} |
|
|
|
RCT_EXPORT_METHOD(scheduleLocalNotification:(UILocalNotification *)notification) |
|
{ |
|
[RCTSharedApplication() scheduleLocalNotification:notification]; |
|
} |
|
|
|
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) |
|
{ |
|
if ([UNUserNotificationCenter class]) { |
|
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; |
|
[center removeAllDeliveredNotifications]; |
|
} |
|
} |
|
|
|
RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers) |
|
{ |
|
if ([UNUserNotificationCenter class]) { |
|
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; |
|
[center removeDeliveredNotificationsWithIdentifiers:identifiers]; |
|
} |
|
} |
|
|
|
RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback) |
|
{ |
|
if ([UNUserNotificationCenter class]) { |
|
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 |
|
|
|
- (NSArray<NSString *> *)supportedEvents |
|
{ |
|
return @[]; |
|
} |
|
|
|
#endif //TARGET_OS_TV |
|
|
|
@end
|
|
|