From f2230b8c818cb2d5cff6913294996aa4407e1470 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Mon, 20 Jun 2016 20:41:33 -0700 Subject: [PATCH 01/44] [TIMOB-23527] Start to map notifications to iOS 10 --- .../Classes/TiAppiOSLocalNotificationProxy.h | 9 + .../Classes/TiAppiOSLocalNotificationProxy.m | 14 +- .../Classes/TiAppiOSNotificationActionProxy.h | 17 +- .../Classes/TiAppiOSNotificationActionProxy.m | 89 +++- .../TiAppiOSNotificationCategoryProxy.h | 11 +- .../TiAppiOSNotificationCategoryProxy.m | 52 ++- iphone/Classes/TiAppiOSProxy.m | 386 ++++++++++++------ 7 files changed, 426 insertions(+), 152 deletions(-) diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index 8303bae2d02..3761c748cad 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -5,16 +5,25 @@ * Please see the LICENSE included with this distribution for details. */ #import "TiProxy.h" +#import #ifdef USE_TI_APPIOS @interface TiAppiOSLocalNotificationProxy : TiProxy { @private +#if IS_XCODE_8 + UNMutableNotificationContent *_notification; +#else UILocalNotification *_notification; +#endif } +#if IS_XCODE_8 +@property(nonatomic,retain) UNMutableNotificationContent *notification; +#else @property(nonatomic,retain) UILocalNotification *notification; +#endif -(void)cancel:(id)args; diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 3ea2c96d56c..6ea5660e498 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -27,9 +27,19 @@ -(NSString*)apiName -(void)cancel:(id)args { +#if IS_XCODE_8 + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + + TiThreadPerformOnMainThread(^{ + [center removePendingNotificationRequestsWithIdentifiers:@[[self.notification categoryIdentifier]]]; + }, NO); +#else UILocalNotification * cancelledNotification = [self.notification retain]; - TiThreadPerformOnMainThread(^{[[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; - [cancelledNotification release];}, NO); + TiThreadPerformOnMainThread(^{ + [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; + [cancelledNotification release]; + }, NO); +#endif } @end diff --git a/iphone/Classes/TiAppiOSNotificationActionProxy.h b/iphone/Classes/TiAppiOSNotificationActionProxy.h index d08155408a5..43e74bf808b 100644 --- a/iphone/Classes/TiAppiOSNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSNotificationActionProxy.h @@ -1,23 +1,24 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2014 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ + #import "TiProxy.h" #ifdef USE_TI_APPIOS +#if IS_XCODE_8 +#import +#endif @interface TiAppiOSNotificationActionProxy : TiProxy -{ - -} +#if IS_XCODE_8 +@property(nonatomic,retain) UNNotificationAction *notificationAction; +#else @property(nonatomic,retain) UIMutableUserNotificationAction *notificationAction; - -@property (nonatomic, assign) NSString* identifier; -@property (nonatomic, assign) NSString* title; -@property (nonatomic, assign) NSNumber* activationMode; +#endif @end diff --git a/iphone/Classes/TiAppiOSNotificationActionProxy.m b/iphone/Classes/TiAppiOSNotificationActionProxy.m index d958de05a4b..d426a64efad 100644 --- a/iphone/Classes/TiAppiOSNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSNotificationActionProxy.m @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2014 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ @@ -23,40 +23,95 @@ -(NSString*)apiName return @"Ti.App.iOS.NotificationAction"; } +-(id)_initWithPageContext:(id)context args:(NSArray *)args +{ + if (_notificationAction == nil) { + +#if IS_XCODE_8 + id identifier = [args valueForKey:@"identifier"]; + id title = [args valueForKey:@"title"]; + id activationMode = [args valueForKey:@"activationMode"]; + id authenticationRequired = [args valueForKey:@"authenticationRequired"]; + id destructive = [args valueForKey:@"destructive"]; + id behavior = [args valueForKey:@"behavior"]; + id textInputButtonTitle = [args valueForKey:@"textInputButtonTitle"]; + id textInputButtonPlaceholder = [args valueForKey:@"textInputButtonPlaceholder"]; + + UNNotificationActionOptions options = UNNotificationActionOptionNone; + + if (destructive) { + options |= UNNotificationActionOptionDestructive; + } + + if (authenticationRequired) { + options |= UNNotificationActionOptionAuthenticationRequired; + } + + if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { + _notificationAction = [UNTextInputNotificationAction actionWithIdentifier:identifier + title:title + options:options + textInputButtonTitle:textInputButtonTitle + textInputPlaceholder:textInputButtonPlaceholder]; + return; + } + + _notificationAction = [UNNotificationAction actionWithIdentifier:identifier + title:title + options:[TiUtils intValue:activationMode]]; +#else + _notificationAction = [UIMutableUserNotificationAction new]; +#endif + } + + [super _initWithPageContext:context args:args]; +} + +#if IS_XCODE_8 +-(UNNotificationAction*) notificationAction +#else -(UIMutableUserNotificationAction*) notificationAction +#endif { - if (_notificationAction == nil) { - _notificationAction = [[UIMutableUserNotificationAction alloc] init]; - } return _notificationAction; } --(NSString*)identifier +#pragma mark Public API's + +#if IS_XCODE_8 + // The iOS 10 API's are creation-only, so there are no proxy setters +#else +- (void)setIdentifier:(id)value { - return [[self notificationAction] identifier]; + [[self notificationAction] setIdentifier:value]; } --(NSString*)title + +- (void)setTitle:(id)value { - return [[self notificationAction] title]; + [[self notificationAction] setTitle:value]; } --(NSNumber*)activationMode + +- (void)setActivationMode:(id)value { - return NUMINT([[self notificationAction] activationMode]); + [[self notificationAction] setActivationMode:[TiUtils intValue:value]]; } --(void)setIdentifier:(NSString*)args +- (void)setBehavior:(id)value { - [[self notificationAction] setIdentifier: args]; + [[self notificationAction] setBehavior:[TiUtils intValue:value]]; } --(void)setTitle:(NSString*)args + +- (void)setDestructive:(id)value { - [[self notificationAction] setTitle: args]; + [[self notificationAction] setDestructive:[TiUtils boolValue:value]]; } --(void)setActivationMode:(NSNumber*)args + +- (void)setAuthenticationRequired:(id)value { - UIUserNotificationActivationMode activationMode = [TiUtils intValue:args def:0]; - [[self notificationAction] setActivationMode: activationMode]; + [[self notificationAction] setAuthenticationRequired:[TiUtils boolValue:value]]; } +#endif + @end #endif diff --git a/iphone/Classes/TiAppiOSNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSNotificationCategoryProxy.h index c692356f60b..c9cdf7f9f85 100644 --- a/iphone/Classes/TiAppiOSNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSNotificationCategoryProxy.h @@ -1,19 +1,26 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2014 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ #import "TiProxy.h" #ifdef USE_TI_APPIOS +#if IS_XCODE_8 +#import +#endif @interface TiAppiOSNotificationCategoryProxy : TiProxy { } -@property (nonatomic,retain) UIUserNotificationCategory *notificationCategory; +#if IS_XCODE_8 +@property (nonatomic,retain) UNNotificationCategory *notificationCategory; +#else +@property (nonatomic,retain) UIMutableUserNotificationCategory *notificationCategory; +#endif @property (nonatomic,readonly) NSString *identifier; @end diff --git a/iphone/Classes/TiAppiOSNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSNotificationCategoryProxy.m index 1396c6d59c5..b8d2d0dc588 100644 --- a/iphone/Classes/TiAppiOSNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSNotificationCategoryProxy.m @@ -1,11 +1,12 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2014 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ #import "TiAppiOSNotificationCategoryProxy.h" +#import "TiAppiOSNotificationActionProxy.h" #import "TiUtils.h" #ifdef USE_TI_APPIOS @@ -22,11 +23,54 @@ -(NSString*)apiName { return @"Ti.App.iOS.NotificationCategory"; } + +-(id)_initWithPageContext:(id)context args:(NSArray *)args +{ + if (_notificationCategory == nil) { + + id identifier = [args valueForKey:@"identifier"]; + id actionsForDefaultContext = [args valueForKey:@"actionsForDefaultContext"]; + id actionsForMinimalContext = [args valueForKey:@"actionsForMinimalContext"]; + id intentIdentifiers = [args valueForKey:@"intentIdentifiers"]; + + NSMutableArray *defaultActions = [NSMutableArray new]; + NSMutableArray *minimalActions = [NSMutableArray new]; + + for (TiAppiOSNotificationActionProxy *action in actionsForDefaultContext) { + [defaultActions addObject:[action notificationAction]]; + } + + for (TiAppiOSNotificationActionProxy *action in actionsForMinimalContext) { + [minimalActions addObject:[action notificationAction]]; + } + + if (!intentIdentifiers) { + intentIdentifiers = @[]; + } + +#if IS_XCODE_8 + _notificationCategory = [UNNotificationCategory categoryWithIdentifier:identifier + actions:defaultActions + minimalActions:minimalActions + intentIdentifiers:intentIdentifiers + options:UNNotificationCategoryOptionNone]; +#else + _notificationCategory = [[UIMutableUserNotificationCategory alloc] init]; + [_notificationCategory setIdentifier:identifier]; + [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; + [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; +#endif + } + + [super _initWithPageContext:context args:args]; +} + +#if IS_XCODE_8 +-(UNNotificationCategory*)notificationCategory +#else -(UIUserNotificationCategory*)notificationCategory +#endif { - if (_notificationCategory == nil) { - _notificationCategory = [[UIUserNotificationCategory alloc] init]; - } return _notificationCategory; } diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index ac4712f1f11..a67e2d8ee77 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -20,6 +20,10 @@ #import "TiAppiOSSearchableItemProxy.h" #import "TiAppiOSSearchableIndexProxy.h" +#if IS_XCODE_8 +#import +#endif + #import #import @@ -312,96 +316,6 @@ -(id)registerBackgroundService:(id)args //TO DO: implement didRegisterUserNotificationSettings delegate? //remote notifications add 'category' --(id)createUserNotificationAction:(id)args -{ - - if(![TiUtils isIOS8OrGreater]) { - return nil; - } - - ENSURE_SINGLE_ARG(args,NSDictionary); - UIMutableUserNotificationAction *notifAction = [[UIMutableUserNotificationAction alloc] init]; - - id identifier = [args objectForKey:@"identifier"]; - - if (identifier!=nil) { - notifAction.identifier = identifier; - } - - id title = [args objectForKey:@"title"]; - - if (title!=nil) { - notifAction.title = title; - } - - UIUserNotificationActivationMode activationMode = [TiUtils intValue:[args objectForKey:@"activationMode"]]; - notifAction.activationMode = activationMode; - - BOOL destructive = [TiUtils boolValue:[args objectForKey:@"destructive"]]; - - notifAction.destructive = destructive; - - BOOL authenticationRequired = [TiUtils boolValue:[args objectForKey:@"authenticationRequired"]]; - notifAction.authenticationRequired = authenticationRequired; - - if([TiUtils isIOS9OrGreater] == YES) { - NSInteger behavior = [TiUtils intValue:[args objectForKey:@"behavior"]]; - notifAction.behavior = behavior; - } - - TiAppiOSNotificationActionProxy *ap = [[[TiAppiOSNotificationActionProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - ap.notificationAction = notifAction; - - [notifAction release]; - return ap; -} - --(id)createUserNotificationCategory:(id)args -{ - - if(![TiUtils isIOS8OrGreater]) { - return nil; - } - - ENSURE_SINGLE_ARG(args,NSDictionary); - UIMutableUserNotificationCategory *notifCategory = [[UIMutableUserNotificationCategory alloc] init]; - - id identifier = [args objectForKey:@"identifier"]; - - if (identifier!=nil) { - notifCategory.identifier = identifier; - } - - id actionsForDefaultContext = [args objectForKey:@"actionsForDefaultContext"]; - id actionsForMinimalContext = [args objectForKey:@"actionsForMinimalContext"]; - - if (actionsForDefaultContext != nil) { - NSMutableArray *afdc = [[NSMutableArray alloc] init]; - - for(TiAppiOSNotificationActionProxy* action in actionsForDefaultContext) { - [afdc addObject:action.notificationAction]; - } - [notifCategory setActions:afdc forContext:UIUserNotificationActionContextDefault]; - RELEASE_TO_NIL(afdc); - } - if (actionsForMinimalContext != nil) { - NSMutableArray *afmc = [[NSMutableArray alloc] init]; - - for(TiAppiOSNotificationActionProxy* action in actionsForMinimalContext) { - [afmc addObject:action.notificationAction]; - } - [notifCategory setActions:afmc forContext:UIUserNotificationActionContextMinimal]; - RELEASE_TO_NIL(afmc); - } - - TiAppiOSNotificationCategoryProxy *cp = [[[TiAppiOSNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - - cp.notificationCategory = notifCategory; - - [notifCategory release]; - return cp; -} - -(void)registerUserNotificationSettings:(id)args { if (![TiUtils isIOS8OrGreater]) return; @@ -421,14 +335,41 @@ -(void)registerUserNotificationSettings:(id)args [categoriesSet addObject:[(TiAppiOSNotificationCategoryProxy*)category notificationCategory]]; } } - + +#if IS_XCODE_8 + UNAuthorizationOptions types = UNAuthorizationOptionNone; +#else UIUserNotificationType types = UIUserNotificationTypeNone; +#endif + if (typesRequested != nil) { for (id thisTypeRequested in typesRequested) { NSUInteger value = [TiUtils intValue:thisTypeRequested]; switch(value) { +#if IS_XCODE_8 + case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE + { + types |= UNAuthorizationOptionBadge; + break; + } + case UNAuthorizationOptionAlert: // USER_NOTIFICATION_TYPE_ALERT + { + types |= UNAuthorizationOptionAlert; + break; + } + case UNAuthorizationOptionSound: // USER_NOTIFICATION_TYPE_SOUND + { + types |= UNAuthorizationOptionSound; + break; + } + case UNAuthorizationOptionCarPlay: // USER_NOTIFICATION_TYPE_CAR_PLAY + { + types |= UNAuthorizationOptionCarPlay; + break; + } +#else case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE { types |= UIUserNotificationTypeBadge; @@ -444,14 +385,44 @@ -(void)registerUserNotificationSettings:(id)args types |= UIUserNotificationTypeSound; break; } +#endif } } } - + +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler: ^(BOOL granted, NSError *error) { + if (granted == YES) { + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categoriesSet]; + } + + if ([self _hasListeners:@"usernotificationauthorization"]) { + NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{@"success": NUMBOOL(granted)}]; + + if (error) { + [event setValue:[error localizedDescription] forKey:@"error"]; + [event setValue:NUMINTEGER([error code]) forKey:@"code"]; + } + + [self fireEvent:@"usernotificationauthorization" withObject:event]; + } + }]; +#else UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types categories:categoriesSet]; TiThreadPerformOnMainThread(^{ [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; }, NO); +#endif +} + +-(id)createUserNotificationAction:(id)args +{ + return [[[TiAppiOSNotificationActionProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; +} + +-(id)createUserNotificationCategory:(id)args +{ + return [[[TiAppiOSNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } -(NSArray*)supportedUserActivityTypes @@ -466,19 +437,66 @@ -(NSArray*)supportedUserActivityTypes return supportedActivityTypes; } +-(void)requestCurrentUserNotificationSettings:(id)args +{ + ENSURE_SINGLE_ARG(args, NSArray); + ENSURE_TYPE([args objectAtIndex:0], KrollCallback); + + KrollCallback *callback = [args objectAtIndex:0]; + +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + NSDictionary * propertiesDict = @{ + @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), + @"soundSetting": NUMINTEGER([settings soundSetting]), + @"badgeSetting": NUMINTEGER([settings badgeSetting]), + @"alertSetting": NUMINTEGER([settings alertSetting]), + @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), + @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), + @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), + @"alertStyle": NUMINTEGER([settings alertStyle]) + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; +#else + __block NSDictionary* returnVal = nil; + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + + NSDictionary * propertiesDict = [[self formatUserNotificationSettings:settings]; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }, YES); +#endif +} + -(NSDictionary*)currentUserNotificationSettings { if (![TiUtils isIOS8OrGreater]) { return nil; } + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.requestCurrentUserNotificationSettings"); + +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + DebugLog(@"[ERROR] Please use Ti.App.requestCurrentUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + return; + } +#else __block NSDictionary* returnVal = nil; TiThreadPerformOnMainThread(^{ UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; }, YES); - return [returnVal autorelease];; + return [returnVal autorelease]; +#endif } -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings @@ -526,16 +544,117 @@ -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)noti -(id)scheduleLocalNotification:(id)args { ENSURE_SINGLE_ARG(args,NSDictionary); + + id identifier = [args objectForKey:@"identifier"]; + id repeat = [args objectForKey:@"repeat"]; + id date = [args objectForKey:@"date"]; + id region = [args objectForKey:@"region"]; + id alertTitle = [args objectForKey:@"alertTitle"]; + id alertSubtitle = [args objectForKey:@"alertSubtitle"]; + id alertBody = [args objectForKey:@"alertBody"]; + id alertAction = [args objectForKey:@"alertAction"]; + id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; + id badge = [args objectForKey:@"badge"]; + id category = [args objectForKey:@"category"]; + id userInfo = [args objectForKey:@"userInfo"]; + id sound = [args objectForKey:@"sound"]; + +#if IS_XCODE_8 + UNNotificationTrigger *trigger; + + if (date) { + NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + + NSDateComponents *components = [gregorianCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit + fromDate:date]; + + trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES]; + } else if (repeat) { + // TODO: Calcuate interval from "daily", "weekly", "monthly" and "yearly" + trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0 repeats:YES]; + } else if (region) { + BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; + + // TODO: Deprecate `identifier` in `region` and use top-level identifier for both iOS < 10 and iOS 10 + NSString *identifier = [TiUtils stringValue:[region valueForKey:@"identifier"]]; + + CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) + radius:kCLDistanceFilterNone + identifier:identifier ? identifier : @"notification"]; + + trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion + repeats:triggersOnce]; + } else { + DebugLog(@"[ERROR] Notifications in iOS 10 require the either the `date`, `repeat` or `location` property"); + return; + } + + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + + if (alertTitle) { + [content setTitle:[TiUtils stringValue:alertTitle]]; + } + + if (alertSubtitle) { + [content setSubtitle:[TiUtils stringValue:alertSubtitle]]; + } + + if (alertBody) { + [content setBody:[TiUtils stringValue:alertBody]]; + } + + if (alertLaunchImage) { + [content setLaunchImageName:[TiUtils stringValue:alertLaunchImage]]; + } + + if (badge) { + [content setBadge:[TiUtils numberFromObject:badge]]; + } + + if (userInfo) { + [content setUserInfo:userInfo]; + } + + if (sound) { + if ([sound isEqual:@"default"]) { + [content setSound:[UNNotificationSound defaultSound]]; + } else { + [content setSound:[UNNotificationSound soundNamed:sound]]; + } + } + + if (category != nil && [category isKindOfClass:[TiAppiOSNotificationCategoryProxy class]]) { + [content setCategoryIdentifier:[(TiAppiOSNotificationCategoryProxy*)category identifier]]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + [category setCategoryIdentifier:category]; + } + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] + content:content + trigger:trigger]; + + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request + withCompletionHandler:^(NSError *error) { + if (error) { + DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); + } + }]; + + TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + lp.notification = content; + + return lp; + +#else UILocalNotification *localNotif = [[UILocalNotification alloc] init]; - - id date = [args objectForKey:@"date"]; - + if (date!=nil) { localNotif.fireDate = date; localNotif.timeZone = [NSTimeZone defaultTimeZone]; } - id repeat = [args objectForKey:@"repeat"]; if (repeat!=nil) { if ([repeat isEqual:@"weekly"]) { localNotif.repeatInterval = NSWeekCalendarUnit; @@ -551,29 +670,27 @@ -(id)scheduleLocalNotification:(id)args } } - id alertBody = [args objectForKey:@"alertBody"]; if (alertBody!=nil) { localNotif.alertBody = alertBody; } - id alertTitle = [args objectForKey:@"alertTitle"]; - if (alertTitle!=nil) { + + if (alertTitle!=nil) { localNotif.alertTitle = alertTitle; } - id alertAction = [args objectForKey:@"alertAction"]; - if (alertAction!=nil) { + + if (alertAction!=nil) { localNotif.alertAction = alertAction; } - id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; - if (alertLaunchImage!=nil) { + + if (alertLaunchImage!=nil) { localNotif.alertLaunchImage = alertLaunchImage; } - id badge = [args objectForKey:@"badge"]; - if (badge!=nil) { + + if (badge!=nil) { localNotif.applicationIconBadgeNumber = [TiUtils intValue:badge]; } - id region = [args objectForKey:@"region"]; if (region!=nil) { ENSURE_TYPE(region, NSDictionary); @@ -596,8 +713,7 @@ -(id)scheduleLocalNotification:(id)args localNotif.regionTriggersOnce = regionTriggersOnce; } - id sound = [args objectForKey:@"sound"]; - if (sound!=nil) { + if (sound) { if ([sound isEqual:@"default"]) { localNotif.soundName = UILocalNotificationDefaultSoundName; } @@ -606,12 +722,11 @@ -(id)scheduleLocalNotification:(id)args } } - id userInfo = [args objectForKey:@"userInfo"]; - if (userInfo!=nil) { + if (userInfo) { localNotif.userInfo = userInfo; } - if([TiUtils isIOS8OrGreater]) { + if ([TiUtils isIOS8OrGreater]) { id category = [args objectForKey:@"category"]; if (category != nil && [category isKindOfClass:[TiAppiOSNotificationCategoryProxy class]]) { localNotif.category = [(TiAppiOSNotificationCategoryProxy*)category identifier]; @@ -623,8 +738,7 @@ -(id)scheduleLocalNotification:(id)args TiThreadPerformOnMainThread(^{ if (date!=nil) { [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; - } - else { + } else { [[UIApplication sharedApplication] presentLocalNotificationNow:localNotif]; } }, NO); @@ -634,6 +748,7 @@ -(id)scheduleLocalNotification:(id)args [localNotif release]; return lp; +#endif } -(void)cancelAllLocalNotifications:(id)args @@ -797,36 +912,69 @@ -(NSNumber*)BACKGROUNDFETCHINTERVAL_NEVER { -(NSNumber*)USER_NOTIFICATION_TYPE_NONE { - if ([TiUtils isIOS8OrGreater]) { +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNAuthorizationOptionNone); + } +#else + if ([TiUtils isIOS8OrGreater]) { return NUMINT(UIUserNotificationTypeNone); } +#endif return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_BADGE { +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNAuthorizationOptionBadge); + } +#else if ([TiUtils isIOS8OrGreater]) { return NUMINT(UIUserNotificationTypeBadge); } +#endif return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_SOUND { +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNAuthorizationOptionSound); + } +#else if ([TiUtils isIOS8OrGreater]) { return NUMINT(UIUserNotificationTypeSound); } +#endif return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_ALERT { - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeAlert); - } - return NUMINT(0); +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNAuthorizationOptionAlert); + } +#else + if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeAlert); + } +#endif + return NUMINT(0); } +-(NSNumber*)USER_NOTIFICATION_TYPE_CAR_PLAY +{ +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNAuthorizationOptionCarPlay); + } +#endif + return NUMINT(0); +} -(NSNumber*)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND { From 2032c2df05edb26ea22ccbb1632262ed5f00053e Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Mon, 18 Jul 2016 18:34:12 +0200 Subject: [PATCH 02/44] [TIMOB-23527] More work on iOS10 notifications --- iphone/Classes/TiApp.h | 9 +- iphone/Classes/TiApp.m | 71 +++++++++--- iphone/Classes/TiAppiOSProxy.m | 107 +++++++++--------- ... => TiAppiOSUserNotificationActionProxy.h} | 2 +- ... => TiAppiOSUserNotificationActionProxy.m} | 38 ++++--- ...> TiAppiOSUserNotificationCategoryProxy.h} | 2 +- ...> TiAppiOSUserNotificationCategoryProxy.m} | 25 ++-- .../iphone/Titanium.xcodeproj/project.pbxproj | 24 ++-- 8 files changed, 164 insertions(+), 114 deletions(-) rename iphone/Classes/{TiAppiOSNotificationActionProxy.h => TiAppiOSUserNotificationActionProxy.h} (90%) rename iphone/Classes/{TiAppiOSNotificationActionProxy.m => TiAppiOSUserNotificationActionProxy.m} (65%) rename iphone/Classes/{TiAppiOSNotificationCategoryProxy.h => TiAppiOSUserNotificationCategoryProxy.h} (91%) rename iphone/Classes/{TiAppiOSNotificationCategoryProxy.m => TiAppiOSUserNotificationCategoryProxy.m} (69%) diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index 63acda08494..51c08bed0c5 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -6,7 +6,9 @@ */ #import - +#if IS_XCODE_8 +#import +#endif #import "TiHost.h" #import "KrollBridge.h" #ifdef USE_TI_UIWEBVIEW @@ -28,7 +30,12 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o TiApp represents an instance of an application. There is always only one instance per application which could be accessed through class method. @see app */ + +#if IS_XCODE_8 +@interface TiApp : TiHost +#else @interface TiApp : TiHost +#endif { UIWindow *window; UIImageView *loadView; diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index d4920225444..75f074563a6 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -392,7 +392,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [launchOptions setObject:NUMBOOL([[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey] boolValue]) forKey:@"launchOptionsLocationKey"]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocationKey]; - localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]] retain]; + localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] withIdentifier:nil] retain]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; // reset these to be a little more common if we have them @@ -479,6 +479,26 @@ - (void)application:(UIApplication *)application didRegisterUserNotificationSett [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification object:notificationSettings userInfo:nil]; } +#if IS_XCODE_8 + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +{ + // TODO: Get desired options from notification + completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionSound); +} + +-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler +{ + RELEASE_TO_NIL(localNotification); + localNotification = [[TiApp dictionaryWithLocalNotification:response.notification + withIdentifier:response.notification.request.identifier] retain]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; + completionHandler(); +} + +#else + - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(localNotification); localNotification = [[TiApp dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; @@ -491,6 +511,15 @@ - (void) application:(UIApplication *)application handleActionWithIdentifier:(NS completionHandler(); } +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification +{ + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:nil] retain]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; +} + +#endif + - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(remoteNotification); [self generateNotification:userInfo]; @@ -1201,13 +1230,6 @@ -(void)endBackgrounding RELEASE_TO_NIL(runningServices); } -- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification -{ - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithLocalNotification:notification] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; -} - -(BOOL)handleShortcutItem:(UIApplicationShortcutItem*) shortcutItem waitForBootIfNotLaunched:(BOOL) bootWait { @@ -1302,6 +1324,33 @@ -(void)stopBackgroundService:(TiProxy *)proxy #define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) +#if IS_XCODE_8 ++ (NSDictionary *)dictionaryWithLocalNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier +{ + if (notification == nil) { + return nil; + } + NSMutableDictionary* event = [NSMutableDictionary dictionary]; + + NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + + [event setObject:NOTNIL([notification date]) forKey:@"date"]; + + // TODO: Try to map timezone + //event setObject:NOTNIL([[notification timeZone] name]) forKey:@"timezone"]; + [event setObject:NOTNIL([[[notification request] content] body]) forKey:@"alertBody"]; + [event setObject:NOTNIL([[[notification request] content] title]) forKey:@"alertTitle"]; + [event setObject:NOTNIL([[[notification request] content] subtitle]) forKey:@"alertSubtitle"]; + [event setObject:NOTNIL([[[notification request] content] launchImageName]) forKey:@"alertLaunchImage"]; + [event setObject:NOTNIL([[[notification request] content] sound]) forKey:@"sound"]; + [event setObject:NOTNIL([[[notification request] content] badge]) forKey:@"badge"]; + [event setObject:NOTNIL([[[notification request] content] userInfo]) forKey:@"userInfo"]; + [event setObject:NOTNIL([[[notification request] content] categoryIdentifier]) forKey:@"category"]; + [event setObject:NOTNIL([[notification request] identifier]) forKey:@"identifier"]; + + return event; +} +#else + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier: (NSString *)identifier { if (notification == nil) { @@ -1323,12 +1372,8 @@ + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notific } return event; - -} -+ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification -{ - return [self dictionaryWithLocalNotification: notification withIdentifier: nil]; } +#endif // Returns an NSDictionary with the properties from tiapp.xml // this is called from Ti.App.Properties and other places. diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index a67e2d8ee77..91f72379fe5 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -12,8 +12,8 @@ #ifdef USE_TI_APPIOS #import "TiAppiOSBackgroundServiceProxy.h" #import "TiAppiOSLocalNotificationProxy.h" -#import "TiAppiOSNotificationActionProxy.h" -#import "TiAppiOSNotificationCategoryProxy.h" +#import "TiAppiOSUserNotificationActionProxy.h" +#import "TiAppiOSUserNotificationCategoryProxy.h" #import "TiAppiOSUserDefaultsProxy.h" #import "TiAppiOSUserActivityProxy.h" #import "TiAppiOSSearchableItemAttributeSetProxy.h" @@ -331,8 +331,8 @@ -(void)registerUserNotificationSettings:(id)args if (categories != nil) { categoriesSet = [NSMutableSet set]; for (id category in categories) { - ENSURE_TYPE(category, TiAppiOSNotificationCategoryProxy); - [categoriesSet addObject:[(TiAppiOSNotificationCategoryProxy*)category notificationCategory]]; + ENSURE_TYPE(category, TiAppiOSUserNotificationCategoryProxy); + [categoriesSet addObject:[(TiAppiOSUserNotificationCategoryProxy*)category notificationCategory]]; } } @@ -417,12 +417,13 @@ -(void)registerUserNotificationSettings:(id)args -(id)createUserNotificationAction:(id)args { - return [[[TiAppiOSNotificationActionProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; + return [[[TiAppiOSUserNotificationActionProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } + -(id)createUserNotificationCategory:(id)args { - return [[[TiAppiOSNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; + return [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } -(NSArray*)supportedUserActivityTypes @@ -531,7 +532,7 @@ -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)noti // Categories for (id cat in categories) { - TiAppiOSNotificationCategoryProxy *categoryProxy = [[[TiAppiOSNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; categoryProxy.notificationCategory = cat; [categoriesArray addObject:categoryProxy]; } @@ -565,7 +566,7 @@ -(id)scheduleLocalNotification:(id)args if (date) { NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - NSDateComponents *components = [gregorianCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit + NSDateComponents *components = [gregorianCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:date]; trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES]; @@ -574,8 +575,8 @@ -(id)scheduleLocalNotification:(id)args trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0 repeats:YES]; } else if (region) { BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; // TODO: Deprecate `identifier` in `region` and use top-level identifier for both iOS < 10 and iOS 10 NSString *identifier = [TiUtils stringValue:[region valueForKey:@"identifier"]]; @@ -625,70 +626,65 @@ -(id)scheduleLocalNotification:(id)args } } - if (category != nil && [category isKindOfClass:[TiAppiOSNotificationCategoryProxy class]]) { - [content setCategoryIdentifier:[(TiAppiOSNotificationCategoryProxy*)category identifier]]; + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + [content setCategoryIdentifier:[(TiAppiOSUserNotificationCategoryProxy*)category identifier]]; } else if (category != nil && [category isKindOfClass:[NSString class]]) { - [category setCategoryIdentifier:category]; + [content setCategoryIdentifier:[TiUtils stringValue:category]]; } UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] content:content trigger:trigger]; - [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request - withCompletionHandler:^(NSError *error) { - if (error) { - DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); - } - }]; - - TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - lp.notification = content; - - return lp; + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError *error) { + if (error) { + DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); + } + }]; + }, NO); #else - UILocalNotification *localNotif = [[UILocalNotification alloc] init]; + UILocalNotification *content = [UILocalNotification new]; if (date!=nil) { - localNotif.fireDate = date; - localNotif.timeZone = [NSTimeZone defaultTimeZone]; + content.fireDate = date; + content.timeZone = [NSTimeZone defaultTimeZone]; } if (repeat!=nil) { if ([repeat isEqual:@"weekly"]) { - localNotif.repeatInterval = NSWeekCalendarUnit; + content.repeatInterval = NSWeekCalendarUnit; } else if ([repeat isEqual:@"daily"]) { - localNotif.repeatInterval = NSDayCalendarUnit; + content.repeatInterval = NSDayCalendarUnit; } else if ([repeat isEqual:@"yearly"]) { - localNotif.repeatInterval = NSYearCalendarUnit; + content.repeatInterval = NSYearCalendarUnit; } else if ([repeat isEqual:@"monthly"]) { - localNotif.repeatInterval = NSMonthCalendarUnit; + content.repeatInterval = NSMonthCalendarUnit; } } if (alertBody!=nil) { - localNotif.alertBody = alertBody; + content.alertBody = alertBody; } if (alertTitle!=nil) { - localNotif.alertTitle = alertTitle; + content.alertTitle = alertTitle; } if (alertAction!=nil) { - localNotif.alertAction = alertAction; + content.alertAction = alertAction; } if (alertLaunchImage!=nil) { - localNotif.alertLaunchImage = alertLaunchImage; + content.alertLaunchImage = alertLaunchImage; } - if (badge!=nil) { - localNotif.applicationIconBadgeNumber = [TiUtils intValue:badge]; + content.applicationIconBadgeNumber = [TiUtils intValue:badge]; } if (region!=nil) { @@ -706,49 +702,48 @@ -(id)scheduleLocalNotification:(id)args return; } - localNotif.region = [[CLCircularRegion alloc] initWithCenter:center - radius:kCLDistanceFilterNone - identifier:identifier ? identifier : @"notification"]; + content.region = [[CLCircularRegion alloc] initWithCenter:center + radius:kCLDistanceFilterNone + identifier:identifier ? identifier : @"notification"]; - localNotif.regionTriggersOnce = regionTriggersOnce; + content.regionTriggersOnce = regionTriggersOnce; } if (sound) { if ([sound isEqual:@"default"]) { - localNotif.soundName = UILocalNotificationDefaultSoundName; - } - else { - localNotif.soundName = sound; + content.soundName = UILocalNotificationDefaultSoundName; + } else { + content.soundName = sound; } } if (userInfo) { - localNotif.userInfo = userInfo; + content.userInfo = userInfo; } if ([TiUtils isIOS8OrGreater]) { id category = [args objectForKey:@"category"]; - if (category != nil && [category isKindOfClass:[TiAppiOSNotificationCategoryProxy class]]) { - localNotif.category = [(TiAppiOSNotificationCategoryProxy*)category identifier]; + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + content.category = [(TiAppiOSUserNotificationCategoryProxy*)category identifier]; } else if (category != nil && [category isKindOfClass:[NSString class]]) { - localNotif.category = category; + content.category = category; } } TiThreadPerformOnMainThread(^{ - if (date!=nil) { - [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; + if (date != nil) { + [[UIApplication sharedApplication] scheduleLocalNotification:content]; } else { - [[UIApplication sharedApplication] presentLocalNotificationNow:localNotif]; + [[UIApplication sharedApplication] presentLocalNotificationNow:content]; } }, NO); - +#endif + TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - lp.notification = localNotif; + lp.notification = content; - [localNotif release]; + [content release]; return lp; -#endif } -(void)cancelAllLocalNotifications:(id)args diff --git a/iphone/Classes/TiAppiOSNotificationActionProxy.h b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h similarity index 90% rename from iphone/Classes/TiAppiOSNotificationActionProxy.h rename to iphone/Classes/TiAppiOSUserNotificationActionProxy.h index 43e74bf808b..f7093d897f3 100644 --- a/iphone/Classes/TiAppiOSNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h @@ -12,7 +12,7 @@ #import #endif -@interface TiAppiOSNotificationActionProxy : TiProxy +@interface TiAppiOSUserNotificationActionProxy : TiProxy #if IS_XCODE_8 @property(nonatomic,retain) UNNotificationAction *notificationAction; diff --git a/iphone/Classes/TiAppiOSNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m similarity index 65% rename from iphone/Classes/TiAppiOSNotificationActionProxy.m rename to iphone/Classes/TiAppiOSUserNotificationActionProxy.m index d426a64efad..546b9b57339 100644 --- a/iphone/Classes/TiAppiOSNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -5,12 +5,12 @@ * Please see the LICENSE included with this distribution for details. */ -#import "TiAppiOSNotificationActionProxy.h" +#import "TiAppiOSUserNotificationActionProxy.h" #import "TiUtils.h" #ifdef USE_TI_APPIOS -@implementation TiAppiOSNotificationActionProxy +@implementation TiAppiOSUserNotificationActionProxy -(void)dealloc { @@ -20,22 +20,22 @@ -(void)dealloc -(NSString*)apiName { - return @"Ti.App.iOS.NotificationAction"; + return @"Ti.App.iOS.UserNotificationAction"; } --(id)_initWithPageContext:(id)context args:(NSArray *)args +-(void)_initWithProperties:(NSDictionary *)properties { if (_notificationAction == nil) { #if IS_XCODE_8 - id identifier = [args valueForKey:@"identifier"]; - id title = [args valueForKey:@"title"]; - id activationMode = [args valueForKey:@"activationMode"]; - id authenticationRequired = [args valueForKey:@"authenticationRequired"]; - id destructive = [args valueForKey:@"destructive"]; - id behavior = [args valueForKey:@"behavior"]; - id textInputButtonTitle = [args valueForKey:@"textInputButtonTitle"]; - id textInputButtonPlaceholder = [args valueForKey:@"textInputButtonPlaceholder"]; + id identifier = [properties valueForKey:@"identifier"]; + id title = [properties valueForKey:@"title"]; + id activationMode = [properties valueForKey:@"activationMode"]; + id authenticationRequired = [properties valueForKey:@"authenticationRequired"]; + id destructive = [properties valueForKey:@"destructive"]; + id behavior = [properties valueForKey:@"behavior"]; + id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; + id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; UNNotificationActionOptions options = UNNotificationActionOptionNone; @@ -48,23 +48,25 @@ -(id)_initWithPageContext:(id)context args:(NSArray *)args } if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { - _notificationAction = [UNTextInputNotificationAction actionWithIdentifier:identifier + _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:options textInputButtonTitle:textInputButtonTitle - textInputPlaceholder:textInputButtonPlaceholder]; + textInputPlaceholder:textInputButtonPlaceholder] retain]; + + [super _initWithProperties:properties]; return; } - _notificationAction = [UNNotificationAction actionWithIdentifier:identifier + _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier title:title - options:[TiUtils intValue:activationMode]]; + options:[TiUtils intValue:activationMode]] retain]; #else - _notificationAction = [UIMutableUserNotificationAction new]; + _notificationAction = [[UIMutableUserNotificationAction new] retain]; #endif } - [super _initWithPageContext:context args:args]; + [super _initWithProperties:properties]; } #if IS_XCODE_8 diff --git a/iphone/Classes/TiAppiOSNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h similarity index 91% rename from iphone/Classes/TiAppiOSNotificationCategoryProxy.h rename to iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index c9cdf7f9f85..fcd0393eaf8 100644 --- a/iphone/Classes/TiAppiOSNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -11,7 +11,7 @@ #import #endif -@interface TiAppiOSNotificationCategoryProxy : TiProxy +@interface TiAppiOSUserNotificationCategoryProxy : TiProxy { } diff --git a/iphone/Classes/TiAppiOSNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m similarity index 69% rename from iphone/Classes/TiAppiOSNotificationCategoryProxy.m rename to iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index b8d2d0dc588..54f670c0311 100644 --- a/iphone/Classes/TiAppiOSNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -5,13 +5,13 @@ * Please see the LICENSE included with this distribution for details. */ -#import "TiAppiOSNotificationCategoryProxy.h" -#import "TiAppiOSNotificationActionProxy.h" +#import "TiAppiOSUserNotificationCategoryProxy.h" +#import "TiAppiOSUserNotificationActionProxy.h" #import "TiUtils.h" #ifdef USE_TI_APPIOS -@implementation TiAppiOSNotificationCategoryProxy +@implementation TiAppiOSUserNotificationCategoryProxy -(void)dealloc { @@ -21,26 +21,27 @@ -(void)dealloc -(NSString*)apiName { - return @"Ti.App.iOS.NotificationCategory"; + return @"Ti.App.iOS.UserNotificationCategory"; } --(id)_initWithPageContext:(id)context args:(NSArray *)args +-(void)_initWithProperties:(NSDictionary *)properties { if (_notificationCategory == nil) { - id identifier = [args valueForKey:@"identifier"]; - id actionsForDefaultContext = [args valueForKey:@"actionsForDefaultContext"]; - id actionsForMinimalContext = [args valueForKey:@"actionsForMinimalContext"]; - id intentIdentifiers = [args valueForKey:@"intentIdentifiers"]; + // TODO: Grab properties from self (proxy) instead of local copy + id identifier = [properties valueForKey:@"identifier"]; + id actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; + id actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; + id intentIdentifiers = [properties valueForKey:@"intentIdentifiers"]; NSMutableArray *defaultActions = [NSMutableArray new]; NSMutableArray *minimalActions = [NSMutableArray new]; - for (TiAppiOSNotificationActionProxy *action in actionsForDefaultContext) { + for (TiAppiOSUserNotificationActionProxy *action in actionsForDefaultContext) { [defaultActions addObject:[action notificationAction]]; } - for (TiAppiOSNotificationActionProxy *action in actionsForMinimalContext) { + for (TiAppiOSUserNotificationActionProxy *action in actionsForMinimalContext) { [minimalActions addObject:[action notificationAction]]; } @@ -62,7 +63,7 @@ -(id)_initWithPageContext:(id)context args:(NSArray *)args #endif } - [super _initWithPageContext:context args:args]; + [super _initWithProperties:properties]; } #if IS_XCODE_8 diff --git a/iphone/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/iphone/Titanium.xcodeproj/project.pbxproj index 21b22a52a85..5b2accebd44 100644 --- a/iphone/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/iphone/Titanium.xcodeproj/project.pbxproj @@ -312,8 +312,8 @@ B63761701BC5CA4A0070A695 /* TiLayoutView.m in Sources */ = {isa = PBXBuildFile; fileRef = B637616E1BC5CA4A0070A695 /* TiLayoutView.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; B6465C2318D1011C003C51A8 /* TiNetworkCookieProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B6465C2218D1011C003C51A8 /* TiNetworkCookieProxy.m */; }; B6A0A2B1180DF4DA00E3FAA6 /* TiUIiOSTransitionAnimationProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A0A2B0180DF4DA00E3FAA6 /* TiUIiOSTransitionAnimationProxy.m */; }; - BB26FC8019AB13B9007A35AF /* TiAppiOSNotificationActionProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BB26FC7D19AB13B9007A35AF /* TiAppiOSNotificationActionProxy.m */; }; - BB26FC8319AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BB26FC7F19AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.m */; }; + BB26FC8019AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BB26FC7D19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m */; }; + BB26FC8319AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BB26FC7F19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m */; }; BBDD81341A2C71C9003CDA10 /* TiUIAttributedStringProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BBDD81331A2C71C9003CDA10 /* TiUIAttributedStringProxy.m */; }; CA0D39E51B7F55C6009D534C /* TiAppiOSSearchableItemAttributeSetProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0D39E41B7F55C6009D534C /* TiAppiOSSearchableItemAttributeSetProxy.m */; }; CA0D39E81B7F709E009D534C /* TiAppiOSSearchableItemProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0D39E71B7F709E009D534C /* TiAppiOSSearchableItemProxy.m */; }; @@ -973,10 +973,10 @@ B6A0A2AF180DF4DA00E3FAA6 /* TiUIiOSTransitionAnimationProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIiOSTransitionAnimationProxy.h; sourceTree = ""; }; B6A0A2B0180DF4DA00E3FAA6 /* TiUIiOSTransitionAnimationProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIiOSTransitionAnimationProxy.m; sourceTree = ""; }; B6DFC5CE1A3B8FC200A857B7 /* TiDebugger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TiDebugger.h; path = ../Classes/TiDebugger.h; sourceTree = ""; }; - BB26FC7C19AB13B9007A35AF /* TiAppiOSNotificationActionProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSNotificationActionProxy.h; sourceTree = ""; }; - BB26FC7D19AB13B9007A35AF /* TiAppiOSNotificationActionProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSNotificationActionProxy.m; sourceTree = ""; }; - BB26FC7E19AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSNotificationCategoryProxy.h; sourceTree = ""; }; - BB26FC7F19AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSNotificationCategoryProxy.m; sourceTree = ""; }; + BB26FC7C19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSUserNotificationActionProxy.h; sourceTree = ""; }; + BB26FC7D19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSUserNotificationActionProxy.m; sourceTree = ""; }; + BB26FC7E19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSUserNotificationCategoryProxy.h; sourceTree = ""; }; + BB26FC7F19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSUserNotificationCategoryProxy.m; sourceTree = ""; }; BBDD81321A2C71C9003CDA10 /* TiUIAttributedStringProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIAttributedStringProxy.h; sourceTree = ""; }; BBDD81331A2C71C9003CDA10 /* TiUIAttributedStringProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIAttributedStringProxy.m; sourceTree = ""; }; CA0D39E31B7F55C6009D534C /* TiAppiOSSearchableItemAttributeSetProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSSearchableItemAttributeSetProxy.h; sourceTree = ""; }; @@ -1153,10 +1153,10 @@ 24ADC5151299F6AA0014DB75 /* TiAppiOSBackgroundServiceProxy.m */, 24ADC632129A1ED60014DB75 /* TiAppiOSLocalNotificationProxy.h */, 24ADC633129A1ED60014DB75 /* TiAppiOSLocalNotificationProxy.m */, - BB26FC7C19AB13B9007A35AF /* TiAppiOSNotificationActionProxy.h */, - BB26FC7D19AB13B9007A35AF /* TiAppiOSNotificationActionProxy.m */, - BB26FC7E19AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.h */, - BB26FC7F19AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.m */, + BB26FC7C19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.h */, + BB26FC7D19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m */, + BB26FC7E19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.h */, + BB26FC7F19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m */, 83924E861B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.h */, 83924E871B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.m */, CEBC156F1A95452000CB7B66 /* TiAppiOSUserDefaultsProxy.h */, @@ -2821,7 +2821,7 @@ 24A1E992112E1363003DA834 /* TiUIPickerColumnProxy.m in Sources */, 24A1EAF6112F4C02003DA834 /* UIImage+Alpha.m in Sources */, 24A1EAF7112F4C02003DA834 /* UIImage+Resize.m in Sources */, - BB26FC8319AB13B9007A35AF /* TiAppiOSNotificationCategoryProxy.m in Sources */, + BB26FC8319AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m in Sources */, 15CB440E1C4EBE4000D81480 /* TiUIiOSStatusBarProxy.m in Sources */, 24A1EAF8112F4C02003DA834 /* UIImage+RoundedCorner.m in Sources */, 245B3C3D11375A6600CE7530 /* UtilsModule.m in Sources */, @@ -2925,7 +2925,7 @@ 84D541AD1460B3EE005338D1 /* TiDOMEntityRefProxy.m in Sources */, B6465C2318D1011C003C51A8 /* TiNetworkCookieProxy.m in Sources */, 2BDEA4F31448FFB7004EC750 /* TiUIiOSTabbedBarProxy.m in Sources */, - BB26FC8019AB13B9007A35AF /* TiAppiOSNotificationActionProxy.m in Sources */, + BB26FC8019AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m in Sources */, 844E1F7E14883A3700F5424C /* TiDOMValidator.m in Sources */, DAA72343156D642400757987 /* TiConsole.m in Sources */, 2B353A8115901D41008FBD84 /* Ti3DMatrix.m in Sources */, From dfefb1704cc0c5c2e234f78c71484c87d2190fac Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Mon, 18 Jul 2016 22:27:43 +0200 Subject: [PATCH 03/44] [TIMOB-23527] Support notification attachments --- iphone/Classes/TiApp.m | 13 +++++-------- iphone/Classes/TiAppiOSProxy.m | 35 ++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index cefbac9c672..1ca1ea80745 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -491,14 +491,13 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(localNotification); - localNotification = [[TiApp dictionaryWithLocalNotification:response.notification + localNotification = [[TiApp dictionaryWithUserNotification:response.notification withIdentifier:response.notification.request.identifier] retain]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; completionHandler(); } - -#else +#endif - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(localNotification); @@ -519,8 +518,6 @@ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UI [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; } -#endif - - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(remoteNotification); [self generateNotification:userInfo]; @@ -1331,7 +1328,7 @@ -(void)stopBackgroundService:(TiProxy *)proxy #define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) #if IS_XCODE_8 -+ (NSDictionary *)dictionaryWithLocalNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier ++ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier { if (notification == nil) { return nil; @@ -1356,7 +1353,8 @@ + (NSDictionary *)dictionaryWithLocalNotification:(UNNotification *)notification return event; } -#else +#endif + + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier: (NSString *)identifier { if (notification == nil) { @@ -1379,7 +1377,6 @@ + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notific return event; } -#endif // Returns an NSDictionary with the properties from tiapp.xml // this is called from Ti.App.Properties and other places. diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 91f72379fe5..af2c54fed0e 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -396,7 +396,7 @@ -(void)registerUserNotificationSettings:(id)args [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categoriesSet]; } - if ([self _hasListeners:@"usernotificationauthorization"]) { + if ([self _hasListeners:@"usernotificationsettings"]) { NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{@"success": NUMBOOL(granted)}]; if (error) { @@ -404,7 +404,7 @@ -(void)registerUserNotificationSettings:(id)args [event setValue:NUMINTEGER([error code]) forKey:@"code"]; } - [self fireEvent:@"usernotificationauthorization" withObject:event]; + [self fireEvent:@"usernotificationsettings" withObject:event]; } }]; #else @@ -559,6 +559,7 @@ -(id)scheduleLocalNotification:(id)args id category = [args objectForKey:@"category"]; id userInfo = [args objectForKey:@"userInfo"]; id sound = [args objectForKey:@"sound"]; + id attachments = [args objectForKey:@"attachments"]; #if IS_XCODE_8 UNNotificationTrigger *trigger; @@ -618,6 +619,32 @@ -(id)scheduleLocalNotification:(id)args [content setUserInfo:userInfo]; } + if (attachments) { + NSMutableArray *selectedAttachments = [NSMutableArray arrayWithCapacity:[attachments count]]; + for (id attachment in attachments) { + NSString *_identifier; + NSString *_url; + NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} + NSError *error; + + ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); + ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); + ENSURE_ARG_OR_NIL_FOR_KEY(_options, attachment, @"options", NSDictionary); + + UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier + URL:[TiUtils toURL:_url proxy:self] + options:_options + error:&error]; + if (error) { + NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); + RELEASE_TO_NIL(_attachment); + } else { + [selectedAttachments addObject:_attachment]; + } + } + [content setAttachments:selectedAttachments]; + } + if (sound) { if ([sound isEqual:@"default"]) { [content setSound:[UNNotificationSound defaultSound]]; @@ -691,8 +718,8 @@ -(id)scheduleLocalNotification:(id)args ENSURE_TYPE(region, NSDictionary); BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"latitide"] def:0]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; NSString *identifier = [TiUtils stringValue:[region valueForKey:@"identifier"]]; CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); From 4ac7d9d3093e784b8bdafd35274548f7f62b07fd Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Mon, 18 Jul 2016 22:34:41 +0200 Subject: [PATCH 04/44] [TIMOB-23527] Support notification cancellation --- iphone/Classes/TiAppiOSProxy.m | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index af2c54fed0e..f235efdb32c 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -345,8 +345,7 @@ -(void)registerUserNotificationSettings:(id)args if (typesRequested != nil) { for (id thisTypeRequested in typesRequested) { - NSUInteger value = [TiUtils intValue:thisTypeRequested]; - switch(value) + switch([TiUtils intValue:thisTypeRequested]) { #if IS_XCODE_8 case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE @@ -776,13 +775,22 @@ -(id)scheduleLocalNotification:(id)args -(void)cancelAllLocalNotifications:(id)args { ENSURE_UI_THREAD(cancelAllLocalNotifications,args); + +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; +#else [[UIApplication sharedApplication] cancelAllLocalNotifications]; +#endif } -(void)cancelLocalNotification:(id)args { ENSURE_SINGLE_ARG(args,NSObject); ENSURE_UI_THREAD(cancelLocalNotification,args); + +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[[TiUtils stringValue:args]]]; +#else NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; if (notifications!=nil) { @@ -794,8 +802,8 @@ -(void)cancelLocalNotification:(id)args return; } } - } +#endif } -(void)didReceiveContinueActivityNotification:(NSNotification*)notif From 26e2b0e056a61368c871f7594eb312090f72d764 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Mon, 18 Jul 2016 22:45:28 +0200 Subject: [PATCH 05/44] [TIMOB-23527] Fix compatibility macros --- iphone/Classes/TiAppiOSLocalNotificationProxy.h | 6 ++++-- iphone/Classes/TiAppiOSLocalNotificationProxy.m | 3 +-- iphone/Classes/TiAppiOSProxy.m | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index 3761c748cad..ed5f87645a1 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -4,10 +4,12 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ -#import "TiProxy.h" -#import #ifdef USE_TI_APPIOS +#import "TiProxy.h" +#if IS_XCODE_8 +#import +#endif @interface TiAppiOSLocalNotificationProxy : TiProxy { @private diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 6ea5660e498..732a72b0d11 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -5,11 +5,10 @@ * Please see the LICENSE included with this distribution for details. */ +#ifdef USE_TI_APPIOS #import "TiAppiOSLocalNotificationProxy.h" #import "TiUtils.h" -#ifdef USE_TI_APPIOS - @implementation TiAppiOSLocalNotificationProxy @synthesize notification = _notification; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index f235efdb32c..37ff56e8a97 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -464,9 +464,9 @@ -(void)requestCurrentUserNotificationSettings:(id)args #else __block NSDictionary* returnVal = nil; TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - NSDictionary * propertiesDict = [[self formatUserNotificationSettings:settings]; + NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; [callback call:invocationArray thisObject:self]; From cf7624f2a168946b4b0014a3935dcc4c4090ebf3 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Tue, 19 Jul 2016 11:45:47 +0200 Subject: [PATCH 06/44] [TIMOB-23527] Support notification actions --- iphone/Classes/TiAppiOSProxy.m | 17 +++++++---------- .../TiAppiOSUserNotificationCategoryProxy.h | 2 ++ .../TiAppiOSUserNotificationCategoryProxy.m | 7 +++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 37ff56e8a97..a5d4d9fefcf 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -313,9 +313,6 @@ -(id)registerBackgroundService:(id)args return proxy; } -//TO DO: implement didRegisterUserNotificationSettings delegate? -//remote notifications add 'category' - -(void)registerUserNotificationSettings:(id)args { if (![TiUtils isIOS8OrGreater]) return; @@ -327,12 +324,11 @@ -(void)registerUserNotificationSettings:(id)args ENSURE_ARG_OR_NIL_FOR_KEY(categories, args, @"categories", NSArray); ENSURE_ARG_OR_NIL_FOR_KEY(typesRequested, args, @"types", NSArray); - NSMutableSet *categoriesSet = nil; + NSMutableArray *nativeCategories = [NSMutableArray arrayWithCapacity:[categories count]]; if (categories != nil) { - categoriesSet = [NSMutableSet set]; for (id category in categories) { ENSURE_TYPE(category, TiAppiOSUserNotificationCategoryProxy); - [categoriesSet addObject:[(TiAppiOSUserNotificationCategoryProxy*)category notificationCategory]]; + [nativeCategories addObject:[(TiAppiOSUserNotificationCategoryProxy*)category notificationCategory]]; } } @@ -392,7 +388,7 @@ -(void)registerUserNotificationSettings:(id)args #if IS_XCODE_8 [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler: ^(BOOL granted, NSError *error) { if (granted == YES) { - [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categoriesSet]; + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithArray:nativeCategories]]; } if ([self _hasListeners:@"usernotificationsettings"]) { @@ -407,7 +403,8 @@ -(void)registerUserNotificationSettings:(id)args } }]; #else - UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types categories:categoriesSet]; + UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types + categories:[NSSet setWithArray:nativeCategories]]; TiThreadPerformOnMainThread(^{ [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; }, NO); @@ -624,7 +621,7 @@ -(id)scheduleLocalNotification:(id)args NSString *_identifier; NSString *_url; NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} - NSError *error; + NSError *error = nil; ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); @@ -634,7 +631,7 @@ -(id)scheduleLocalNotification:(id)args URL:[TiUtils toURL:_url proxy:self] options:_options error:&error]; - if (error) { + if (error != nil) { NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); RELEASE_TO_NIL(_attachment); } else { diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index fcd0393eaf8..15012ab2f3f 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -23,6 +23,8 @@ #endif @property (nonatomic,readonly) NSString *identifier; +- (UNNotificationCategory*)notificationCategory; + @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 54f670c0311..7a19c3c3590 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -28,7 +28,6 @@ -(void)_initWithProperties:(NSDictionary *)properties { if (_notificationCategory == nil) { - // TODO: Grab properties from self (proxy) instead of local copy id identifier = [properties valueForKey:@"identifier"]; id actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; id actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; @@ -50,13 +49,13 @@ -(void)_initWithProperties:(NSDictionary *)properties } #if IS_XCODE_8 - _notificationCategory = [UNNotificationCategory categoryWithIdentifier:identifier + _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier actions:defaultActions minimalActions:minimalActions intentIdentifiers:intentIdentifiers - options:UNNotificationCategoryOptionNone]; + options:UNNotificationCategoryOptionCustomDismissAction] retain]; #else - _notificationCategory = [[UIMutableUserNotificationCategory alloc] init]; + _notificationCategory = [UIMutableUserNotificationCategory new]; [_notificationCategory setIdentifier:identifier]; [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; From 63c244e8f8f3232c95ddfc7fa215183a8ebe06dd Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Tue, 19 Jul 2016 12:26:01 +0200 Subject: [PATCH 07/44] [TIMOB-23527] Introduce user-notification-center --- iphone/Classes/TiApp.h | 12 ++ iphone/Classes/TiAppiOSProxy.h | 4 + iphone/Classes/TiAppiOSProxy.m | 15 +++ .../TiAppiOSUserNotificationCenterProxy.h | 27 ++++ .../TiAppiOSUserNotificationCenterProxy.m | 117 ++++++++++++++++++ iphone/Classes/defines.h | 1 + .../iphone/Titanium.xcodeproj/project.pbxproj | 6 + 7 files changed, 182 insertions(+) create mode 100644 iphone/Classes/TiAppiOSUserNotificationCenterProxy.h create mode 100644 iphone/Classes/TiAppiOSUserNotificationCenterProxy.m diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index 1f3d44dda59..468d2da198b 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -217,6 +217,18 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o */ -(NSString*)systemUserAgent; +#if IS_XCODE_8 +/** + Returns a dictionary containing the native notification information (iOS 10 and later). + */ ++ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier; +#endif + +/** + Returns a dictionary containing the native notification information. + */ ++ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier: (NSString *)identifier; + /** Returns or set the user agent string to use for network requests. */ diff --git a/iphone/Classes/TiAppiOSProxy.h b/iphone/Classes/TiAppiOSProxy.h index c9b99cc1c5f..2724e1a51fe 100644 --- a/iphone/Classes/TiAppiOSProxy.h +++ b/iphone/Classes/TiAppiOSProxy.h @@ -13,6 +13,10 @@ @interface TiAppiOSProxy : TiProxy { @private NSMutableDictionary *backgroundServices; + +#ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER + TiProxy *UserNotificationCenter; +#endif } @property (nonatomic, readonly) NSString *EVENT_ACCESSIBILITY_LAYOUT_CHANGED; @property (nonatomic, readonly) NSString *EVENT_ACCESSIBILITY_SCREEN_CHANGED; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index a5d4d9fefcf..5b84b2eaa67 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -20,6 +20,10 @@ #import "TiAppiOSSearchableItemProxy.h" #import "TiAppiOSSearchableIndexProxy.h" +#ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER +#import "TiAppiOSUserNotificationCenterProxy.h" +#endif + #if IS_XCODE_8 #import #endif @@ -187,6 +191,17 @@ -(void)didReceiveApplicationShortcutNotification:(NSNotification*)info [self fireEvent:@"shortcutitemclick" withObject:event]; } +#ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER +-(id)UserNotificationCenter +{ + if (UserNotificationCenter == nil) { + UserNotificationCenter = [[TiAppiOSUserNotificationCenterProxy alloc] _initWithPageContext:[self executionContext]]; + [self rememberProxy:UserNotificationCenter]; + } + return UserNotificationCenter; +} +#endif + #ifdef USE_TI_APPIOSSEARCHABLEINDEX -(id)createSearchableIndex:(id)unused { diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h new file mode 100644 index 00000000000..cd92661b67d --- /dev/null +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -0,0 +1,27 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ +#import "TiProxy.h" +#import "TiApp.h" +#if IS_XCODE_8 +#import +#endif + +@interface TiAppiOSUserNotificationCenterProxy : TiProxy + +- (void)getPendingNotifications:(id)args; + +- (void)getDeliveredNotifications:(id)args; + +- (void)removePendingNotificationsWithIdentifiers:(id)args; + +- (void)removeDeliveredNotificationsWithIdentifiers:(id)args; + +- (void)removeAllPendingNotifications:(id)unused; + +- (void)removeAllDeliveredNotifications:(id)unused; + +@end diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m new file mode 100644 index 00000000000..7cd475e56d8 --- /dev/null +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -0,0 +1,117 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ + +#import "TiAppiOSUserNotificationCenterProxy.h" + +@implementation TiAppiOSUserNotificationCenterProxy + +- (void)getPendingNotifications:(id)args +{ + KrollCallback *callback = nil; + ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); + +#if IS_XCODE_8_ + [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[request identifier]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; +#else + NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; + + for (UILocalNotification *notification in notifications) { + [result addObject:[TiApp dictionaryWithLocalNotification:notification withIdentifier: nil]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; +#endif +} + +- (void)getDeliveredNotifications:(id)args +{ +#if IS_XCODE_8 + KrollCallback *callback = nil; + ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); + + [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[request identifier]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; +#else + NSLog(@"This API is not mapped to iOS < 10, yet."); +#endif +} + +- (void)removePendingNotificationsWithIdentifiers:(id)args +{ +#if IS_XCODE_8 + ENSURE_TYPE(args, NSArray); + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:args]; +#else + NSLog(@"This API is not mapped to iOS < 10, yet."); +#endif +} + +- (void)removeDeliveredNotificationsWithIdentifiers:(id)args +{ +#if IS_XCODE_8 + ENSURE_TYPE(args, NSArray); + [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:args]; +#else + NSLog(@"This API is not mapped to iOS < 10, yet."); +#endif +} + +- (void)removeAllPendingNotifications:(id)unused +{ +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; +#else + [[UIApplication sharedApplication] cancelAllLocalNotifications]; +#endif +} + +- (void)removeAllDeliveredNotifications:(id)unused +{ +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; +#else + // TODO: This currently behaves the same as `removeAllPendingNotifications` + // Either note this in the docs or check if we can remove delivered notifications in iOS < 10 + [[UIApplication sharedApplication] cancelAllLocalNotifications]; +#endif +} + +@end diff --git a/iphone/Classes/defines.h b/iphone/Classes/defines.h index 176ae1fef3e..fa0387dcac4 100644 --- a/iphone/Classes/defines.h +++ b/iphone/Classes/defines.h @@ -118,6 +118,7 @@ #define USE_TI_APPIOSSEARCHABLEITEM #define USE_TI_APPIOSSEARCHABLEITEMATTRIBUTESET #define USE_TI_APPIOSUSERACTIVITY +#define USE_TI_APPIOSUSERNOTIFICATIONCENTER #define USE_TI_UIIOSANIMATOR #define USE_TI_UIIOSSNAPBEHAVIOR #define USE_TI_UIIOSPUSHBEHAVIOR diff --git a/iphone/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/iphone/Titanium.xcodeproj/project.pbxproj index feaefa11c7d..ab4eea1ed4a 100644 --- a/iphone/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/iphone/Titanium.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ 3A0E54371BE811CD003EE654 /* TiUIiOSMenuPopupProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A0E54361BE811CD003EE654 /* TiUIiOSMenuPopupProxy.m */; }; 3A1E40511BEAC73D00943233 /* TiUIiOSMenuPopup.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A1E40501BEAC73D00943233 /* TiUIiOSMenuPopup.m */; }; 3A275F3E1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A275F3D1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m */; }; + 3A3BBAF51D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */; }; 3A5AD7261BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A5AD7251BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m */; }; 3A5AD7291BB9BEA8005B408B /* TiUIiOSPreviewContextProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A5AD7281BB9BEA8005B408B /* TiUIiOSPreviewContextProxy.m */; }; 3A811CD01C2C21E50023468C /* TiUIiOSBlurViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A811CCF1C2C21E50023468C /* TiUIiOSBlurViewProxy.m */; }; @@ -800,6 +801,8 @@ 3A1E40501BEAC73D00943233 /* TiUIiOSMenuPopup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIiOSMenuPopup.m; sourceTree = ""; }; 3A275F3C1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIActivityIndicatorStyleProxy.h; sourceTree = ""; }; 3A275F3D1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIActivityIndicatorStyleProxy.m; sourceTree = ""; }; + 3A3BBAF31D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSUserNotificationCenterProxy.h; sourceTree = ""; }; + 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSUserNotificationCenterProxy.m; sourceTree = ""; }; 3A5AD7241BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIiOSPreviewActionGroupProxy.h; sourceTree = ""; }; 3A5AD7251BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIiOSPreviewActionGroupProxy.m; sourceTree = ""; }; 3A5AD7271BB9BEA8005B408B /* TiUIiOSPreviewContextProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIiOSPreviewContextProxy.h; sourceTree = ""; }; @@ -1136,6 +1139,8 @@ BB26FC7D19AB13B9007A35AF /* TiAppiOSUserNotificationActionProxy.m */, BB26FC7E19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.h */, BB26FC7F19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m */, + 3A3BBAF31D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.h */, + 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */, 83924E861B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.h */, 83924E871B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.m */, CEBC156F1A95452000CB7B66 /* TiAppiOSUserDefaultsProxy.h */, @@ -2647,6 +2652,7 @@ 3A5AD7261BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m in Sources */, 24CA8B7D111161FE0084E2DE /* TiUITabProxy.m in Sources */, 3A811CD01C2C21E50023468C /* TiUIiOSBlurViewProxy.m in Sources */, + 3A3BBAF51D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m in Sources */, CA0D39E51B7F55C6009D534C /* TiAppiOSSearchableItemAttributeSetProxy.m in Sources */, 24CA8B80111161FE0084E2DE /* TiUITableViewProxy.m in Sources */, 24CA8B84111161FE0084E2DE /* TiUITableView.m in Sources */, From ff65895afc9d2594fe3b72ed6259a65384d0a26c Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Tue, 19 Jul 2016 18:18:12 +0200 Subject: [PATCH 08/44] [TIMOB-23527] Migrate to Xcode Beta 3, change note --- iphone/Classes/NetworkModule.m | 5 ++--- iphone/Classes/TiApp.m | 18 ++++++++++++++++++ .../TiAppiOSUserNotificationCategoryProxy.m | 6 ++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/iphone/Classes/NetworkModule.m b/iphone/Classes/NetworkModule.m index 4c8d68ea3f4..2e5bafb5a44 100644 --- a/iphone/Classes/NetworkModule.m +++ b/iphone/Classes/NetworkModule.m @@ -304,7 +304,7 @@ -(void)registerForPushNotifications:(id)args [app registerForRemoteNotifications]; if ([args objectForKey:@"types"] != nil) { - NSLog(@"[WARN] Passing `types` to registerForPushNotifications is not supported on iOS 8 and greater. Use registerUserNotificationSettings to register notification types."); + NSLog(@"[WARN] Passing `types` to registerForPushNotifications is not supported on iOS 8 and greater. Use Ti.App.iOS.registerUserNotificationSettings to register notification types."); } } else { @@ -359,8 +359,7 @@ -(void)registerForPushNotifications:(id)args -(void)unregisterForPushNotifications:(id)args { - UIApplication * app = [UIApplication sharedApplication]; - [app unregisterForRemoteNotifications]; + [[UIApplication sharedApplication] unregisterForRemoteNotifications]; } #pragma mark Push Notification Delegates diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 1ca1ea80745..495e7298c5b 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -490,6 +490,24 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { + /*RELEASE_TO_NIL(remoteNotification); + [self generateNotification:userInfo]; + NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; + event[@"data"] = remoteNotification; + if (identifier != nil) { + event[@"identifier"] = identifier; + } + NSString *category = remoteNotification[@"category"]; + if (category != nil) { + event[@"category"] = category; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; + [event autorelease]; + completionHandler();*/ + + // TODO: See if notification is local or remote + + RELEASE_TO_NIL(localNotification); localNotification = [[TiApp dictionaryWithUserNotification:response.notification withIdentifier:response.notification.request.identifier] retain]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 7a19c3c3590..67404d5f62a 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -49,11 +49,13 @@ -(void)_initWithProperties:(NSDictionary *)properties } #if IS_XCODE_8 + RELEASE_TO_NIL(minimalActions); + RELEASE_TO_NIL(actionsForMinimalContext); + _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier actions:defaultActions - minimalActions:minimalActions intentIdentifiers:intentIdentifiers - options:UNNotificationCategoryOptionCustomDismissAction] retain]; + options:UNNotificationCategoryOptionCustomDismissAction] retain]; #else _notificationCategory = [UIMutableUserNotificationCategory new]; [_notificationCategory setIdentifier:identifier]; From cebea15fba0c8a3a93fc70bbd8e61b5428cf86f0 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Tue, 19 Jul 2016 21:05:31 +0200 Subject: [PATCH 09/44] [TIMOB-23527] Cleanup, first docs --- apidoc/Titanium/App/iOS/iOS.yml | 58 ++++++++- iphone/Classes/TiApp.m | 3 +- iphone/Classes/TiAppiOSProxy.m | 121 +++++++++--------- .../TiAppiOSUserNotificationCenterProxy.h | 2 + .../TiAppiOSUserNotificationCenterProxy.m | 39 ++++++ iphone/Classes/TiUtils.h | 6 + iphone/Classes/TiUtils.m | 5 + 7 files changed, 164 insertions(+), 70 deletions(-) diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index d18c8114c2c..a301ab90a1b 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -1106,6 +1106,12 @@ since: "1.7" platforms: [iphone, ipad] properties: + - name: identifier + summary: The notification identifier. + description: This property is required in iOS 10 and later. + optional: false + since: "6.0.0" + - name: alertAction summary: | Alert button text ('Open', by default) or slider text ('slide to unlock...', by default) @@ -1119,16 +1125,31 @@ properties: optional: true - name: alertTitle - summary: Alert title to display. Available since Titanium SDK 5.4.0. + summary: Alert title to display. + type: String + optional: true + osver: {ios: {min: "8.2"}} + since: "6.0.0" + + - name: alertSubtitle + summary: Alert subtitle to display. type: String optional: true - since: "5.4.0" + osver: {ios: {min: "10.0"}} + since: "6.0.0" - name: alertLaunchImage summary: Image to display instead of `Default.png` when launching the application. type: String optional: true + - name: attachments + summary: Notification attachments to display. + type: Array + optional: true + osver: {ios: {min: "10.0"}} + since: "6.0.0" + - name: badge summary: Application badge value. type: Number @@ -1174,11 +1195,40 @@ properties: - `latitude`: Latitude of the location center, in decimal degrees (required). - `longitude`: Longitude of the location center, in decimal degrees (required). - `triggersOnce`: Whether or not the notification will only fire once (optional, default: true). - - `identifier`: Identifier of the region (optional). type: Dictionary optional: true - since: "5.4.0" + osver: {ios: {min: "8.0"}} + since: "6.0.0" +--- +name: UserNotificationAttachment +summary: | + Provide at least the property `identifier` and `url` property to identify a local + image, sound or video. If your media is invalid, the API will throw an error log and + skip the invalid attachment. +since: "6.0.0" +platforms: [iphone, ipad] +osver: {ios: {min: "10.0"}} + +properties: + + - name: identifier + type: String + summary: The identifier of this attachment. + optional: false + - name: url + type: String + summary: | + The URL to the attachment's data. If you have obtained this attachment from + the notification-center then the URL will be security-scoped. + optional: false + - name: options + type: Dictionary + summary: An additional dictionary of options to provide. + description: | + Allowed options can be found in the [Apple docs](https://developer.apple.com/reference/usernotifications/1974189-usernotifications_constants). + optional: true + --- name: UserNotificationSettings summary: | diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 495e7298c5b..7985ee51af5 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -1357,8 +1357,7 @@ + (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification [event setObject:NOTNIL([notification date]) forKey:@"date"]; - // TODO: Try to map timezone - //event setObject:NOTNIL([[notification timeZone] name]) forKey:@"timezone"]; + [event setObject:NOTNIL([[NSTimeZone defaultTimeZone] name]) forKey:@"timezone"]; [event setObject:NOTNIL([[[notification request] content] body]) forKey:@"alertBody"]; [event setObject:NOTNIL([[[notification request] content] title]) forKey:@"alertTitle"]; [event setObject:NOTNIL([[[notification request] content] subtitle]) forKey:@"alertSubtitle"]; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 5b84b2eaa67..470e3c2d4b2 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -449,43 +449,6 @@ -(NSArray*)supportedUserActivityTypes return supportedActivityTypes; } --(void)requestCurrentUserNotificationSettings:(id)args -{ - ENSURE_SINGLE_ARG(args, NSArray); - ENSURE_TYPE([args objectAtIndex:0], KrollCallback); - - KrollCallback *callback = [args objectAtIndex:0]; - -#if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { - NSDictionary * propertiesDict = @{ - @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), - @"soundSetting": NUMINTEGER([settings soundSetting]), - @"badgeSetting": NUMINTEGER([settings badgeSetting]), - @"alertSetting": NUMINTEGER([settings alertSetting]), - @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), - @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), - @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), - @"alertStyle": NUMINTEGER([settings alertStyle]) - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; -#else - __block NSDictionary* returnVal = nil; - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - - NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }, YES); -#endif -} -(NSDictionary*)currentUserNotificationSettings { @@ -493,11 +456,11 @@ -(NSDictionary*)currentUserNotificationSettings return nil; } - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.requestCurrentUserNotificationSettings"); + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.NotificationCenter.requestCurrentUserNotificationSettings"); #if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { - DebugLog(@"[ERROR] Please use Ti.App.requestCurrentUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + DebugLog(@"[ERROR] Please use Ti.App.NotificationCenter.requestCurrentUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; } #else @@ -555,7 +518,7 @@ -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)noti -(id)scheduleLocalNotification:(id)args { - ENSURE_SINGLE_ARG(args,NSDictionary); + ENSURE_SINGLE_ARG(args,NSDictionary); id identifier = [args objectForKey:@"identifier"]; id repeat = [args objectForKey:@"repeat"]; @@ -576,31 +539,44 @@ -(id)scheduleLocalNotification:(id)args UNNotificationTrigger *trigger; if (date) { - NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - - NSDateComponents *components = [gregorianCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit - fromDate:date]; + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + + // Per default, use all components and don't repeat + NSCalendarUnit components = NSYearCalendarUnit|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond; + + if (repeat != nil) { + if ([repeat isEqual:@"weekly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"daily"]) { + components = NSCalendarUnitDay; + } else if ([repeat isEqual:@"yearly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"monthly"]) { + components = NSCalendarUnitMonth; + } else { + NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); + } + } - trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES]; - } else if (repeat) { - // TODO: Calcuate interval from "daily", "weekly", "monthly" and "yearly" - trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0 repeats:YES]; + trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components + fromDate:date] + repeats:(repeat != nil)]; } else if (region) { BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - - // TODO: Deprecate `identifier` in `region` and use top-level identifier for both iOS < 10 and iOS 10 - NSString *identifier = [TiUtils stringValue:[region valueForKey:@"identifier"]]; - + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; + CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) - radius:kCLDistanceFilterNone - identifier:identifier ? identifier : @"notification"]; + radius:radius + identifier:[TiUtils stringValue:@"identifier" + properties:args + def:@"notification"]]; trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion repeats:triggersOnce]; } else { - DebugLog(@"[ERROR] Notifications in iOS 10 require the either the `date`, `repeat` or `location` property"); + DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); return; } @@ -631,7 +607,7 @@ -(id)scheduleLocalNotification:(id)args } if (attachments) { - NSMutableArray *selectedAttachments = [NSMutableArray arrayWithCapacity:[attachments count]]; + NSMutableArray *_attachments = [NSMutableArray arrayWithCapacity:[attachments count]]; for (id attachment in attachments) { NSString *_identifier; NSString *_url; @@ -650,10 +626,10 @@ -(id)scheduleLocalNotification:(id)args NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); RELEASE_TO_NIL(_attachment); } else { - [selectedAttachments addObject:_attachment]; + [_attachments addObject:_attachment]; } } - [content setAttachments:selectedAttachments]; + [content setAttachments:_attachments]; } if (sound) { @@ -675,7 +651,8 @@ -(id)scheduleLocalNotification:(id)args trigger:trigger]; TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError *error) { + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request + withCompletionHandler:^(NSError *error) { if (error) { DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); } @@ -709,7 +686,7 @@ -(id)scheduleLocalNotification:(id)args content.alertBody = alertBody; } - if (alertTitle!=nil) { + if (alertTitle!=nil && [TiUtils isIOS82rGreater]) { content.alertTitle = alertTitle; } @@ -730,8 +707,8 @@ -(id)scheduleLocalNotification:(id)args BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - NSString *identifier = [TiUtils stringValue:[region valueForKey:@"identifier"]]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); @@ -741,8 +718,10 @@ -(id)scheduleLocalNotification:(id)args } content.region = [[CLCircularRegion alloc] initWithCenter:center - radius:kCLDistanceFilterNone - identifier:identifier ? identifier : @"notification"]; + radius:radius + identifier:[TiUtils stringValue:@"identifier" + properties:args + def:@"notification"]]; content.regionTriggersOnce = regionTriggersOnce; } @@ -1281,6 +1260,20 @@ -(NSString*)applicationOpenSettingsURL MAKE_SYSTEM_PROP(FETCH_NODATA, 1); //UIBackgroundFetchResultNoData MAKE_SYSTEM_PROP(FETCH_FAILED, 2); //UIBackgroundFetchResultFailed +#if IS_XCODE_8 +MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED, UNAuthorizationStatusDenied); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED, UNAuthorizationStatusAuthorized); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_NOT_DETERMINED, UNAuthorizationStatusNotDetermined); + +MAKE_SYSTEM_PROP(USER_NOTIFICATION_SETTING_ENABLED, UNNotificationSettingEnabled); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_SETTING_DISABLED, UNNotificationSettingDisabled); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_SETTING_NOT_SUPPORTED, UNNotificationSettingNotSupported); + +MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_NONE, UNAlertStyleNone); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_ALERT, UNAlertStyleAlert); +MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_BANNER, UNAlertStyleBanner); +#endif + @end #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index cd92661b67d..e16895cc572 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -24,4 +24,6 @@ - (void)removeAllDeliveredNotifications:(id)unused; +- (void)requestCurrentUserNotificationSettings:(id)args; + @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 7cd475e56d8..44dea36698d 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -114,4 +114,43 @@ - (void)removeAllDeliveredNotifications:(id)unused #endif } + +- (void)requestCurrentUserNotificationSettings:(id)args +{ + ENSURE_SINGLE_ARG(args, NSArray); + ENSURE_TYPE([args objectAtIndex:0], KrollCallback); + + KrollCallback *callback = [args objectAtIndex:0]; + +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + NSDictionary * propertiesDict = @{ + @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), + @"soundSetting": NUMINTEGER([settings soundSetting]), + @"badgeSetting": NUMINTEGER([settings badgeSetting]), + @"alertSetting": NUMINTEGER([settings alertSetting]), + @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), + @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), + @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), + @"alertStyle": NUMINTEGER([settings alertStyle]) + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; +#else + __block NSDictionary* returnVal = nil; + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + + NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }, YES); +#endif +} + @end diff --git a/iphone/Classes/TiUtils.h b/iphone/Classes/TiUtils.h index c3c4839c60f..6ed3b242c31 100644 --- a/iphone/Classes/TiUtils.h +++ b/iphone/Classes/TiUtils.h @@ -569,6 +569,12 @@ typedef enum */ +(BOOL)isIOS8OrGreater; +/** + Whether or not the current OS version is equal to or greater than 8.2. + @return _YES_ if the current OS version is equal to or greater thann 8.2, _NO_ otherwise. + */ ++(BOOL)isIOS82rGreater; + /** Whether or not the current OS version is equal to or greater than 9.0. @return _YES_ if the current OS version is equal to or greater thann 9.0, _NO_ otherwise. diff --git a/iphone/Classes/TiUtils.m b/iphone/Classes/TiUtils.m index 175410dcf58..2f1a8573b0c 100644 --- a/iphone/Classes/TiUtils.m +++ b/iphone/Classes/TiUtils.m @@ -191,6 +191,11 @@ +(BOOL)isIOS8OrGreater return [UIView instancesRespondToSelector:@selector(layoutMarginsDidChange)]; } ++(BOOL)isIOS82rGreater +{ + return [UILocalNotification instancesRespondToSelector:@selector(alertTitle)]; +} + +(BOOL)isIOS9OrGreater { return [UIImage instancesRespondToSelector:@selector(flipsForRightToLeftLayoutDirection)]; From 914629406705786950d5cb6eb17eeb37fbfeee25 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Wed, 20 Jul 2016 10:00:15 +0200 Subject: [PATCH 10/44] [TIMOB-23527] Add more documentation / constants --- apidoc/Titanium/App/iOS/iOS.yml | 97 ++++++++++++++++++- iphone/Classes/TiAppiOSProxy.m | 4 +- .../TiAppiOSUserNotificationCenterProxy.h | 2 +- .../TiAppiOSUserNotificationCenterProxy.m | 2 +- 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index a301ab90a1b..6d2a9802f16 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -309,6 +309,98 @@ properties: osver: {ios: {min: "9.0"}} since: "5.1.0" + - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_NOT_DETERMINED + summary: | + The user has not yet made a choice regarding whether the application may post + user notifications. + description: | + Use to check the `authorizationStatus` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED + summary: The application is authorized to post user notifications. + description: | + Use to check the `authorizationStatus` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED + summary: The application is not authorized to post user notifications. + description: | + Use to check the `authorizationStatus` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_SETTING_NOT_SUPPORTED + summary: The application does not support this notification type. + description: | + Use to check application-wide enabled notification settings received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_SETTING_ENABLED + summary: The notification setting is turned on. + description: | + Use to check application-wide enabled notification settings received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_SETTING_DISABLED + summary: The notification setting is turned off. + description: | + Use to check application-wide enabled notification settings received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_ALERT_STYLE_NONE + summary: No banner or alert dialog is presented when the notification is received. + description: | + Use to check the `alertStyle` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_ALERT_STYLE_ALERT + summary: A alert dialog is presented when the notification is received. + description: | + Use to check the `alertStyle` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: USER_NOTIFICATION_ALERT_STYLE_BANNER + summary: A banner is presented when the notification is received. + description: | + Use to check the `alertStyle` attribute received in + . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "6.0.0" + - name: UTTYPE_TEXT summary: | Uniform type identifier for all text types. @@ -576,6 +668,9 @@ properties: (available on iOS 8 and later). type: UserNotificationSettings permission: read-only + deprecated: + since: "6.0.0" + notes: Use instead. osver: {ios: {min: "8.0"}} since: "3.4.0" @@ -1236,7 +1331,7 @@ summary: | the method. To retrieve the current notification settings, use the - property. + method. since: "3.4.0" platforms: [iphone, ipad] diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 470e3c2d4b2..2e8b92693b3 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -456,11 +456,11 @@ -(NSDictionary*)currentUserNotificationSettings return nil; } - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.NotificationCenter.requestCurrentUserNotificationSettings"); + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); #if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { - DebugLog(@"[ERROR] Please use Ti.App.NotificationCenter.requestCurrentUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + DebugLog(@"[ERROR] Please use Ti.App.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; } #else diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index e16895cc572..b45a7593426 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -24,6 +24,6 @@ - (void)removeAllDeliveredNotifications:(id)unused; -- (void)requestCurrentUserNotificationSettings:(id)args; +- (void)requestUserNotificationSettings:(id)args; @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 44dea36698d..26307c801ae 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -115,7 +115,7 @@ - (void)removeAllDeliveredNotifications:(id)unused } -- (void)requestCurrentUserNotificationSettings:(id)args +- (void)requestUserNotificationSettings:(id)args { ENSURE_SINGLE_ARG(args, NSArray); ENSURE_TYPE([args objectAtIndex:0], KrollCallback); From 5499b9c5e6edce96e1d785303cc4deefc1469612 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Wed, 20 Jul 2016 10:44:22 +0200 Subject: [PATCH 11/44] [TIMOB-23527] Clean-up response, wrap iOS10-stuff --- iphone/Classes/TiApp.m | 11 +- .../TiAppiOSUserNotificationCenterProxy.m | 145 +++++++++++------- 2 files changed, 97 insertions(+), 59 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 7985ee51af5..ebfecd3450a 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -509,8 +509,8 @@ -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotif RELEASE_TO_NIL(localNotification); - localNotification = [[TiApp dictionaryWithUserNotification:response.notification - withIdentifier:response.notification.request.identifier] retain]; + localNotification = [[[self class] dictionaryWithUserNotification:response.notification + withIdentifier:response.actionIdentifier] retain]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; completionHandler(); @@ -519,7 +519,7 @@ -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotif - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(localNotification); - localNotification = [[TiApp dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; + localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; if([TiUtils isIOS9OrGreater] == YES) { [localNotification setValue:responseInfo[UIUserNotificationActionResponseTypedTextKey] forKey:@"typedText"]; @@ -1353,11 +1353,8 @@ + (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification } NSMutableDictionary* event = [NSMutableDictionary dictionary]; - NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - [event setObject:NOTNIL([notification date]) forKey:@"date"]; - - [event setObject:NOTNIL([[NSTimeZone defaultTimeZone] name]) forKey:@"timezone"]; + [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; [event setObject:NOTNIL([[[notification request] content] body]) forKey:@"alertBody"]; [event setObject:NOTNIL([[[notification request] content] title]) forKey:@"alertTitle"]; [event setObject:NOTNIL([[[notification request] content] subtitle]) forKey:@"alertSubtitle"]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 26307c801ae..c7fd57072ff 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -7,6 +7,8 @@ #import "TiAppiOSUserNotificationCenterProxy.h" +#define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) + @implementation TiAppiOSUserNotificationCenterProxy - (void)getPendingNotifications:(id)args @@ -14,12 +16,30 @@ - (void)getPendingNotifications:(id)args KrollCallback *callback = nil; ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); -#if IS_XCODE_8_ - [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[request identifier]]; + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; +#else + } else { + NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; + + for (UILocalNotification *notification in notifications) { + [result addObject:[[TiApp app] dictionaryWithLocalNotification:notification withIdentifier: nil]]; } NSDictionary * propertiesDict = @{ @@ -29,92 +49,91 @@ - (void)getPendingNotifications:(id)args [callback call:invocationArray thisObject:self]; [invocationArray release]; - }]; -#else - NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; - - for (UILocalNotification *notification in notifications) { - [result addObject:[TiApp dictionaryWithLocalNotification:notification withIdentifier: nil]]; - } - - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; #endif + } } - (void)getDeliveredNotifications:(id)args { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - KrollCallback *callback = nil; - ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); - - [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[request identifier]]; - } + KrollCallback *callback = nil; + ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; + [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; #else - NSLog(@"This API is not mapped to iOS < 10, yet."); + } else { + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); #endif + } } - (void)removePendingNotificationsWithIdentifiers:(id)args { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - ENSURE_TYPE(args, NSArray); - [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:args]; + ENSURE_TYPE(args, NSArray); + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:args]; #else - NSLog(@"This API is not mapped to iOS < 10, yet."); + } else { + // TODO + // [[UIApplication sharedApplication] cancelLocalNotification:notification]; + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers is not available in iOS < 10."); #endif + } } - (void)removeDeliveredNotificationsWithIdentifiers:(id)args { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - ENSURE_TYPE(args, NSArray); - [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:args]; + ENSURE_TYPE(args, NSArray); + [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:args]; #else - NSLog(@"This API is not mapped to iOS < 10, yet."); + } else { + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotificationsWithIdentifiers is not avaible in iOS < 10."); #endif + } } - (void)removeAllPendingNotifications:(id)unused { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; + [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; #else - [[UIApplication sharedApplication] cancelAllLocalNotifications]; + } else { + [[UIApplication sharedApplication] cancelAllLocalNotifications]; #endif + } } - (void)removeAllDeliveredNotifications:(id)unused { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; #else - // TODO: This currently behaves the same as `removeAllPendingNotifications` - // Either note this in the docs or check if we can remove delivered notifications in iOS < 10 - [[UIApplication sharedApplication] cancelAllLocalNotifications]; + } else { + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeAllDeliveredNotifications is not avaible in iOS < 10."); #endif + } } - - (void)requestUserNotificationSettings:(id)args { ENSURE_SINGLE_ARG(args, NSArray); @@ -153,4 +172,26 @@ - (void)requestUserNotificationSettings:(id)args #endif } +#pragma mark Utilities + +#if IS_XCODE_8 +- (NSDictionary*)dictionaryWithUserNotificationRequest:(UNNotificationRequest*)request +{ + NSMutableDictionary* event = [NSMutableDictionary dictionary]; + + [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; + [event setObject:NOTNIL([[request content] body]) forKey:@"alertBody"]; + [event setObject:NOTNIL([[request content] title]) forKey:@"alertTitle"]; + [event setObject:NOTNIL([[request content] subtitle]) forKey:@"alertSubtitle"]; + [event setObject:NOTNIL([[request content] launchImageName]) forKey:@"alertLaunchImage"]; + [event setObject:NOTNIL([[request content] sound]) forKey:@"sound"]; + [event setObject:NOTNIL([[request content] badge]) forKey:@"badge"]; + [event setObject:NOTNIL([[request content] userInfo]) forKey:@"userInfo"]; + [event setObject:NOTNIL([[request content] categoryIdentifier]) forKey:@"category"]; + [event setObject:NOTNIL([request identifier]) forKey:@"identifier"]; + + return event; +} +#endif + @end From bc633f55adaf70a47bf068655d5987e64461a33b Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Wed, 20 Jul 2016 10:50:07 +0200 Subject: [PATCH 12/44] [TIMOB-23527] Fix compatibility macros --- .../TiAppiOSUserNotificationCategoryProxy.h | 4 ++ .../TiAppiOSUserNotificationCenterProxy.h | 3 ++ .../TiAppiOSUserNotificationCenterProxy.m | 47 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index 15012ab2f3f..dfc7777014c 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -23,7 +23,11 @@ #endif @property (nonatomic,readonly) NSString *identifier; +#if IS_XCODE_8 - (UNNotificationCategory*)notificationCategory; +#else +- (UIMutableUserNotificationCategory*)notificationCategory; +#endif @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index b45a7593426..89dd35e69ba 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -4,6 +4,8 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ +#ifdef USE_TI_APPIOS + #import "TiProxy.h" #import "TiApp.h" #if IS_XCODE_8 @@ -27,3 +29,4 @@ - (void)requestUserNotificationSettings:(id)args; @end +#endif \ No newline at end of file diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index c7fd57072ff..bce0c1d5f6f 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -5,7 +5,9 @@ * Please see the LICENSE included with this distribution for details. */ +#ifdef USE_TI_APPIOS #import "TiAppiOSUserNotificationCenterProxy.h" +#import "TiAppiOSUserNotificationCategoryProxy.h" #define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) @@ -39,7 +41,7 @@ - (void)getPendingNotifications:(id)args NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; for (UILocalNotification *notification in notifications) { - [result addObject:[[TiApp app] dictionaryWithLocalNotification:notification withIdentifier: nil]]; + [result addObject:[TiApp dictionaryWithLocalNotification:notification withIdentifier: nil]]; } NSDictionary * propertiesDict = @{ @@ -194,4 +196,47 @@ - (NSDictionary*)dictionaryWithUserNotificationRequest:(UNNotificationRequest*)r } #endif +-(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings +{ + if (![NSThread isMainThread]) { + __block NSDictionary*result = nil; + TiThreadPerformOnMainThread(^{ + result = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, YES); + return [result autorelease]; + + } + NSMutableArray *typesArray = [NSMutableArray array]; + NSMutableArray *categoriesArray = [NSMutableArray array]; + + NSUInteger types = notificationSettings.types; + NSSet *categories = notificationSettings.categories; + + // Types + if ((types & UIUserNotificationTypeBadge)!=0) + { + [typesArray addObject:NUMINT(UIUserNotificationTypeBadge)]; + } + if ((types & UIUserNotificationTypeAlert)!=0) + { + [typesArray addObject:NUMINT(UIUserNotificationTypeAlert)]; + } + if ((types & UIUserNotificationTypeSound)!=0) + { + [typesArray addObject:NUMINT(UIUserNotificationTypeSound)]; + } + + // Categories + for (id cat in categories) { + TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + categoryProxy.notificationCategory = cat; + [categoriesArray addObject:categoryProxy]; + } + return [NSDictionary dictionaryWithObjectsAndKeys: + typesArray, @"types", + categoriesArray, @"categories", + nil]; +} + @end +#endif \ No newline at end of file From 91b9db50f6a60f11cf59d5a8599645f5bd53f480 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Thu, 21 Jul 2016 19:16:05 +0200 Subject: [PATCH 13/44] [TIMOB-23527] Migrate more to notification center --- .../Classes/TiAppiOSLocalNotificationProxy.h | 2 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 19 +-- iphone/Classes/TiAppiOSProxy.m | 111 ++++++++++-------- .../TiAppiOSUserNotificationCenterProxy.m | 56 +++++++-- 4 files changed, 119 insertions(+), 69 deletions(-) diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index ed5f87645a1..83fae954bb3 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -27,7 +27,7 @@ @property(nonatomic,retain) UILocalNotification *notification; #endif --(void)cancel:(id)args; +-(void)cancel:(id)used; @end diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 732a72b0d11..0300a486324 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -24,19 +24,20 @@ -(NSString*)apiName return @"Ti.App.iOS.LocalNotification"; } --(void)cancel:(id)args +-(void)cancel:(id)unused { -#if IS_XCODE_8 - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.0.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); - TiThreadPerformOnMainThread(^{ - [center removePendingNotificationRequestsWithIdentifiers:@[[self.notification categoryIdentifier]]]; - }, NO); +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + return; + } #else - UILocalNotification * cancelledNotification = [self.notification retain]; - TiThreadPerformOnMainThread(^{ + UILocalNotification * cancelledNotification = [self.notification retain]; + TiThreadPerformOnMainThread(^{ [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; - [cancelledNotification release]; + [cancelledNotification release]; }, NO); #endif } diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 2e8b92693b3..5b2aa531bac 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -458,20 +458,21 @@ -(NSDictionary*)currentUserNotificationSettings DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { - DebugLog(@"[ERROR] Please use Ti.App.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); +#if IS_XCODE_8 + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; - } + } else { #else - __block NSDictionary* returnVal = nil; - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; - }, YES); - - return [returnVal autorelease]; + __block NSDictionary* returnVal = nil; + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, YES); + + return [returnVal autorelease]; #endif + } } -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings @@ -748,7 +749,7 @@ -(id)scheduleLocalNotification:(id)args } TiThreadPerformOnMainThread(^{ - if (date != nil) { + if (date != nil || region != nil) { [[UIApplication sharedApplication] scheduleLocalNotification:content]; } else { [[UIApplication sharedApplication] presentLocalNotificationNow:content]; @@ -763,15 +764,21 @@ -(id)scheduleLocalNotification:(id)args return lp; } --(void)cancelAllLocalNotifications:(id)args +-(void)cancelAllLocalNotifications:(id)unused { - ENSURE_UI_THREAD(cancelAllLocalNotifications,args); + ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); + + DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.0.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removeAllPendingNotifications in iOS 10 and later."); + return; + } else { #else - [[UIApplication sharedApplication] cancelAllLocalNotifications]; + [[UIApplication sharedApplication] cancelAllLocalNotifications]; #endif + } } -(void)cancelLocalNotification:(id)args @@ -779,22 +786,28 @@ -(void)cancelLocalNotification:(id)args ENSURE_SINGLE_ARG(args,NSObject); ENSURE_UI_THREAD(cancelLocalNotification,args); + DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.0.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[[TiUtils stringValue:args]]]; + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers in iOS 10 and later."); + return; + } else { #else - NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; - if (notifications!=nil) - { - for (UILocalNotification *notification in notifications) - { - if([[[notification userInfo] objectForKey:@"id"] isEqual:args]) - { - [[UIApplication sharedApplication] cancelLocalNotification:notification]; - return; - } - } - } + NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; + if (notifications!=nil) + { + for (UILocalNotification *notification in notifications) + { + if([[[notification userInfo] objectForKey:@"id"] isEqual:args]) + { + [[UIApplication sharedApplication] cancelLocalNotification:notification]; + return; + } + } + } #endif + } } -(void)didReceiveContinueActivityNotification:(NSNotification*)notif @@ -933,57 +946,53 @@ -(NSNumber*)BACKGROUNDFETCHINTERVAL_NEVER { -(NSNumber*)USER_NOTIFICATION_TYPE_NONE { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionNone); - } #else - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeNone); - } + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeNone); #endif - return NUMINT(0); + } + return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_BADGE { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionBadge); - } + } else if ([TiUtils isIOS8OrGreater]) { #else - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeBadge); - } + return NUMINT(UIUserNotificationTypeBadge); #endif - return NUMINT(0); + } + return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_SOUND { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionSound); - } + } else if ([TiUtils isIOS8OrGreater]) { #else - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeSound); - } + return NUMINT(UIUserNotificationTypeSound); #endif - return NUMINT(0); + } + return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_ALERT { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionAlert); - } + } else if ([TiUtils isIOS8OrGreater]) { #else - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeAlert); - } + return NUMINT(UIUserNotificationTypeAlert); #endif + } return NUMINT(0); } diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index bce0c1d5f6f..f2a0ff415f1 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -8,6 +8,7 @@ #ifdef USE_TI_APPIOS #import "TiAppiOSUserNotificationCenterProxy.h" #import "TiAppiOSUserNotificationCategoryProxy.h" +#import "TiAppiOSLocalNotificationProxy.h" #define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) @@ -86,25 +87,64 @@ - (void)getDeliveredNotifications:(id)args - (void)removePendingNotificationsWithIdentifiers:(id)args { + ENSURE_TYPE(args, NSArray); + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - ENSURE_TYPE(args, NSArray); - [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:args]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + TiThreadPerformOnMainThread(^{ + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + + // Loop through current notification requests + for (UNNotificationRequest *request in requests) { + + // Loop throigh provided notifications + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + + if ([request content] == [(TiAppiOSLocalNotificationProxy*)notification notification]) { + [center removePendingNotificationRequestsWithIdentifiers:@[[request identifier]]]; + } + } + } + }]; + }, NO); #else } else { - // TODO - // [[UIApplication sharedApplication] cancelLocalNotification:notification]; - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers is not available in iOS < 10."); + TiThreadPerformOnMainThread(^{ + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + [[UIApplication sharedApplication] cancelLocalNotification:[(TiAppiOSLocalNotificationProxy*)notification notification]]; + } + }, NO); #endif } } - (void)removeDeliveredNotificationsWithIdentifiers:(id)args { + ENSURE_TYPE(args, NSArray); + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - ENSURE_TYPE(args, NSArray); - [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:args]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + TiThreadPerformOnMainThread(^{ + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + + // Loop through current notification requests + for (UNNotificationRequest *request in requests) { + + // Loop throigh provided notifications + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + + if ([request content] == [(TiAppiOSLocalNotificationProxy*)notification notification]) { + [center removeDeliveredNotificationsWithIdentifiers:@[[request identifier]]]; + } + } + } + }]; + }, NO); #else } else { NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotificationsWithIdentifiers is not avaible in iOS < 10."); @@ -239,4 +279,4 @@ -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)noti } @end -#endif \ No newline at end of file +#endif From 7e36b48015ac511be922a48d572cb161df9678b4 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Fri, 22 Jul 2016 14:55:23 +0200 Subject: [PATCH 14/44] [TIMOB-23527] Ensure iOS < 10 compatibility --- iphone/Classes/TiAppiOSProxy.m | 86 ++++++++++--------- .../TiAppiOSUserNotificationActionProxy.h | 6 +- .../TiAppiOSUserNotificationActionProxy.m | 62 +++++++------ .../TiAppiOSUserNotificationCategoryProxy.h | 6 +- .../TiAppiOSUserNotificationCategoryProxy.m | 32 ++++--- 5 files changed, 94 insertions(+), 98 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 5b2aa531bac..126047b9a97 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -346,56 +346,64 @@ -(void)registerUserNotificationSettings:(id)args [nativeCategories addObject:[(TiAppiOSUserNotificationCategoryProxy*)category notificationCategory]]; } } + + NSUInteger types; + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - UNAuthorizationOptions types = UNAuthorizationOptionNone; -#else - UIUserNotificationType types = UIUserNotificationTypeNone; + types = UNAuthorizationOptionNone; #endif + } else { + types = UIUserNotificationTypeNone; + } if (typesRequested != nil) { for (id thisTypeRequested in typesRequested) { - switch([TiUtils intValue:thisTypeRequested]) - { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE + switch([TiUtils intValue:thisTypeRequested]) { - types |= UNAuthorizationOptionBadge; - break; - } - case UNAuthorizationOptionAlert: // USER_NOTIFICATION_TYPE_ALERT - { - types |= UNAuthorizationOptionAlert; - break; - } - case UNAuthorizationOptionSound: // USER_NOTIFICATION_TYPE_SOUND - { - types |= UNAuthorizationOptionSound; - break; - } - case UNAuthorizationOptionCarPlay: // USER_NOTIFICATION_TYPE_CAR_PLAY - { - types |= UNAuthorizationOptionCarPlay; - break; - } -#else - case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE - { - types |= UIUserNotificationTypeBadge; - break; - } - case UIUserNotificationTypeAlert: // USER_NOTIFICATION_TYPE_ALERT - { - types |= UIUserNotificationTypeAlert; - break; - } - case UIUserNotificationTypeSound: // USER_NOTIFICATION_TYPE_SOUND - { - types |= UIUserNotificationTypeSound; - break; + case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE + { + types |= UNAuthorizationOptionBadge; + break; + } + case UNAuthorizationOptionAlert: // USER_NOTIFICATION_TYPE_ALERT + { + types |= UNAuthorizationOptionAlert; + break; + } + case UNAuthorizationOptionSound: // USER_NOTIFICATION_TYPE_SOUND + { + types |= UNAuthorizationOptionSound; + break; + } + case UNAuthorizationOptionCarPlay: // USER_NOTIFICATION_TYPE_CAR_PLAY + { + types |= UNAuthorizationOptionCarPlay; + break; + } } #endif + } else { + switch([TiUtils intValue:thisTypeRequested]) { + case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE + { + types |= UIUserNotificationTypeBadge; + break; + } + case UIUserNotificationTypeAlert: // USER_NOTIFICATION_TYPE_ALERT + { + types |= UIUserNotificationTypeAlert; + break; + } + case UIUserNotificationTypeSound: // USER_NOTIFICATION_TYPE_SOUND + { + types |= UIUserNotificationTypeSound; + break; + } + } } } } diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h index f7093d897f3..8a123794057 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h @@ -14,11 +14,7 @@ @interface TiAppiOSUserNotificationActionProxy : TiProxy -#if IS_XCODE_8 -@property(nonatomic,retain) UNNotificationAction *notificationAction; -#else -@property(nonatomic,retain) UIMutableUserNotificationAction *notificationAction; -#endif +@property(nonatomic,retain) id notificationAction; @end diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 546b9b57339..151d251fcc6 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -27,7 +27,6 @@ -(void)_initWithProperties:(NSDictionary *)properties { if (_notificationAction == nil) { -#if IS_XCODE_8 id identifier = [properties valueForKey:@"identifier"]; id title = [properties valueForKey:@"title"]; id activationMode = [properties valueForKey:@"activationMode"]; @@ -37,43 +36,42 @@ -(void)_initWithProperties:(NSDictionary *)properties id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; - UNNotificationActionOptions options = UNNotificationActionOptionNone; - - if (destructive) { - options |= UNNotificationActionOptionDestructive; - } - - if (authenticationRequired) { - options |= UNNotificationActionOptionAuthenticationRequired; - } - - if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { - _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier - title:title - options:options - textInputButtonTitle:textInputButtonTitle - textInputPlaceholder:textInputButtonPlaceholder] retain]; - - [super _initWithProperties:properties]; - return; - } - - _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier - title:title - options:[TiUtils intValue:activationMode]] retain]; -#else - _notificationAction = [[UIMutableUserNotificationAction new] retain]; + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + UNNotificationActionOptions options = UNNotificationActionOptionNone; + + if (destructive) { + options |= UNNotificationActionOptionDestructive; + } + + if (authenticationRequired) { + options |= UNNotificationActionOptionAuthenticationRequired; + } + + if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { + _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier + title:title + options:options + textInputButtonTitle:textInputButtonTitle + textInputPlaceholder:textInputButtonPlaceholder] retain]; + + [super _initWithProperties:properties]; + return; + } + + _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier + title:title + options:[TiUtils intValue:activationMode]] retain]; #endif + } else { + _notificationAction = [[UIMutableUserNotificationAction new] retain]; + } } [super _initWithProperties:properties]; } -#if IS_XCODE_8 --(UNNotificationAction*) notificationAction -#else --(UIMutableUserNotificationAction*) notificationAction -#endif +-(id) notificationAction { return _notificationAction; } diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index dfc7777014c..addde073f52 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -16,11 +16,7 @@ } -#if IS_XCODE_8 -@property (nonatomic,retain) UNNotificationCategory *notificationCategory; -#else -@property (nonatomic,retain) UIMutableUserNotificationCategory *notificationCategory; -#endif +@property (nonatomic,retain) id notificationCategory; @property (nonatomic,readonly) NSString *identifier; #if IS_XCODE_8 diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 67404d5f62a..5e0cbe61ac7 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -48,30 +48,28 @@ -(void)_initWithProperties:(NSDictionary *)properties intentIdentifiers = @[]; } + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - RELEASE_TO_NIL(minimalActions); - RELEASE_TO_NIL(actionsForMinimalContext); - - _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier - actions:defaultActions - intentIdentifiers:intentIdentifiers - options:UNNotificationCategoryOptionCustomDismissAction] retain]; -#else - _notificationCategory = [UIMutableUserNotificationCategory new]; - [_notificationCategory setIdentifier:identifier]; - [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; - [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; + RELEASE_TO_NIL(minimalActions); + RELEASE_TO_NIL(actionsForMinimalContext); + + _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier + actions:defaultActions + intentIdentifiers:intentIdentifiers + options:UNNotificationCategoryOptionCustomDismissAction] retain]; #endif + } else { + _notificationCategory = [UIMutableUserNotificationCategory new]; + [_notificationCategory setIdentifier:identifier]; + [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; + [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; + } } [super _initWithProperties:properties]; } -#if IS_XCODE_8 --(UNNotificationCategory*)notificationCategory -#else --(UIUserNotificationCategory*)notificationCategory -#endif +-(id)notificationCategory { return _notificationCategory; } From 257b5b95f1b97fe6a0ead74e96691cfa092c914c Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Fri, 22 Jul 2016 20:58:41 +0200 Subject: [PATCH 15/44] [TIMOB-23527] Fix more legacy code-compatibility --- iphone/Classes/TiApp.m | 11 +- .../Classes/TiAppiOSLocalNotificationProxy.h | 13 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 16 +- iphone/Classes/TiAppiOSProxy.m | 504 +++++++++--------- .../TiAppiOSUserNotificationActionProxy.m | 14 +- .../TiAppiOSUserNotificationCategoryProxy.h | 9 +- .../TiAppiOSUserNotificationCategoryProxy.m | 7 +- .../TiAppiOSUserNotificationCenterProxy.h | 10 +- .../TiAppiOSUserNotificationCenterProxy.m | 135 ++--- 9 files changed, 356 insertions(+), 363 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index ebfecd3450a..1c524762649 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -481,10 +481,10 @@ - (void)application:(UIApplication *)application didRegisterUserNotificationSett } #if IS_XCODE_8 - - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { // TODO: Get desired options from notification + // For example, pass none for silent pushes completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionSound); } @@ -1383,11 +1383,16 @@ + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notific [event setObject:NOTNIL([notification soundName]) forKey:@"sound"]; [event setObject:NUMINTEGER([notification applicationIconBadgeNumber]) forKey:@"badge"]; [event setObject:NOTNIL([notification userInfo]) forKey:@"userInfo"]; - //include category for ios8 + + // Include category for iOS 8 if ([TiUtils isIOS8OrGreater]) { [event setObject:NOTNIL([notification category]) forKey:@"category"]; - [event setObject:NOTNIL(identifier) forKey:@"identifier"]; } + + // Include title for iOS 8.2 + if ([TiUtils isIOS82rGreater]) { + [event setObject:NOTNIL([notification alertTitle]) forKey:@"alertTitle"]; + } return event; } diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index 83fae954bb3..6f3176a8d64 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -13,19 +13,10 @@ @interface TiAppiOSLocalNotificationProxy : TiProxy { @private -#if IS_XCODE_8 - UNMutableNotificationContent *_notification; -#else - UILocalNotification *_notification; -#endif - + id _notification; } -#if IS_XCODE_8 -@property(nonatomic,retain) UNMutableNotificationContent *notification; -#else -@property(nonatomic,retain) UILocalNotification *notification; -#endif +@property(nonatomic,retain) id notification; -(void)cancel:(id)used; diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 0300a486324..ee93b3f6a80 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -28,18 +28,18 @@ -(void)cancel:(id)unused { DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.0.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; - } -#else - UILocalNotification * cancelledNotification = [self.notification retain]; - TiThreadPerformOnMainThread(^{ - [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; - [cancelledNotification release]; - }, NO); #endif + } else { + UILocalNotification * cancelledNotification = [self.notification retain]; + TiThreadPerformOnMainThread(^{ + [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; + [cancelledNotification release]; + }, NO); + } } @end diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 126047b9a97..8e253ffd23f 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -408,30 +408,32 @@ -(void)registerUserNotificationSettings:(id)args } } + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler: ^(BOOL granted, NSError *error) { - if (granted == YES) { - [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithArray:nativeCategories]]; - } - - if ([self _hasListeners:@"usernotificationsettings"]) { - NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{@"success": NUMBOOL(granted)}]; - - if (error) { - [event setValue:[error localizedDescription] forKey:@"error"]; - [event setValue:NUMINTEGER([error code]) forKey:@"code"]; + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler: ^(BOOL granted, NSError *error) { + if (granted == YES) { + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithArray:nativeCategories]]; } - [self fireEvent:@"usernotificationsettings" withObject:event]; - } - }]; -#else - UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types - categories:[NSSet setWithArray:nativeCategories]]; - TiThreadPerformOnMainThread(^{ - [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; - }, NO); + if ([self _hasListeners:@"usernotificationsettings"]) { + NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{@"success": NUMBOOL(granted)}]; + + if (error) { + [event setValue:[error localizedDescription] forKey:@"error"]; + [event setValue:NUMINTEGER([error code]) forKey:@"code"]; + } + + [self fireEvent:@"usernotificationsettings" withObject:event]; + } + }]; #endif + } else { + UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types + categories:[NSSet setWithArray:nativeCategories]]; + TiThreadPerformOnMainThread(^{ + [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; + }, NO); + } } -(id)createUserNotificationAction:(id)args @@ -470,8 +472,8 @@ -(NSDictionary*)currentUserNotificationSettings #if IS_XCODE_8 DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; +#endif } else { -#else __block NSDictionary* returnVal = nil; TiThreadPerformOnMainThread(^{ UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; @@ -479,7 +481,6 @@ -(NSDictionary*)currentUserNotificationSettings }, YES); return [returnVal autorelease]; -#endif } } @@ -536,7 +537,6 @@ -(id)scheduleLocalNotification:(id)args id alertTitle = [args objectForKey:@"alertTitle"]; id alertSubtitle = [args objectForKey:@"alertSubtitle"]; id alertBody = [args objectForKey:@"alertBody"]; - id alertAction = [args objectForKey:@"alertAction"]; id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; id badge = [args objectForKey:@"badge"]; id category = [args objectForKey:@"category"]; @@ -544,232 +544,236 @@ -(id)scheduleLocalNotification:(id)args id sound = [args objectForKey:@"sound"]; id attachments = [args objectForKey:@"attachments"]; -#if IS_XCODE_8 - UNNotificationTrigger *trigger; - - if (date) { - NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - - // Per default, use all components and don't repeat - NSCalendarUnit components = NSYearCalendarUnit|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond; + TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + UNNotificationTrigger *trigger; + + if (date) { + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + + // Per default, use all components and don't repeat + NSCalendarUnit components = NSYearCalendarUnit|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond; + + if (repeat != nil) { + if ([repeat isEqual:@"weekly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"daily"]) { + components = NSCalendarUnitDay; + } else if ([repeat isEqual:@"yearly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"monthly"]) { + components = NSCalendarUnitMonth; + } else { + NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); + } + } + + trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components + fromDate:date] + repeats:(repeat != nil)]; + } else if (region) { + BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; + + CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) + radius:radius + identifier:[TiUtils stringValue:@"identifier" + properties:args + def:@"notification"]]; + + trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion + repeats:triggersOnce]; + } else { + DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); + return; + } + + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + + if (alertTitle) { + [content setTitle:[TiUtils stringValue:alertTitle]]; + } + + if (alertSubtitle) { + [content setSubtitle:[TiUtils stringValue:alertSubtitle]]; + } + + if (alertBody) { + [content setBody:[TiUtils stringValue:alertBody]]; + } + + if (alertLaunchImage) { + [content setLaunchImageName:[TiUtils stringValue:alertLaunchImage]]; + } + + if (badge) { + [content setBadge:[TiUtils numberFromObject:badge]]; + } + + if (userInfo) { + [content setUserInfo:userInfo]; + } + + if (attachments) { + NSMutableArray *_attachments = [NSMutableArray arrayWithCapacity:[attachments count]]; + for (id attachment in attachments) { + NSString *_identifier; + NSString *_url; + NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} + NSError *error = nil; + + ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); + ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); + ENSURE_ARG_OR_NIL_FOR_KEY(_options, attachment, @"options", NSDictionary); + + UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier + URL:[TiUtils toURL:_url proxy:self] + options:_options + error:&error]; + if (error != nil) { + NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); + } else { + [_attachments addObject:_attachment]; + } + } + [content setAttachments:_attachments]; + } + + if (sound) { + if ([sound isEqual:@"default"]) { + [content setSound:[UNNotificationSound defaultSound]]; + } else { + [content setSound:[UNNotificationSound soundNamed:sound]]; + } + } + + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + [content setCategoryIdentifier:[(TiAppiOSUserNotificationCategoryProxy*)category identifier]]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + [content setCategoryIdentifier:[TiUtils stringValue:category]]; + } + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] + content:content + trigger:trigger]; + + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request + withCompletionHandler:^(NSError *error) { + if (error) { + DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); + } + }]; + }, NO); + + lp.notification = content; + [content release]; + + return lp; +#endif + } else { + UILocalNotification *content = [UILocalNotification new]; + id alertAction = [args objectForKey:@"alertAction"]; + + if (date!=nil) { + content.fireDate = date; + content.timeZone = [NSTimeZone defaultTimeZone]; + } + if (repeat != nil) { if ([repeat isEqual:@"weekly"]) { - components = NSCalendarUnitYear; + content.repeatInterval = NSWeekCalendarUnit; } else if ([repeat isEqual:@"daily"]) { - components = NSCalendarUnitDay; + content.repeatInterval = NSDayCalendarUnit; } else if ([repeat isEqual:@"yearly"]) { - components = NSCalendarUnitYear; + content.repeatInterval = NSYearCalendarUnit; } else if ([repeat isEqual:@"monthly"]) { - components = NSCalendarUnitMonth; - } else { - NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); + content.repeatInterval = NSMonthCalendarUnit; } } - trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components - fromDate:date] - repeats:(repeat != nil)]; - } else if (region) { - BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; - - CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) - radius:radius - identifier:[TiUtils stringValue:@"identifier" - properties:args - def:@"notification"]]; + if (alertBody != nil) { + content.alertBody = alertBody; + } + + if (alertTitle != nil && [TiUtils isIOS82rGreater]) { + content.alertTitle = alertTitle; + } - trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion - repeats:triggersOnce]; - } else { - DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); - return; - } - - UNMutableNotificationContent *content = [UNMutableNotificationContent new]; - - if (alertTitle) { - [content setTitle:[TiUtils stringValue:alertTitle]]; - } - - if (alertSubtitle) { - [content setSubtitle:[TiUtils stringValue:alertSubtitle]]; - } - - if (alertBody) { - [content setBody:[TiUtils stringValue:alertBody]]; - } - - if (alertLaunchImage) { - [content setLaunchImageName:[TiUtils stringValue:alertLaunchImage]]; - } - - if (badge) { - [content setBadge:[TiUtils numberFromObject:badge]]; - } - - if (userInfo) { - [content setUserInfo:userInfo]; - } - - if (attachments) { - NSMutableArray *_attachments = [NSMutableArray arrayWithCapacity:[attachments count]]; - for (id attachment in attachments) { - NSString *_identifier; - NSString *_url; - NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} - NSError *error = nil; + if (alertAction != nil) { + content.alertAction = alertAction; + } + + if (alertLaunchImage != nil) { + content.alertLaunchImage = alertLaunchImage; + } + + if (badge != nil) { + content.applicationIconBadgeNumber = [TiUtils intValue:badge]; + } + + if (region != nil) { + ENSURE_TYPE(region, NSDictionary); - ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); - ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); - ENSURE_ARG_OR_NIL_FOR_KEY(_options, attachment, @"options", NSDictionary); + BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; + + CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); - UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier - URL:[TiUtils toURL:_url proxy:self] - options:_options - error:&error]; - if (error != nil) { - NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); - RELEASE_TO_NIL(_attachment); - } else { - [_attachments addObject:_attachment]; + if (!CLLocationCoordinate2DIsValid(center)) { + NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); + return; } + + content.region = [[CLCircularRegion alloc] initWithCenter:center + radius:radius + identifier:[TiUtils stringValue:@"identifier" + properties:args + def:@"notification"]]; + + content.regionTriggersOnce = regionTriggersOnce; } - [content setAttachments:_attachments]; - } - - if (sound) { - if ([sound isEqual:@"default"]) { - [content setSound:[UNNotificationSound defaultSound]]; - } else { - [content setSound:[UNNotificationSound soundNamed:sound]]; - } - } - - if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { - [content setCategoryIdentifier:[(TiAppiOSUserNotificationCategoryProxy*)category identifier]]; - } else if (category != nil && [category isKindOfClass:[NSString class]]) { - [content setCategoryIdentifier:[TiUtils stringValue:category]]; - } - - UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] - content:content - trigger:trigger]; - - TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request - withCompletionHandler:^(NSError *error) { - if (error) { - DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); - } - }]; - }, NO); - -#else - UILocalNotification *content = [UILocalNotification new]; - - if (date!=nil) { - content.fireDate = date; - content.timeZone = [NSTimeZone defaultTimeZone]; - } - - if (repeat!=nil) { - if ([repeat isEqual:@"weekly"]) { - content.repeatInterval = NSWeekCalendarUnit; - } - else if ([repeat isEqual:@"daily"]) { - content.repeatInterval = NSDayCalendarUnit; - } - else if ([repeat isEqual:@"yearly"]) { - content.repeatInterval = NSYearCalendarUnit; - } - else if ([repeat isEqual:@"monthly"]) { - content.repeatInterval = NSMonthCalendarUnit; - } - } - - if (alertBody!=nil) { - content.alertBody = alertBody; - } - if (alertTitle!=nil && [TiUtils isIOS82rGreater]) { - content.alertTitle = alertTitle; - } - - if (alertAction!=nil) { - content.alertAction = alertAction; - } + if (sound) { + if ([sound isEqual:@"default"]) { + content.soundName = UILocalNotificationDefaultSoundName; + } else { + content.soundName = sound; + } + } - if (alertLaunchImage!=nil) { - content.alertLaunchImage = alertLaunchImage; - } + if (userInfo) { + content.userInfo = userInfo; + } - if (badge!=nil) { - content.applicationIconBadgeNumber = [TiUtils intValue:badge]; - } - - if (region!=nil) { - ENSURE_TYPE(region, NSDictionary); + if ([TiUtils isIOS8OrGreater]) { + id category = [args objectForKey:@"category"]; + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + content.category = [(TiAppiOSUserNotificationCategoryProxy*)category identifier]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + content.category = category; + } + } - BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; - - CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); + TiThreadPerformOnMainThread(^{ + if (date != nil || region != nil) { + [[UIApplication sharedApplication] scheduleLocalNotification:content]; + } else { + [[UIApplication sharedApplication] presentLocalNotificationNow:content]; + } + }, NO); - if (!CLLocationCoordinate2DIsValid(center)) { - NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); - return; - } + lp.notification = content; + [content release]; - content.region = [[CLCircularRegion alloc] initWithCenter:center - radius:radius - identifier:[TiUtils stringValue:@"identifier" - properties:args - def:@"notification"]]; - - content.regionTriggersOnce = regionTriggersOnce; - } - - if (sound) { - if ([sound isEqual:@"default"]) { - content.soundName = UILocalNotificationDefaultSoundName; - } else { - content.soundName = sound; - } - } - - if (userInfo) { - content.userInfo = userInfo; - } - - if ([TiUtils isIOS8OrGreater]) { - id category = [args objectForKey:@"category"]; - if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { - content.category = [(TiAppiOSUserNotificationCategoryProxy*)category identifier]; - } else if (category != nil && [category isKindOfClass:[NSString class]]) { - content.category = category; - } - } - - TiThreadPerformOnMainThread(^{ - if (date != nil || region != nil) { - [[UIApplication sharedApplication] scheduleLocalNotification:content]; - } else { - [[UIApplication sharedApplication] presentLocalNotificationNow:content]; - } - }, NO); -#endif - - TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - lp.notification = content; - - [content release]; - return lp; + return lp; + } } -(void)cancelAllLocalNotifications:(id)unused @@ -781,11 +785,9 @@ -(void)cancelAllLocalNotifications:(id)unused if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removeAllPendingNotifications in iOS 10 and later."); - return; +#endif } else { -#else [[UIApplication sharedApplication] cancelAllLocalNotifications]; -#endif } } @@ -799,9 +801,8 @@ -(void)cancelLocalNotification:(id)args if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers in iOS 10 and later."); - return; +#endif } else { -#else NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; if (notifications!=nil) { @@ -814,7 +815,6 @@ -(void)cancelLocalNotification:(id)args } } } -#endif } } @@ -957,10 +957,9 @@ -(NSNumber*)USER_NOTIFICATION_TYPE_NONE if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionNone); -#else +#endif } else if ([TiUtils isIOS8OrGreater]) { return NUMINT(UIUserNotificationTypeNone); -#endif } return NUMINT(0); } @@ -970,10 +969,9 @@ -(NSNumber*)USER_NOTIFICATION_TYPE_BADGE if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionBadge); +#endif } else if ([TiUtils isIOS8OrGreater]) { -#else return NUMINT(UIUserNotificationTypeBadge); -#endif } return NUMINT(0); } @@ -983,10 +981,9 @@ -(NSNumber*)USER_NOTIFICATION_TYPE_SOUND if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionSound); +#endif } else if ([TiUtils isIOS8OrGreater]) { -#else return NUMINT(UIUserNotificationTypeSound); -#endif } return NUMINT(0); } @@ -996,35 +993,42 @@ -(NSNumber*)USER_NOTIFICATION_TYPE_ALERT if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionAlert); +#endif } else if ([TiUtils isIOS8OrGreater]) { -#else return NUMINT(UIUserNotificationTypeAlert); -#endif } return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_TYPE_CAR_PLAY { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionCarPlay); - } #endif + } return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND { - if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationActivationModeBackground); - } - return NUMINT(0); + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + return NUMINT(UNNotificationActionOptionNone); +#endif + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationActivationModeBackground); + } + return NUMINT(0); } -(NSNumber*)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND { - if ([TiUtils isIOS8OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + return NUMINT(UNNotificationActionOptionForeground); +#endif + } else if ([TiUtils isIOS8OrGreater]) { return NUMINT(UIUserNotificationActivationModeForeground); } return NUMINT(0); diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 151d251fcc6..280849dc033 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -57,11 +57,11 @@ -(void)_initWithProperties:(NSDictionary *)properties [super _initWithProperties:properties]; return; + } else { + _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier + title:title + options:[TiUtils intValue:activationMode]] retain]; } - - _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier - title:title - options:[TiUtils intValue:activationMode]] retain]; #endif } else { _notificationAction = [[UIMutableUserNotificationAction new] retain]; @@ -71,16 +71,14 @@ -(void)_initWithProperties:(NSDictionary *)properties [super _initWithProperties:properties]; } --(id) notificationAction +- (id)notificationAction { return _notificationAction; } #pragma mark Public API's -#if IS_XCODE_8 - // The iOS 10 API's are creation-only, so there are no proxy setters -#else +#if !defined(IS_XCODE_8) - (void)setIdentifier:(id)value { [[self notificationAction] setIdentifier:value]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index addde073f52..242dc3ceda5 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -12,18 +12,11 @@ #endif @interface TiAppiOSUserNotificationCategoryProxy : TiProxy -{ - -} @property (nonatomic,retain) id notificationCategory; @property (nonatomic,readonly) NSString *identifier; -#if IS_XCODE_8 -- (UNNotificationCategory*)notificationCategory; -#else -- (UIMutableUserNotificationCategory*)notificationCategory; -#endif +- (id)notificationCategory; @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 5e0cbe61ac7..5e182ae2e0b 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -50,9 +50,6 @@ -(void)_initWithProperties:(NSDictionary *)properties if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - RELEASE_TO_NIL(minimalActions); - RELEASE_TO_NIL(actionsForMinimalContext); - _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier actions:defaultActions intentIdentifiers:intentIdentifiers @@ -60,10 +57,14 @@ -(void)_initWithProperties:(NSDictionary *)properties #endif } else { _notificationCategory = [UIMutableUserNotificationCategory new]; + [_notificationCategory setIdentifier:identifier]; [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; } + + RELEASE_TO_NIL(minimalActions); + RELEASE_TO_NIL(defaultActions); } [super _initWithProperties:properties]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index 89dd35e69ba..20b1e4694f6 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -18,15 +18,11 @@ - (void)getDeliveredNotifications:(id)args; -- (void)removePendingNotificationsWithIdentifiers:(id)args; +- (void)removePendingNotifications:(id)args; -- (void)removeDeliveredNotificationsWithIdentifiers:(id)args; - -- (void)removeAllPendingNotifications:(id)unused; - -- (void)removeAllDeliveredNotifications:(id)unused; +- (void)removeDeliveredNotifications:(id)args; - (void)requestUserNotificationSettings:(id)args; @end -#endif \ No newline at end of file +#endif diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index f2a0ff415f1..72c31c09851 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -9,6 +9,7 @@ #import "TiAppiOSUserNotificationCenterProxy.h" #import "TiAppiOSUserNotificationCategoryProxy.h" #import "TiAppiOSLocalNotificationProxy.h" +#import #define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) @@ -36,7 +37,7 @@ - (void)getPendingNotifications:(id)args [callback call:invocationArray thisObject:self]; [invocationArray release]; }]; -#else +#endif } else { NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; @@ -52,7 +53,6 @@ - (void)getPendingNotifications:(id)args [callback call:invocationArray thisObject:self]; [invocationArray release]; -#endif } } @@ -78,14 +78,13 @@ - (void)getDeliveredNotifications:(id)args [callback call:invocationArray thisObject:self]; [invocationArray release]; }]; -#else +#endif } else { NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); -#endif } } -- (void)removePendingNotificationsWithIdentifiers:(id)args +- (void)removePendingNotifications:(id)args { ENSURE_TYPE(args, NSArray); @@ -93,6 +92,11 @@ - (void)removePendingNotificationsWithIdentifiers:(id)args #if IS_XCODE_8 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; TiThreadPerformOnMainThread(^{ + if ([args count] == 0) { + [center removeAllPendingNotificationRequests]; + return; + } + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { // Loop through current notification requests @@ -109,19 +113,23 @@ - (void)removePendingNotificationsWithIdentifiers:(id)args } }]; }, NO); -#else +#endif } else { TiThreadPerformOnMainThread(^{ + if ([args count] == 0) { + [[UIApplication sharedApplication] cancelAllLocalNotifications]; + return; + } + for (id notification in args) { ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); [[UIApplication sharedApplication] cancelLocalNotification:[(TiAppiOSLocalNotificationProxy*)notification notification]]; } }, NO); -#endif } } -- (void)removeDeliveredNotificationsWithIdentifiers:(id)args +- (void)removeDeliveredNotifications:(id)args { ENSURE_TYPE(args, NSArray); @@ -129,6 +137,12 @@ - (void)removeDeliveredNotificationsWithIdentifiers:(id)args #if IS_XCODE_8 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; TiThreadPerformOnMainThread(^{ + + if ([args count] == 0) { + [center removeAllDeliveredNotifications]; + return; + } + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { // Loop through current notification requests @@ -145,34 +159,9 @@ - (void)removeDeliveredNotificationsWithIdentifiers:(id)args } }]; }, NO); -#else - } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotificationsWithIdentifiers is not avaible in iOS < 10."); #endif - } -} - -- (void)removeAllPendingNotifications:(id)unused -{ - if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; -#else } else { - [[UIApplication sharedApplication] cancelAllLocalNotifications]; -#endif - } -} - -- (void)removeAllDeliveredNotifications:(id)unused -{ - if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; -#else - } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeAllDeliveredNotifications is not avaible in iOS < 10."); -#endif + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only avaible in iOS 10 and later."); } } @@ -183,35 +172,36 @@ - (void)requestUserNotificationSettings:(id)args KrollCallback *callback = [args objectAtIndex:0]; + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { - NSDictionary * propertiesDict = @{ - @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), - @"soundSetting": NUMINTEGER([settings soundSetting]), - @"badgeSetting": NUMINTEGER([settings badgeSetting]), - @"alertSetting": NUMINTEGER([settings alertSetting]), - @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), - @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), - @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), - @"alertStyle": NUMINTEGER([settings alertStyle]) - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; -#else - __block NSDictionary* returnVal = nil; - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - - NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }, YES); + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + NSDictionary * propertiesDict = @{ + @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), + @"soundSetting": NUMINTEGER([settings soundSetting]), + @"badgeSetting": NUMINTEGER([settings badgeSetting]), + @"alertSetting": NUMINTEGER([settings alertSetting]), + @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), + @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), + @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), + @"alertStyle": NUMINTEGER([settings alertStyle]) + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; #endif + } else { + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + + NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }, YES); + } } #pragma mark Utilities @@ -232,6 +222,20 @@ - (NSDictionary*)dictionaryWithUserNotificationRequest:(UNNotificationRequest*)r [event setObject:NOTNIL([[request content] categoryIdentifier]) forKey:@"category"]; [event setObject:NOTNIL([request identifier]) forKey:@"identifier"]; + if ([[request trigger] isKindOfClass:[UNCalendarNotificationTrigger class]]) { + [event setObject:NOTNIL([(UNCalendarNotificationTrigger*)[request trigger] nextTriggerDate]) forKey:@"date"]; + } else if ([[request trigger] isKindOfClass:[UNLocationNotificationTrigger class]]) { + CLCircularRegion *region = (CLCircularRegion*)[(UNLocationNotificationTrigger*)[request trigger] region]; + + NSDictionary *dict = @{ + @"latitude": NUMDOUBLE(region.center.latitude), + @"longitude": NUMDOUBLE(region.center.longitude), + @"radius": NUMDOUBLE(region.radius), + @"identifier": region.identifier + }; + [event setObject:dict forKey:@"region"]; + } + return event; } #endif @@ -272,10 +276,11 @@ -(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)noti categoryProxy.notificationCategory = cat; [categoriesArray addObject:categoryProxy]; } - return [NSDictionary dictionaryWithObjectsAndKeys: - typesArray, @"types", - categoriesArray, @"categories", - nil]; + + return @{ + @"types": typesArray, + @"categories": categoriesArray + }; } @end From 39ca685e0fe4ca7617595c692de08b245c307e10 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Fri, 22 Jul 2016 21:20:19 +0200 Subject: [PATCH 16/44] [TIMOB-23527] Add NotificationCenter documentation --- .../Titanium/App/iOS/NotificationCenter.yml | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 apidoc/Titanium/App/iOS/NotificationCenter.yml diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml new file mode 100644 index 00000000000..c6580951936 --- /dev/null +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -0,0 +1,209 @@ +--- +name: Titanium.App.iOS.NotificationCenter +summary: | + The top-level App iOS Notification Center module, available only to iOS devices running iOS 8 or later. It is + used to control scheduled notifications and receive details about the system-wide notification settings. + +extends: Titanium.Module +platforms: [iphone, ipad] +osver: {ios: {min: "8.0"}} +since: "6.0.0" + +methods: + - name: getPendingNotifications + summary: Fetches the pending notifications asynchronously. + parameters: + - name: callback + summary: | + The function that is being called after the notifications + have been fetched. + type: Callback + since: "6.0.0" + + - name: getDeliveredNotifications + summary: Fetches the delivered notifications asynchronously. + parameters: + - name: callback + summary: | + The function that is being called after the notifications + have been fetched. + type: Callback + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: removePendingNotifications + summary: | + Removes the specified pending notifications to prevent them from being triggered. + If no notifications are specified, all pending notifications will be removed. + since: "6.0.0" + + - name: removeDeliveredNotifications + summary: | + Removes the specified delivered notifications from the notification-center. + If no notifications are specified, all delivered notifications will be removed. + osver: {ios: {min: "10.0"}} + since: "6.0.0" + + - name: requestUserNotificationSettings + summary: | + Notification types and user notification categories the application is registered to use + (available on iOS 8 and later). + type: UserNotificationSettings + since: "6.0.0" + +--- +name: UserNotificationCallbackResponse +summary: | + Response when receiving pending or local notifications + in and + . +since: "6.0.0" +properties: + - name: notifications + type: Array + summary: An array of identifiers used to create notifications. + +--- +name: UserNotificationDictionary +summary: | + Dictionary of notification data used in the array of `notifications` + when receiving pending or local notifications in + and + . +since: "6.0.0" +properties: + - name: alertTitle + summary: Title of the notification. + type: String + osver: {ios: {min: "8.2"}} + + - name: alertSubtitle + summary: Subtitle of the notification. + type: String + osver: {ios: {min: "10.0"}} + + - name: alertAction + summary: | + Alert button text ('View', by default) or slider text ('slide to unlock...', by default). + type: String + + - name: alertBody + summary: Alert message. + type: String + + - name: alertLaunchImage + summary: Image displayed instead of `Default.png` when launching the application. + type: String + + - name: badge + summary: Application badge value. + type: Number + + - name: date + summary: Date and time when the notification was configured to fire. + type: Date + + - name: sound + summary: Path to the sound file configured to play when the notification was fired. + type: String + + - name: timezone + summary: Timezone of the date when the notification was configured to fire. + type: String + + - name: userInfo + summary: Custom data object. + type: Dictionary + + - name: category + summary: Category identifier of the notification. + type: String + osver: {ios: {min: "8.0"}} + + - name: identifier + summary: Request identifier of the notification. + type: String + osver: {ios: {min: "10.0"}} + + - name: region + summary: Region of the notification. + description: | + The following keys are included: + - latitude: The latitude of the region. + - longitude: The longitude of the region. + - radius: The radius of the region. + - identifier: The identifier of the region. + type: Dictionary + osver: {ios: {min: "10.0"}} + +--- +name: UserNotificationSettings +summary: | + Dictionary object of parameters used to register the application with local notifications using + the method. +platforms: [iphone, ipad] + +properties: + + - name: types + summary: Notification types to use. + description: | + Only available in iOS < 10. iOS 10 and later returns notification settings more detailed, + check the other attributes for more information. + type: Array + constants: Titanium.App.iOS.USER_NOTIFICATION_TYPE_* + + - name: categories + summary: Set of categories of user notification actions required by the applicaiton to use. + type: Array + description: | + Only available in iOS < 10. iOS 10 and later returns notification settings more detailed, + check the other attributes for more information. + + - name: authorizationStatus + summary: The current authorization status for using notifications. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_AUTHORIZATION_STATUS_*] + osver: {ios: {min: "10.0"}} + + - name: soundSetting + summary: The current sound settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: badgeSetting + summary: The current badge settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: alertSetting + summary: The current alert settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: notificationCenterSetting + summary: The current notication-center settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: lockScreenSetting + summary: The current lock-screen settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: carPlaySetting + summary: The current CarPlay settings. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + osver: {ios: {min: "10.0"}} + + - name: alertStyle + summary: The current alert style used to display notifications. + type: Number + constants: [Ti.App.iOS.USER_NOTIFICATION_ALERT_STYLE_*] + osver: {ios: {min: "10.0"}} From fc8ed0d03505e8864bd64c5327c078606c40880f Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Sat, 23 Jul 2016 22:16:42 +0200 Subject: [PATCH 17/44] [TIMOB-23527] Add SDK-side support for extensions --- iphone/Classes/TiApp.m | 48 +++++++++++++++++++++++++++++----- iphone/Classes/TiAppiOSProxy.m | 10 ++++++- iphone/Classes/TiBase.h | 1 + iphone/Classes/TiBase.m | 1 + 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 1c524762649..46f602af0f0 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -53,8 +53,34 @@ - (void)checkBackgroundServices; - (void)appBoot; @end -@implementation TiApp +#if IS_XCODE_8 +@interface TiUserNotificationExtention : UNNotificationServiceExtension + +@end + +@implementation TiUserNotificationExtention + +-(void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler +{ + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[[request content] userInfo]]; + UNMutableNotificationContent *content = [(UNMutableNotificationContent*)[request content] copy]; + + [userInfo setObject:@YES forKey:@"isRemoteNotification"]; + [content setUserInfo:userInfo]; + + contentHandler(content); + RELEASE_TO_NIL(content); +} +-(void)serviceExtensionTimeWillExpire +{ + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:@{} userInfo:nil]; +} + +@end +#endif + +@implementation TiApp -(void)clearMemoryPanic { @@ -505,14 +531,22 @@ -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotif [event autorelease]; completionHandler();*/ - // TODO: See if notification is local or remote - + // TODO: Find out where the payload is stored to handle the above - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithUserNotification:response.notification - withIdentifier:response.actionIdentifier] retain]; + if ([[[[[response notification] request] content] userInfo] valueForKey:@"isRemoteNotification"] != nil) { + RELEASE_TO_NIL(remoteNotification); + remoteNotification = [[[self class] dictionaryWithUserNotification:response.notification + withIdentifier:response.actionIdentifier] retain]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:remoteNotification userInfo:nil]; + } else { + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithUserNotification:response.notification + withIdentifier:response.actionIdentifier] retain]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; + } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; completionHandler(); } #endif diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 8e253ffd23f..19fe934a87f 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -56,7 +56,9 @@ -(void)_listenerAdded:(NSString*)type count:(int)count if (count == 1 && [type isEqual:@"remotenotificationaction"]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveRemoteNotificationAction:) name:kTiRemoteNotificationAction object:nil]; } - + if (count == 1 && [type isEqual:@"remoteextentionwillexpire"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteExtensionWillExpire:) name:kTiRemoteExtentionWillExpire object:nil]; + } if ((count == 1) && [type isEqual:@"backgroundfetch"]) { NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; if ([backgroundModes containsObject:@"fetch"]) { @@ -842,6 +844,12 @@ -(void)didReceiveRemoteNotificationAction:(NSNotification*)note [self fireEvent:@"remotenotificationaction" withObject:notification]; } +-(void)remoteExtensionWillExpire:(NSNotification*)note +{ + NSDictionary *notification = [note object]; + [self fireEvent:@"remoteextentionwillexpire" withObject:notification]; +} + -(void)didReceiveBackgroundFetchNotification:(NSNotification*)note { [self fireEvent:@"backgroundfetch" withObject:[note userInfo]]; diff --git a/iphone/Classes/TiBase.h b/iphone/Classes/TiBase.h index 34b9ac4a839..add694f24ce 100644 --- a/iphone/Classes/TiBase.h +++ b/iphone/Classes/TiBase.h @@ -586,6 +586,7 @@ extern NSString * const kTiFrameAdjustNotification; extern NSString * const kTiLocalNotification; extern NSString * const kTiLocalNotificationAction; extern NSString * const kTiRemoteNotificationAction; +extern NSString * const kTiRemoteExtentionWillExpire; extern NSString * const kTiUserNotificationSettingsNotification; extern NSString * const kTiBackgroundTransfer; extern NSString * const kTiURLDownloadFinished; diff --git a/iphone/Classes/TiBase.m b/iphone/Classes/TiBase.m index ad0152ac68c..47392dc1634 100644 --- a/iphone/Classes/TiBase.m +++ b/iphone/Classes/TiBase.m @@ -161,6 +161,7 @@ void TiLogMessage(NSString* str, ...) { NSString * const kTiLocalNotification = @"TiLocalNotification"; NSString * const kTiLocalNotificationAction = @"TiLocalNotificationAction"; NSString * const kTiRemoteNotificationAction = @"TiRemoteNotificationAction"; +NSString * const kTiRemoteExtentionWillExpire = @"remoteextentionwillexpire"; NSString * const kTiUserNotificationSettingsNotification = @"TiUserNotificationSettingsNotification"; NSString * const kTiWatchKitExtensionRequest = @"TiWatchKitExtensionRequest"; NSString * const kTiContinueActivity = @"TiContinueActivity"; From 33d22df9575f477d0c95d54c8e15578149675de9 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Sat, 23 Jul 2016 22:26:41 +0200 Subject: [PATCH 18/44] [TIMOB-23527] Fix threading issues --- .../TiAppiOSUserNotificationCenterProxy.m | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 72c31c09851..c31a172ad05 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -22,21 +22,23 @@ - (void)getPendingNotifications:(id)args if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[self dictionaryWithUserNotificationRequest:request]]; - } - - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; + }, NO); #endif } else { NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; @@ -63,21 +65,23 @@ - (void)getDeliveredNotifications:(id)args KrollCallback *callback = nil; ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); - [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[self dictionaryWithUserNotificationRequest:request]]; - } - - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; + } + + NSDictionary * propertiesDict = @{ + @"notifications": result + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; + }, NO); #endif } else { NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); @@ -135,8 +139,8 @@ - (void)removeDeliveredNotifications:(id)args if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; TiThreadPerformOnMainThread(^{ + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; if ([args count] == 0) { [center removeAllDeliveredNotifications]; @@ -174,22 +178,24 @@ - (void)requestUserNotificationSettings:(id)args if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { - NSDictionary * propertiesDict = @{ - @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), - @"soundSetting": NUMINTEGER([settings soundSetting]), - @"badgeSetting": NUMINTEGER([settings badgeSetting]), - @"alertSetting": NUMINTEGER([settings alertSetting]), - @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), - @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), - @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), - @"alertStyle": NUMINTEGER([settings alertStyle]) - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + NSDictionary * propertiesDict = @{ + @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), + @"soundSetting": NUMINTEGER([settings soundSetting]), + @"badgeSetting": NUMINTEGER([settings badgeSetting]), + @"alertSetting": NUMINTEGER([settings alertSetting]), + @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), + @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), + @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), + @"alertStyle": NUMINTEGER([settings alertStyle]) + }; + NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; + }, NO); #endif } else { TiThreadPerformOnMainThread(^{ From 716449b2fe6d366e6867c24f73392ac7601ca413 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Sat, 27 Aug 2016 17:52:00 +0200 Subject: [PATCH 19/44] [TIMOB-23527] Fix nil-crash, update more docs --- apidoc/Titanium/App/iOS/UserNotificationCategory.yml | 2 ++ iphone/Classes/TiAppiOSProxy.m | 6 ++---- iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m | 10 +++++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apidoc/Titanium/App/iOS/UserNotificationCategory.yml b/apidoc/Titanium/App/iOS/UserNotificationCategory.yml index c42ff4040d5..1e8837d9361 100644 --- a/apidoc/Titanium/App/iOS/UserNotificationCategory.yml +++ b/apidoc/Titanium/App/iOS/UserNotificationCategory.yml @@ -36,8 +36,10 @@ properties: summary: Array of notification actions to display for non-dialog-style notification. description: | If not specified, the first two actions from `actionsForDefaultContent` are displayed. + Note: This property has been removed in iOS 10 and iOS will handle the actions internally. type: Array accessors: false + osver: {ios: {max: 9.3}} availability: creation - name: identifier diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 19fe934a87f..1a9b8f9f9f5 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -583,9 +583,7 @@ -(id)scheduleLocalNotification:(id)args CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) radius:radius - identifier:[TiUtils stringValue:@"identifier" - properties:args - def:@"notification"]]; + identifier:[TiUtils stringValue:@"identifier"] ?: @"notification"]; trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion repeats:triggersOnce]; @@ -659,7 +657,7 @@ -(id)scheduleLocalNotification:(id)args [content setCategoryIdentifier:[TiUtils stringValue:category]]; } - UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] ?: @"notification" content:content trigger:trigger]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 5e182ae2e0b..30841153d2a 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -44,15 +44,19 @@ -(void)_initWithProperties:(NSDictionary *)properties [minimalActions addObject:[action notificationAction]]; } - if (!intentIdentifiers) { - intentIdentifiers = @[]; + if (intentIdentifiers) { + for (id itentIdentifier in intentIdentifiers) { + if (![itentIdentifier isKindOfClass:[NSString class]]) { + NSLog(@"[ERROR] All elements in itentIdentifiers must be a String, \"%@\" is not!", itentIdentifier); + } + } } if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier actions:defaultActions - intentIdentifiers:intentIdentifiers + intentIdentifiers:intentIdentifiers ?: @[] options:UNNotificationCategoryOptionCustomDismissAction] retain]; #endif } else { From ce4d71cba4ab193157a5ec25b48fa01feb785b68 Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Sat, 27 Aug 2016 18:12:07 +0200 Subject: [PATCH 20/44] [TIMOB-23527] Fix all memory-leaks in new proxies --- iphone/Classes/TiAppiOSProxy.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 1a9b8f9f9f5..2b66c4af8be 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -191,6 +191,7 @@ -(void)didReceiveApplicationShortcutNotification:(NSNotification*)info } [self fireEvent:@"shortcutitemclick" withObject:event]; + RELEASE_TO_NIL(event); } #ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER @@ -575,6 +576,7 @@ -(id)scheduleLocalNotification:(id)args trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components fromDate:date] repeats:(repeat != nil)]; + RELEASE_TO_NIL(calendar); } else if (region) { BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; @@ -587,6 +589,7 @@ -(id)scheduleLocalNotification:(id)args trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion repeats:triggersOnce]; + RELEASE_TO_NIL(circularRegion); } else { DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); return; @@ -728,14 +731,15 @@ -(id)scheduleLocalNotification:(id)args if (!CLLocationCoordinate2DIsValid(center)) { NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); + RELEASE_TO_NIL(content); return; } - content.region = [[CLCircularRegion alloc] initWithCenter:center + content.region = [[[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:[TiUtils stringValue:@"identifier" properties:args - def:@"notification"]]; + def:@"notification"]] autorelease]; content.regionTriggersOnce = regionTriggersOnce; } From cd218588cab0eea0f31b465d13d8f2462d7e2aab Mon Sep 17 00:00:00 2001 From: Hans Knoechel Date: Sat, 27 Aug 2016 19:15:38 +0200 Subject: [PATCH 21/44] [TIMOB-23527] Fix possible iOS < 10 leaks --- iphone/Classes/TiAppiOSProxy.m | 17 ++++++++--------- .../TiAppiOSUserNotificationActionProxy.m | 18 +++++++++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 2b66c4af8be..e8deeb14106 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -350,15 +350,13 @@ -(void)registerUserNotificationSettings:(id)args } } - NSUInteger types; + NSUInteger types = UIUserNotificationTypeNone; - if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { types = UNAuthorizationOptionNone; -#endif - } else { - types = UIUserNotificationTypeNone; } +#endif if (typesRequested != nil) { for (id thisTypeRequested in typesRequested) @@ -533,24 +531,25 @@ -(id)scheduleLocalNotification:(id)args { ENSURE_SINGLE_ARG(args,NSDictionary); - id identifier = [args objectForKey:@"identifier"]; id repeat = [args objectForKey:@"repeat"]; id date = [args objectForKey:@"date"]; id region = [args objectForKey:@"region"]; id alertTitle = [args objectForKey:@"alertTitle"]; - id alertSubtitle = [args objectForKey:@"alertSubtitle"]; id alertBody = [args objectForKey:@"alertBody"]; id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; id badge = [args objectForKey:@"badge"]; - id category = [args objectForKey:@"category"]; id userInfo = [args objectForKey:@"userInfo"]; id sound = [args objectForKey:@"sound"]; - id attachments = [args objectForKey:@"attachments"]; TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 + id identifier = [args objectForKey:@"identifier"]; + id alertSubtitle = [args objectForKey:@"alertSubtitle"]; + id category = [args objectForKey:@"category"]; + id attachments = [args objectForKey:@"attachments"]; + UNNotificationTrigger *trigger; if (date) { diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 280849dc033..bcf4ba34ee8 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -27,17 +27,17 @@ -(void)_initWithProperties:(NSDictionary *)properties { if (_notificationAction == nil) { - id identifier = [properties valueForKey:@"identifier"]; - id title = [properties valueForKey:@"title"]; - id activationMode = [properties valueForKey:@"activationMode"]; - id authenticationRequired = [properties valueForKey:@"authenticationRequired"]; - id destructive = [properties valueForKey:@"destructive"]; - id behavior = [properties valueForKey:@"behavior"]; - id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; - id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; - if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 + id identifier = [properties valueForKey:@"identifier"]; + id title = [properties valueForKey:@"title"]; + id activationMode = [properties valueForKey:@"activationMode"]; + id authenticationRequired = [properties valueForKey:@"authenticationRequired"]; + id destructive = [properties valueForKey:@"destructive"]; + id behavior = [properties valueForKey:@"behavior"]; + id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; + id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; + UNNotificationActionOptions options = UNNotificationActionOptionNone; if (destructive) { From 3aad1d24253b3f13ade91d36a99836553492be7c Mon Sep 17 00:00:00 2001 From: hansemannn Date: Mon, 3 Oct 2016 16:14:04 +0200 Subject: [PATCH 22/44] [TIMOB-23527] Update docs to 6.1.0 --- .../Titanium/App/iOS/NotificationCenter.yml | 17 +++++----- apidoc/Titanium/App/iOS/iOS.yml | 32 +++++++++---------- .../Classes/TiAppiOSLocalNotificationProxy.m | 2 +- iphone/Classes/TiAppiOSProxy.m | 6 ++-- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index c6580951936..1f3f1981cd0 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -7,7 +7,7 @@ summary: | extends: Titanium.Module platforms: [iphone, ipad] osver: {ios: {min: "8.0"}} -since: "6.0.0" +since: "6.1.0" methods: - name: getPendingNotifications @@ -18,7 +18,7 @@ methods: The function that is being called after the notifications have been fetched. type: Callback - since: "6.0.0" + since: "6.1.0" - name: getDeliveredNotifications summary: Fetches the delivered notifications asynchronously. @@ -29,27 +29,27 @@ methods: have been fetched. type: Callback osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: removePendingNotifications summary: | Removes the specified pending notifications to prevent them from being triggered. If no notifications are specified, all pending notifications will be removed. - since: "6.0.0" + since: "6.1.0" - name: removeDeliveredNotifications summary: | Removes the specified delivered notifications from the notification-center. If no notifications are specified, all delivered notifications will be removed. osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: requestUserNotificationSettings summary: | Notification types and user notification categories the application is registered to use (available on iOS 8 and later). type: UserNotificationSettings - since: "6.0.0" + since: "6.1.0" --- name: UserNotificationCallbackResponse @@ -57,7 +57,7 @@ summary: | Response when receiving pending or local notifications in and . -since: "6.0.0" +since: "6.1.0" properties: - name: notifications type: Array @@ -70,7 +70,7 @@ summary: | when receiving pending or local notifications in and . -since: "6.0.0" +since: "6.1.0" properties: - name: alertTitle summary: Title of the notification. @@ -144,7 +144,6 @@ summary: | platforms: [iphone, ipad] properties: - - name: types summary: Notification types to use. description: | diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index 6d2a9802f16..c3859ca1f88 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -319,7 +319,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED summary: The application is authorized to post user notifications. @@ -329,7 +329,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED summary: The application is not authorized to post user notifications. @@ -339,7 +339,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_SETTING_NOT_SUPPORTED summary: The application does not support this notification type. @@ -349,7 +349,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_SETTING_ENABLED summary: The notification setting is turned on. @@ -359,7 +359,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_SETTING_DISABLED summary: The notification setting is turned off. @@ -369,7 +369,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_NONE summary: No banner or alert dialog is presented when the notification is received. @@ -379,7 +379,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_ALERT summary: A alert dialog is presented when the notification is received. @@ -389,7 +389,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_BANNER summary: A banner is presented when the notification is received. @@ -399,7 +399,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: UTTYPE_TEXT summary: | @@ -669,7 +669,7 @@ properties: type: UserNotificationSettings permission: read-only deprecated: - since: "6.0.0" + since: "6.1.0" notes: Use instead. osver: {ios: {min: "8.0"}} since: "3.4.0" @@ -1205,7 +1205,7 @@ properties: summary: The notification identifier. description: This property is required in iOS 10 and later. optional: false - since: "6.0.0" + since: "6.1.0" - name: alertAction summary: | @@ -1224,14 +1224,14 @@ properties: type: String optional: true osver: {ios: {min: "8.2"}} - since: "6.0.0" + since: "6.1.0" - name: alertSubtitle summary: Alert subtitle to display. type: String optional: true osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: alertLaunchImage summary: Image to display instead of `Default.png` when launching the application. @@ -1243,7 +1243,7 @@ properties: type: Array optional: true osver: {ios: {min: "10.0"}} - since: "6.0.0" + since: "6.1.0" - name: badge summary: Application badge value. @@ -1293,7 +1293,7 @@ properties: type: Dictionary optional: true osver: {ios: {min: "8.0"}} - since: "6.0.0" + since: "6.1.0" --- name: UserNotificationAttachment @@ -1301,7 +1301,7 @@ summary: | Provide at least the property `identifier` and `url` property to identify a local image, sound or video. If your media is invalid, the API will throw an error log and skip the invalid attachment. -since: "6.0.0" +since: "6.1.0" platforms: [iphone, ipad] osver: {ios: {min: "10.0"}} diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index ee93b3f6a80..82e609e8055 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -26,7 +26,7 @@ -(NSString*)apiName -(void)cancel:(id)unused { - DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.0.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index e8deeb14106..a0f31ab694b 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -467,7 +467,7 @@ -(NSDictionary*)currentUserNotificationSettings return nil; } - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.0.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 @@ -783,7 +783,7 @@ -(void)cancelAllLocalNotifications:(id)unused { ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); - DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.0.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); + DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 @@ -799,7 +799,7 @@ -(void)cancelLocalNotification:(id)args ENSURE_SINGLE_ARG(args,NSObject); ENSURE_UI_THREAD(cancelLocalNotification,args); - DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.0.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 From 1abff96b731e99133448f3f21d4c22df1648a291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 09:22:12 +0100 Subject: [PATCH 23/44] First stage of linting --- iphone/Classes/TiApp.h | 148 +- iphone/Classes/TiApp.m | 2053 ++++++++--------- .../Classes/TiAppiOSLocalNotificationProxy.h | 9 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 37 +- iphone/Classes/TiAppiOSProxy.h | 8 +- iphone/Classes/TiAppiOSProxy.m | 1907 +++++++-------- .../TiAppiOSUserNotificationActionProxy.h | 3 +- .../TiAppiOSUserNotificationActionProxy.m | 108 +- .../TiAppiOSUserNotificationCategoryProxy.h | 4 +- .../TiAppiOSUserNotificationCategoryProxy.m | 104 +- .../TiAppiOSUserNotificationCenterProxy.h | 2 +- .../TiAppiOSUserNotificationCenterProxy.m | 460 ++-- iphone/Classes/TiUtils.h | 2 +- 13 files changed, 2420 insertions(+), 2425 deletions(-) diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index 468d2da198b..11029092828 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -9,21 +9,21 @@ #if IS_XCODE_8 #import #endif -#import "TiHost.h" #import "KrollBridge.h" +#import "TiHost.h" #ifdef USE_TI_UIWEBVIEW - #import "XHRBridge.h" +#import "XHRBridge.h" #endif #import "TiRootViewController.h" #import "TiToJS.h" extern BOOL applicationInMemoryPanic; -TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on main thread, or else there is a risk of deadlock! +TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on main thread, or else there is a risk of deadlock! { - while (applicationInMemoryPanic) { - [NSThread sleepForTimeInterval:0.01]; - } + while (applicationInMemoryPanic) { + [NSThread sleepForTimeInterval:0.01]; + } } /** @@ -37,41 +37,41 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o @interface TiApp : TiHost #endif { - UIWindow *window; - UIImageView *loadView; - UIImageView *splashScreenImage; - BOOL loaded; - - TiContextGroupRef contextGroup; - KrollBridge *kjsBridge; - + UIWindow *window; + UIImageView *loadView; + UIImageView *splashScreenImage; + BOOL loaded; + + TiContextGroupRef contextGroup; + KrollBridge *kjsBridge; + #ifdef USE_TI_UIWEBVIEW - XHRBridge *xhrBridge; + XHRBridge *xhrBridge; #endif - - NSMutableDictionary *launchOptions; - NSTimeInterval started; - - int32_t networkActivityCount; - - TiRootViewController *controller; - NSString *userAgent; - NSString *remoteDeviceUUID; - - id remoteNotificationDelegate; - NSDictionary* remoteNotification; - NSMutableDictionary* pendingCompletionHandlers; - NSMutableDictionary* pendingReplyHandlers; - NSMutableDictionary* backgroundTransferCompletionHandlers; - BOOL appBooted; - - NSString *sessionId; - - UIBackgroundTaskIdentifier bgTask; - NSMutableArray *backgroundServices; - NSMutableArray *runningServices; - NSDictionary *localNotification; - UIApplicationShortcutItem *launchedShortcutItem; + + NSMutableDictionary *launchOptions; + NSTimeInterval started; + + int32_t networkActivityCount; + + TiRootViewController *controller; + NSString *userAgent; + NSString *remoteDeviceUUID; + + id remoteNotificationDelegate; + NSDictionary *remoteNotification; + NSMutableDictionary *pendingCompletionHandlers; + NSMutableDictionary *pendingReplyHandlers; + NSMutableDictionary *backgroundTransferCompletionHandlers; + BOOL appBooted; + + NSString *sessionId; + + UIBackgroundTaskIdentifier bgTask; + NSMutableArray *backgroundServices; + NSMutableArray *runningServices; + NSDictionary *localNotification; + UIApplicationShortcutItem *launchedShortcutItem; } @property (nonatomic) BOOL forceSplashAsSnapshot; @@ -85,16 +85,15 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o @property (nonatomic, assign) id remoteNotificationDelegate; - -@property (nonatomic, readonly) NSMutableDictionary* pendingCompletionHandlers; -@property (nonatomic, readonly) NSMutableDictionary* backgroundTransferCompletionHandlers; +@property (nonatomic, readonly) NSMutableDictionary *pendingCompletionHandlers; +@property (nonatomic, readonly) NSMutableDictionary *backgroundTransferCompletionHandlers; /** Returns details for the last remote notification. Dictionary containing details about remote notification, or _nil_. */ -@property (nonatomic, readonly) NSDictionary* remoteNotification; +@property (nonatomic, readonly) NSDictionary *remoteNotification; /** Returns local notification that has bees sent on the application. @@ -102,40 +101,40 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o @return Dictionary containing details about local notification, or _nil_. */ -@property (nonatomic, readonly) NSDictionary* localNotification; +@property (nonatomic, readonly) NSDictionary *localNotification; /** Returns the application's root view controller. */ -@property (nonatomic, retain) TiRootViewController* controller; +@property (nonatomic, retain) TiRootViewController *controller; @property (nonatomic, readonly) TiContextGroupRef contextGroup; -@property (nonatomic,readonly) BOOL willTerminate; +@property (nonatomic, readonly) BOOL willTerminate; /** Returns singleton instance of TiApp application object. */ -+(TiApp*)app; ++ (TiApp *)app; /** * Returns a read-only dictionary from tiapp.xml properties */ -+(NSDictionary *)tiAppProperties; ++ (NSDictionary *)tiAppProperties; /* Convenience method to returns root view controller for TiApp instance. @return The application's root view controller. @see controller */ -+(TiRootViewController*)controller; ++ (TiRootViewController *)controller; -+(TiContextGroupRef)contextGroup; ++ (TiContextGroupRef)contextGroup; --(BOOL)windowIsKeyWindow; +- (BOOL)windowIsKeyWindow; --(UIView *) topMostView; +- (UIView *)topMostView; --(void)attachXHRBridgeIfRequired; +- (void)attachXHRBridgeIfRequired; /** Returns application launch options @@ -143,14 +142,14 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o The method provides access to application launch options that became available when application just launched. @return The launch options dictionary. */ --(NSDictionary*)launchOptions; +- (NSDictionary *)launchOptions; /** Returns remote UUID for the current running device. @return Current device UUID. */ --(NSString*)remoteDeviceUUID; +- (NSString *)remoteDeviceUUID; /** Tells application to show network activity indicator. @@ -158,7 +157,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o Every call of startNetwork should be paired with . @see stopNetwork */ --(void)startNetwork; +- (void)startNetwork; /** Tells application to hide network activity indicator. @@ -166,7 +165,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o Every call of stopNetwork should have corresponding call. @see startNetwork */ --(void)stopNetwork; +- (void)stopNetwork; /** Prevents network activity indicator from showing. @@ -177,7 +176,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o */ @property (nonatomic, assign) BOOL disableNetworkActivityIndicator; --(void)showModalError:(NSString*)message; +- (void)showModalError:(NSString *)message; /** Tells application to display modal view controller. @@ -185,7 +184,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o @param controller The view controller to display. @param animated If _YES_, animates the view controller as it’s presented; otherwise, does not. */ --(void)showModalController:(UIViewController*)controller animated:(BOOL)animated; +- (void)showModalController:(UIViewController *)controller animated:(BOOL)animated; /** Tells application to hide modal view controller. @@ -193,57 +192,56 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run o @param controller The view controller to hide. @param animated If _YES_, animates the view controller as it’s hidden; otherwise, does not. */ --(void)hideModalController:(UIViewController*)controller animated:(BOOL)animated; +- (void)hideModalController:(UIViewController *)controller animated:(BOOL)animated; /** Returns unique identifier for the current application launch. @return Current session id. */ --(NSString*)sessionId; +- (NSString *)sessionId; /** Starts searching for background services. */ --(void)beginBackgrounding; +- (void)beginBackgrounding; /** Ends background services operations. */ --(void)endBackgrounding; +- (void)endBackgrounding; /** Returns the user agent string to use for system network requests. */ --(NSString*)systemUserAgent; +- (NSString *)systemUserAgent; #if IS_XCODE_8 /** Returns a dictionary containing the native notification information (iOS 10 and later). */ -+ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier; ++ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier:(NSString *)identifier; #endif /** Returns a dictionary containing the native notification information. */ -+ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier: (NSString *)identifier; ++ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier:(NSString *)identifier; /** Returns or set the user agent string to use for network requests. */ -@property(nonatomic, retain) NSString* userAgent; +@property (nonatomic, retain) NSString *userAgent; /** Determines if the application finished booting. */ -@property(nonatomic,readonly) BOOL appBooted; +@property (nonatomic, readonly) BOOL appBooted; --(void)registerBackgroundService:(TiProxy*)proxy; --(void)unregisterBackgroundService:(TiProxy*)proxy; --(void)stopBackgroundService:(TiProxy*)proxy; --(void)completionHandler:(id)key withResult:(int)result; --(void)completionHandlerForBackgroundTransfer:(id)key; --(void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary*)userInfo; +- (void)registerBackgroundService:(TiProxy *)proxy; +- (void)unregisterBackgroundService:(TiProxy *)proxy; +- (void)stopBackgroundService:(TiProxy *)proxy; +- (void)completionHandler:(id)key withResult:(int)result; +- (void)completionHandlerForBackgroundTransfer:(id)key; +- (void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary *)userInfo; @end - diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index eb46f8c0904..2f488d63edd 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -6,52 +6,52 @@ */ #include +#import "ApplicationDefaults.h" +#import "ImageLoader.h" +#import "Mimetypes.h" +#import "NSData+Additions.h" #import "TiApp.h" -#import "Webcolor.h" #import "TiBase.h" #import "TiErrorController.h" -#import "NSData+Additions.h" -#import "ImageLoader.h" -#import -#import -#import "ApplicationDefaults.h" -#import #import "TiExceptionHandler.h" -#import "Mimetypes.h" +#import "Webcolor.h" +#import #import +#import +#import #ifdef KROLL_COVERAGE -# import "KrollCoverage.h" +#import "KrollCoverage.h" #endif #ifndef USE_JSCORE_FRAMEWORK #import "TiDebugger.h" #import "TiProfiler/TiProfiler.h" #endif #ifndef DISABLE_TI_LOG_SERVER -# import "TiLogServer.h" +#import "TiLogServer.h" #endif -TiApp* sharedApp; +TiApp *sharedApp; int TiDebugPort = 2525; -extern NSString * const TI_APPLICATION_DEPLOYTYPE; -extern NSString * const TI_APPLICATION_NAME; -extern NSString * const TI_APPLICATION_VERSION; +extern NSString *const TI_APPLICATION_DEPLOYTYPE; +extern NSString *const TI_APPLICATION_NAME; +extern NSString *const TI_APPLICATION_VERSION; extern BOOL const TI_APPLICATION_SHOW_ERROR_CONTROLLER; -NSString * TITANIUM_VERSION; +NSString *TITANIUM_VERSION; extern void UIColorFlushCache(); -#define SHUTDOWN_TIMEOUT_IN_SEC 3 +#define SHUTDOWN_TIMEOUT_IN_SEC 3 #define TIV @"TiVerify" #define TI_BACKGROUNDFETCH_MAX_INTERVAL 29 BOOL applicationInMemoryPanic = NO; -TI_INLINE void waitForMemoryPanicCleared(); //WARNING: This must never be run on main thread, or else there is a risk of deadlock! +TI_INLINE void waitForMemoryPanicCleared(); //WARNING: This must never be run on main thread, or else there is a risk of deadlock! -@interface TiApp() +@interface TiApp () - (void)checkBackgroundServices; - (void)appBoot; @end @@ -63,21 +63,21 @@ @interface TiUserNotificationExtention : UNNotificationServiceExtension @implementation TiUserNotificationExtention --(void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler +- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler { - NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[[request content] userInfo]]; - UNMutableNotificationContent *content = [(UNMutableNotificationContent*)[request content] copy]; - - [userInfo setObject:@YES forKey:@"isRemoteNotification"]; - [content setUserInfo:userInfo]; - - contentHandler(content); - RELEASE_TO_NIL(content); + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[[request content] userInfo]]; + UNMutableNotificationContent *content = [(UNMutableNotificationContent *)[request content] copy]; + + [userInfo setObject:@YES forKey:@"isRemoteNotification"]; + [content setUserInfo:userInfo]; + + contentHandler(content); + RELEASE_TO_NIL(content); } --(void)serviceExtensionTimeWillExpire +- (void)serviceExtensionTimeWillExpire { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:@{} userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:@{} userInfo:nil]; } @end @@ -85,9 +85,9 @@ -(void)serviceExtensionTimeWillExpire @implementation TiApp --(void)clearMemoryPanic +- (void)clearMemoryPanic { - applicationInMemoryPanic = NO; + applicationInMemoryPanic = NO; } @synthesize window, remoteNotificationDelegate, controller; @@ -100,404 +100,386 @@ -(void)clearMemoryPanic @synthesize userAgent; #ifdef TI_USE_KROLL_THREAD -+(void)initialize ++ (void)initialize { - TiThreadInitalize(); + TiThreadInitalize(); } #endif -+ (TiApp*)app ++ (TiApp *)app { - return sharedApp; + return sharedApp; } -+(TiRootViewController*)controller; ++ (TiRootViewController *)controller; { - return [sharedApp controller]; + return [sharedApp controller]; } --(TiContextGroupRef)contextGroup +- (TiContextGroupRef)contextGroup { - if(contextGroup == nil) - { - contextGroup = TiContextGroupCreate(); - TiContextGroupRetain(contextGroup); - } - return contextGroup; + if (contextGroup == nil) { + contextGroup = TiContextGroupCreate(); + TiContextGroupRetain(contextGroup); + } + return contextGroup; } - -+(TiContextGroupRef)contextGroup ++ (TiContextGroupRef)contextGroup { - return [sharedApp contextGroup]; + return [sharedApp contextGroup]; } - --(void)startNetwork +- (void)startNetwork { - ENSURE_UI_THREAD_0_ARGS; - if (OSAtomicIncrement32(&networkActivityCount) == 1) - { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:!disableNetworkActivityIndicator]; - } + ENSURE_UI_THREAD_0_ARGS; + if (OSAtomicIncrement32(&networkActivityCount) == 1) { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:!disableNetworkActivityIndicator]; + } } --(void)stopNetwork +- (void)stopNetwork { - ENSURE_UI_THREAD_0_ARGS; - if (OSAtomicDecrement32(&networkActivityCount) == 0) - { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - } + ENSURE_UI_THREAD_0_ARGS; + if (OSAtomicDecrement32(&networkActivityCount) == 0) { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + } } - (void)setDisableNetworkActivityIndicator:(BOOL)value { - disableNetworkActivityIndicator = value; - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(!disableNetworkActivityIndicator && (networkActivityCount > 0))]; + disableNetworkActivityIndicator = value; + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(!disableNetworkActivityIndicator && (networkActivityCount > 0))]; } --(NSDictionary*)launchOptions +- (NSDictionary *)launchOptions { - return launchOptions; + return launchOptions; } - --(void)initController +- (void)initController { - sharedApp = self; - - // attach our main view controller - controller = [[TiRootViewController alloc] init]; - // attach our main view controller... IF we haven't already loaded the main window. - [window setRootViewController:controller]; - [window makeKeyAndVisible]; + sharedApp = self; + + // attach our main view controller + controller = [[TiRootViewController alloc] init]; + // attach our main view controller... IF we haven't already loaded the main window. + [window setRootViewController:controller]; + [window makeKeyAndVisible]; } --(BOOL)windowIsKeyWindow +- (BOOL)windowIsKeyWindow { - return [window isKeyWindow]; + return [window isKeyWindow]; } --(UIView *) topMostView +- (UIView *)topMostView { - UIWindow *currentKeyWindow_ = [[UIApplication sharedApplication] keyWindow]; - return [[currentKeyWindow_ subviews] lastObject]; + UIWindow *currentKeyWindow_ = [[UIApplication sharedApplication] keyWindow]; + return [[currentKeyWindow_ subviews] lastObject]; } --(void)attachXHRBridgeIfRequired +- (void)attachXHRBridgeIfRequired { #ifdef USE_TI_UIWEBVIEW - if (xhrBridge==nil) - { - xhrBridge = [[XHRBridge alloc] initWithHost:self]; - [xhrBridge boot:self url:nil preload:nil]; - } + if (xhrBridge == nil) { + xhrBridge = [[XHRBridge alloc] initWithHost:self]; + [xhrBridge boot:self url:nil preload:nil]; + } #endif } -- (void) launchToUrl +- (void)launchToUrl { - NSDictionary *launchDefaults = [ApplicationDefaults launchUrl]; - if (launchDefaults != nil) { - UIApplication* app = [UIApplication sharedApplication]; - NSURL *url = [NSURL URLWithString:[launchDefaults objectForKey:@"application-launch-url"]]; - if ([app canOpenURL:url]) { - [app openURL:url]; - } - else { - DebugLog(@"[WARN] The launch-url provided : %@ is invalid.", [launchDefaults objectForKey:@"application-launch-url"]); - } + NSDictionary *launchDefaults = [ApplicationDefaults launchUrl]; + if (launchDefaults != nil) { + UIApplication *app = [UIApplication sharedApplication]; + NSURL *url = [NSURL URLWithString:[launchDefaults objectForKey:@"application-launch-url"]]; + if ([app canOpenURL:url]) { + [app openURL:url]; + } else { + DebugLog(@"[WARN] The launch-url provided : %@ is invalid.", [launchDefaults objectForKey:@"application-launch-url"]); } + } } - (void)createDefaultDirectories { - NSError* error = nil; - [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory - inDomain:NSUserDomainMask - appropriateForURL:nil - create:YES - error:&error]; - if(error) - { - DebugLog(@"[ERROR] %@ %@", error, [error userInfo]); - } + NSError *error = nil; + [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:YES + error:&error]; + if (error) { + DebugLog(@"[ERROR] %@ %@", error, [error userInfo]); + } } - (void)boot { - DebugLog(@"[INFO] %@/%@ (%s.__GITHASH__)",TI_APPLICATION_NAME,TI_APPLICATION_VERSION,TI_VERSION_STR); - - sessionId = [[TiUtils createUUID] retain]; - TITANIUM_VERSION = [[NSString stringWithCString:TI_VERSION_STR encoding:NSUTF8StringEncoding] retain]; + DebugLog(@"[INFO] %@/%@ (%s.__GITHASH__)", TI_APPLICATION_NAME, TI_APPLICATION_VERSION, TI_VERSION_STR); + + sessionId = [[TiUtils createUUID] retain]; + TITANIUM_VERSION = [[NSString stringWithCString:TI_VERSION_STR encoding:NSUTF8StringEncoding] retain]; #ifndef USE_JSCORE_FRAMEWORK - NSString *filePath = [[NSBundle mainBundle] pathForResource:@"debugger" ofType:@"plist"]; - if (filePath != nil) { - NSMutableDictionary *params = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] autorelease]; - NSString *host = [params objectForKey:@"host"]; - NSInteger port = [[params objectForKey:@"port"] integerValue]; - if (([host length] > 0) && ![host isEqualToString:@"__DEBUGGER_HOST__"]) - { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"debugger" ofType:@"plist"]; + if (filePath != nil) { + NSMutableDictionary *params = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] autorelease]; + NSString *host = [params objectForKey:@"host"]; + NSInteger port = [[params objectForKey:@"port"] integerValue]; + if (([host length] > 0) && ![host isEqualToString:@"__DEBUGGER_HOST__"]) { + [self setDebugMode:YES]; + TiDebuggerStart(host, port); + } +#if !TARGET_IPHONE_SIMULATOR + else { + NSString *airkey = [params objectForKey:@"airkey"]; + if (([airkey length] > 0) && ![airkey isEqualToString:@"__DEBUGGER_AIRKEY__"]) { + NSArray *hosts = nil; + NSString *hostsString = [params objectForKey:@"hosts"]; + if (![hostsString isEqualToString:@"__DEBUGGER_HOSTS__"]) { + hosts = [hostsString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; + } + TiDebuggerDiscoveryStart(airkey, hosts, ^(NSString *host, NSInteger port) { + if (host != nil) { [self setDebugMode:YES]; TiDebuggerStart(host, port); - } -#if !TARGET_IPHONE_SIMULATOR - else - { - NSString *airkey = [params objectForKey:@"airkey"]; - if (([airkey length] > 0) && ![airkey isEqualToString:@"__DEBUGGER_AIRKEY__"]) - { - NSArray *hosts = nil; - NSString *hostsString = [params objectForKey:@"hosts"]; - if (![hostsString isEqualToString:@"__DEBUGGER_HOSTS__"]) { - hosts = [hostsString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; - } - TiDebuggerDiscoveryStart(airkey, hosts, ^(NSString *host, NSInteger port) { - if (host != nil) { - [self setDebugMode:YES]; - TiDebuggerStart(host, port); - } - [self appBoot]; - }); - return; - } - } + } + [self appBoot]; + }); + return; + } + } #endif + } + filePath = [[NSBundle mainBundle] pathForResource:@"profiler" ofType:@"plist"]; + if (!self.debugMode && filePath != nil) { + NSMutableDictionary *params = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] autorelease]; + NSString *host = [params objectForKey:@"host"]; + NSInteger port = [[params objectForKey:@"port"] integerValue]; + if (([host length] > 0) && ![host isEqualToString:@"__PROFILER_HOST__"]) { + [self setProfileMode:YES]; + TiProfilerStart(host, port); } - filePath = [[NSBundle mainBundle] pathForResource:@"profiler" ofType:@"plist"]; - if (!self.debugMode && filePath != nil) { - NSMutableDictionary *params = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] autorelease]; - NSString *host = [params objectForKey:@"host"]; - NSInteger port = [[params objectForKey:@"port"] integerValue]; - if (([host length] > 0) && ![host isEqualToString:@"__PROFILER_HOST__"]) - { +#if !TARGET_IPHONE_SIMULATOR + else { + NSString *airkey = [params objectForKey:@"airkey"]; + if (([airkey length] > 0) && ![airkey isEqualToString:@"__PROFILER_AIRKEY__"]) { + NSArray *hosts = nil; + NSString *hostsString = [params objectForKey:@"hosts"]; + if (![hostsString isEqualToString:@"__PROFILER_HOSTS__"]) { + hosts = [hostsString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; + } + TiProfilerDiscoveryStart(airkey, hosts, ^(NSString *host, NSInteger port) { + if (host != nil) { [self setProfileMode:YES]; TiProfilerStart(host, port); - } -#if !TARGET_IPHONE_SIMULATOR - else - { - NSString *airkey = [params objectForKey:@"airkey"]; - if (([airkey length] > 0) && ![airkey isEqualToString:@"__PROFILER_AIRKEY__"]) - { - NSArray *hosts = nil; - NSString *hostsString = [params objectForKey:@"hosts"]; - if (![hostsString isEqualToString:@"__PROFILER_HOSTS__"]) { - hosts = [hostsString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; - } - TiProfilerDiscoveryStart(airkey, hosts, ^(NSString *host, NSInteger port) { - if (host != nil) { - [self setProfileMode:YES]; - TiProfilerStart(host, port); - } - [self appBoot]; - }); - return; - } - } -#endif + } + [self appBoot]; + }); + return; + } } #endif - [self appBoot]; + } +#endif + [self appBoot]; } - (void)appBoot -{ - kjsBridge = [[KrollBridge alloc] initWithHost:self]; - - [kjsBridge boot:self url:nil preload:nil]; - [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; +{ + kjsBridge = [[KrollBridge alloc] initWithHost:self]; + + [kjsBridge boot:self url:nil preload:nil]; + [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } - (void)validator { - [[[NSClassFromString(TIV) alloc] init] autorelease]; + [[[NSClassFromString(TIV) alloc] init] autorelease]; } - (void)booted:(id)bridge { - if ([bridge isKindOfClass:[KrollBridge class]]) - { - DebugLog(@"[DEBUG] Application booted in %f ms", ([NSDate timeIntervalSinceReferenceDate]-started) * 1000); - fflush(stderr); - appBooted = YES; + if ([bridge isKindOfClass:[KrollBridge class]]) { + DebugLog(@"[DEBUG] Application booted in %f ms", ([NSDate timeIntervalSinceReferenceDate] - started) * 1000); + fflush(stderr); + appBooted = YES; - if(launchedShortcutItem != nil) { - [self handleShortcutItem:launchedShortcutItem waitForBootIfNotLaunched:YES]; - RELEASE_TO_NIL(launchedShortcutItem); - } + if (launchedShortcutItem != nil) { + [self handleShortcutItem:launchedShortcutItem waitForBootIfNotLaunched:YES]; + RELEASE_TO_NIL(launchedShortcutItem); + } - if (localNotification != nil) { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; - } - TiThreadPerformOnMainThread(^{[self validator];}, YES); - } + if (localNotification != nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; + } + TiThreadPerformOnMainThread(^{ + [self validator]; + }, + YES); + } } -- (void)applicationDidFinishLaunching:(UIApplication *)application +- (void)applicationDidFinishLaunching:(UIApplication *)application { - [TiExceptionHandler defaultExceptionHandler]; + [TiExceptionHandler defaultExceptionHandler]; #ifndef DISABLE_TI_LOG_SERVER - [TiLogServer startServer]; + [TiLogServer startServer]; #endif - [self initController]; - [self launchToUrl]; - [self boot]; -} - --(UIImageView*)splashScreenImage -{ - if(splashScreenImage == nil) { - splashScreenImage = [[UIImageView alloc] init]; - [splashScreenImage setBackgroundColor:[UIColor yellowColor]]; - [splashScreenImage setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; - [splashScreenImage setContentMode:UIViewContentModeScaleToFill]; - - UIDeviceOrientation imageOrientation; - UIUserInterfaceIdiom imageIdiom; - - UIImage * defaultImage = [controller defaultImageForOrientation: - (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation] - resultingOrientation:&imageOrientation idiom:&imageIdiom]; - if([TiUtils isIPad] && ![TiUtils isIOS8OrGreater]) { - CGAffineTransform transform; - switch ([[UIApplication sharedApplication] statusBarOrientation]) { - case UIInterfaceOrientationPortraitUpsideDown: - transform = CGAffineTransformMakeRotation(M_PI); - break; - case UIInterfaceOrientationLandscapeLeft: - transform = CGAffineTransformMakeRotation(-M_PI_2); - break; - case UIInterfaceOrientationLandscapeRight: - transform = CGAffineTransformMakeRotation(M_PI_2); - break; - default: - transform = CGAffineTransformIdentity; - break; - } - [splashScreenImage setTransform:transform]; - } - [splashScreenImage setImage: defaultImage]; - [splashScreenImage setFrame:[[UIScreen mainScreen] bounds]]; + [self initController]; + [self launchToUrl]; + [self boot]; +} + +- (UIImageView *)splashScreenImage +{ + if (splashScreenImage == nil) { + splashScreenImage = [[UIImageView alloc] init]; + [splashScreenImage setBackgroundColor:[UIColor yellowColor]]; + [splashScreenImage setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; + [splashScreenImage setContentMode:UIViewContentModeScaleToFill]; + + UIDeviceOrientation imageOrientation; + UIUserInterfaceIdiom imageIdiom; + + UIImage *defaultImage = [controller defaultImageForOrientation: + (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation] + resultingOrientation:&imageOrientation + idiom:&imageIdiom]; + if ([TiUtils isIPad] && ![TiUtils isIOS8OrGreater]) { + CGAffineTransform transform; + switch ([[UIApplication sharedApplication] statusBarOrientation]) { + case UIInterfaceOrientationPortraitUpsideDown: + transform = CGAffineTransformMakeRotation(M_PI); + break; + case UIInterfaceOrientationLandscapeLeft: + transform = CGAffineTransformMakeRotation(-M_PI_2); + break; + case UIInterfaceOrientationLandscapeRight: + transform = CGAffineTransformMakeRotation(M_PI_2); + break; + default: + transform = CGAffineTransformIdentity; + break; + } + [splashScreenImage setTransform:transform]; } - return splashScreenImage; -} - -- (void)generateNotification:(NSDictionary*)dict -{ - // Check and see if any keys from APS and the rest of the dictionary match; if they do, just - // bump out the dictionary as-is - remoteNotification = [[NSMutableDictionary alloc] initWithDictionary:dict]; - NSDictionary* aps = [dict objectForKey:@"aps"]; - for (id key in aps) - { - if ([dict objectForKey:key] != nil) { - DebugLog(@"[WARN] Conflicting keys in push APS dictionary and notification dictionary `%@`, not copying to toplevel from APS", key); - continue; - } - [remoteNotification setValue:[aps valueForKey:key] forKey:key]; - } + [splashScreenImage setImage:defaultImage]; + [splashScreenImage setFrame:[[UIScreen mainScreen] bounds]]; + } + return splashScreenImage; +} + +- (void)generateNotification:(NSDictionary *)dict +{ + // Check and see if any keys from APS and the rest of the dictionary match; if they do, just + // bump out the dictionary as-is + remoteNotification = [[NSMutableDictionary alloc] initWithDictionary:dict]; + NSDictionary *aps = [dict objectForKey:@"aps"]; + for (id key in aps) { + if ([dict objectForKey:key] != nil) { + DebugLog(@"[WARN] Conflicting keys in push APS dictionary and notification dictionary `%@`, not copying to toplevel from APS", key); + continue; + } + [remoteNotification setValue:[aps valueForKey:key] forKey:key]; + } } - (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier { - BOOL allowsCustomKeyboard = [TiUtils boolValue:[[TiApp tiAppProperties] objectForKey:@"allow-custom-keyboards"] def:YES]; - - if ([extensionPointIdentifier isEqualToString:UIApplicationKeyboardExtensionPointIdentifier] && !allowsCustomKeyboard) { - return NO; - } - - return YES; + BOOL allowsCustomKeyboard = [TiUtils boolValue:[[TiApp tiAppProperties] objectForKey:@"allow-custom-keyboards"] def:YES]; + + if ([extensionPointIdentifier isEqualToString:UIApplicationKeyboardExtensionPointIdentifier] && !allowsCustomKeyboard) { + return NO; + } + + return YES; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions_ { - started = [NSDate timeIntervalSinceReferenceDate]; - [TiExceptionHandler defaultExceptionHandler]; + started = [NSDate timeIntervalSinceReferenceDate]; + [TiExceptionHandler defaultExceptionHandler]; #ifndef DISABLE_TI_LOG_SERVER - [TiLogServer startServer]; + [TiLogServer startServer]; #endif - // nibless window - window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - - [self initController]; - - // get the current remote device UUID if we have one - NSString *curKey = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; - if (curKey!=nil) - { - remoteDeviceUUID = [curKey copy]; - } - - launchOptions = [[NSMutableDictionary alloc] initWithDictionary:launchOptions_]; - - NSURL *urlOptions = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; - NSString *sourceBundleId = [launchOptions objectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; - - - [launchOptions setObject:NUMBOOL([[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey] boolValue]) forKey:@"launchOptionsLocationKey"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocationKey]; - - localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] withIdentifier:nil] retain]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; - - // reset these to be a little more common if we have them - if (urlOptions!=nil) - { - [launchOptions setObject:[urlOptions absoluteString] forKey:@"url"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; - } - if (sourceBundleId!=nil) - { - [launchOptions setObject:sourceBundleId forKey:@"source"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - } - if (notification!=nil) - { - [self generateNotification:notification]; - } - - if ([TiUtils isIOS9OrGreater] == YES) { - UIApplicationShortcutItem *shortcut = [launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey]; - - if (shortcut != nil) { - launchedShortcutItem = [shortcut retain]; - } + // nibless window + window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + + [self initController]; + + // get the current remote device UUID if we have one + NSString *curKey = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; + if (curKey != nil) { + remoteDeviceUUID = [curKey copy]; + } + + launchOptions = [[NSMutableDictionary alloc] initWithDictionary:launchOptions_]; + + NSURL *urlOptions = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; + NSString *sourceBundleId = [launchOptions objectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; + NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; + + [launchOptions setObject:NUMBOOL([[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey] boolValue]) forKey:@"launchOptionsLocationKey"]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocationKey]; + + localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] withIdentifier:nil] retain]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; + + // reset these to be a little more common if we have them + if (urlOptions != nil) { + [launchOptions setObject:[urlOptions absoluteString] forKey:@"url"]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; + } + if (sourceBundleId != nil) { + [launchOptions setObject:sourceBundleId forKey:@"source"]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; + } + if (notification != nil) { + [self generateNotification:notification]; + } + + if ([TiUtils isIOS9OrGreater] == YES) { + UIApplicationShortcutItem *shortcut = [launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey]; + + if (shortcut != nil) { + launchedShortcutItem = [shortcut retain]; } - - [self launchToUrl]; - [self boot]; - [self createDefaultDirectories]; - return YES; + } + + [self launchToUrl]; + [self boot]; + [self createDefaultDirectories]; + return YES; } // Handle URL-schemes / iOS >= 9 -- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; - [launchOptions setObject:[url absoluteString] forKey:@"url"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - - [launchOptions setObject:[options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey] ?: [NSNull null] forKey:@"source"]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationLaunchedFromURL object:self userInfo:launchOptions]; - - return YES; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; + [launchOptions setObject:[url absoluteString] forKey:@"url"]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; + + [launchOptions setObject:[options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey] ?: [NSNull null] forKey:@"source"]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationLaunchedFromURL object:self userInfo:launchOptions]; + + return YES; } // Handle URL-schemes / iOS < 9 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; - [launchOptions setObject:[url absoluteString] forKey:@"url"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; + [launchOptions setObject:[url absoluteString] forKey:@"url"]; + [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; + + [launchOptions setObject:sourceApplication ?: [NSNull null] forKey:@"source"]; - [launchOptions setObject:sourceApplication ?: [NSNull null] forKey:@"source"]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationLaunchedFromURL object:self userInfo:launchOptions]; - - return YES; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationLaunchedFromURL object:self userInfo:launchOptions]; + + return YES; } #pragma mark @@ -505,31 +487,32 @@ - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceAppl #ifdef USE_TI_FETCH --(void)application:(UIApplication*)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { +- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler +{ - //Only for simulator builds - NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - if ([backgroundModes containsObject:@"fetch"]) { + //Only for simulator builds + NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; + if ([backgroundModes containsObject:@"fetch"]) { - // Generate unique key with timestamp. - id key = [NSString stringWithFormat:@"Fetch-%f",[[NSDate date] timeIntervalSince1970]]; + // Generate unique key with timestamp. + id key = [NSString stringWithFormat:@"Fetch-%f", [[NSDate date] timeIntervalSince1970]]; - // Store the completionhandler till we can come back and send appropriate message. - if (pendingCompletionHandlers == nil) { - pendingCompletionHandlers = [[NSMutableDictionary alloc] init]; - } + // Store the completionhandler till we can come back and send appropriate message. + if (pendingCompletionHandlers == nil) { + pendingCompletionHandlers = [[NSMutableDictionary alloc] init]; + } - [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease ]forKey:key]; + [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; - // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called - // the bridge completes processing of app.js (adding the event into notification center). + // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called + // the bridge completes processing of app.js (adding the event into notification center). - [self postNotificationwithKey:[NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil] withNotificationName:kTiBackgroundFetchNotification] ; + [self postNotificationwithKey:[NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil] withNotificationName:kTiBackgroundFetchNotification]; - // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. - NSTimer* flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO] ; - [[NSRunLoop mainRunLoop] addTimer:flushTimer forMode:NSDefaultRunLoopMode]; - } + // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. + NSTimer *flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:flushTimer forMode:NSDefaultRunLoopMode]; + } } #endif @@ -538,20 +521,20 @@ -(void)application:(UIApplication*)application performFetchWithCompletionHandler - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification object:notificationSettings userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification object:notificationSettings userInfo:nil]; } #if IS_XCODE_8 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { - // TODO: Get desired options from notification - // For example, pass none for silent pushes - completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionSound); + // TODO: Get desired options from notification + // For example, pass none for silent pushes + completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); } --(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { - /*RELEASE_TO_NIL(remoteNotification); + /*RELEASE_TO_NIL(remoteNotification); [self generateNotification:userInfo]; NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; event[@"data"] = remoteNotification; @@ -565,182 +548,184 @@ -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotif [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; [event autorelease]; completionHandler();*/ - - // TODO: Find out where the payload is stored to handle the above - - if ([[[[[response notification] request] content] userInfo] valueForKey:@"isRemoteNotification"] != nil) { - RELEASE_TO_NIL(remoteNotification); - remoteNotification = [[[self class] dictionaryWithUserNotification:response.notification - withIdentifier:response.actionIdentifier] retain]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:remoteNotification userInfo:nil]; - } else { - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithUserNotification:response.notification - withIdentifier:response.actionIdentifier] retain]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; - } - - completionHandler(); + + // TODO: Find out where the payload is stored to handle the above + + if ([[[[[response notification] request] content] userInfo] valueForKey:@"isRemoteNotification"] != nil) { + RELEASE_TO_NIL(remoteNotification); + remoteNotification = [[[self class] dictionaryWithUserNotification:response.notification + withIdentifier:response.actionIdentifier] retain]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:remoteNotification userInfo:nil]; + } else { + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithUserNotification:response.notification + withIdentifier:response.actionIdentifier] retain]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; + } + + completionHandler(); } #endif -- (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; - - if([TiUtils isIOS9OrGreater] == YES) { - [localNotification setValue:responseInfo[UIUserNotificationActionResponseTypedTextKey] forKey:@"typedText"]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; - completionHandler(); +- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler +{ + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; + + if ([TiUtils isIOS9OrGreater] == YES) { + [localNotification setValue:responseInfo[UIUserNotificationActionResponseTypedTextKey] forKey:@"typedText"]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; + completionHandler(); } - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:nil] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:nil] retain]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; } -- (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { - RELEASE_TO_NIL(remoteNotification); - [self generateNotification:userInfo]; - NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; - event[@"data"] = remoteNotification; - if (identifier != nil) { - event[@"identifier"] = identifier; - } - NSString *category = remoteNotification[@"category"]; - if (category != nil) { - event[@"category"] = category; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; - [event autorelease]; - completionHandler(); +- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler +{ + RELEASE_TO_NIL(remoteNotification); + [self generateNotification:userInfo]; + NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; + event[@"data"] = remoteNotification; + if (identifier != nil) { + event[@"identifier"] = identifier; + } + NSString *category = remoteNotification[@"category"]; + if (category != nil) { + event[@"category"] = category; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; + [event autorelease]; + completionHandler(); } - #pragma mark Apple Watchkit handleWatchKitExtensionRequest - (void)application:(UIApplication *)application - handleWatchKitExtensionRequest:(NSDictionary *)userInfo - reply:(void (^)(NSDictionary *replyInfo))reply + handleWatchKitExtensionRequest:(NSDictionary *)userInfo + reply:(void (^)(NSDictionary *replyInfo))reply { - // Generate unique key with timestamp. - id key = [NSString stringWithFormat:@"watchkit-reply-%f",[[NSDate date] timeIntervalSince1970]]; - - if (pendingReplyHandlers == nil) { - pendingReplyHandlers = [[NSMutableDictionary alloc] init]; - } - - [pendingReplyHandlers setObject:[[reply copy] autorelease ]forKey:key]; - - NSMutableDictionary* dic = [[[NSMutableDictionary alloc] init] autorelease]; - [dic setObject:key forKey:@"handlerId"]; - if(userInfo!=nil){ - [dic setObject:userInfo forKey:@"userInfo"]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiWatchKitExtensionRequest object:self userInfo:dic]; + // Generate unique key with timestamp. + id key = [NSString stringWithFormat:@"watchkit-reply-%f", [[NSDate date] timeIntervalSince1970]]; + + if (pendingReplyHandlers == nil) { + pendingReplyHandlers = [[NSMutableDictionary alloc] init]; + } + + [pendingReplyHandlers setObject:[[reply copy] autorelease] forKey:key]; + + NSMutableDictionary *dic = [[[NSMutableDictionary alloc] init] autorelease]; + [dic setObject:key forKey:@"handlerId"]; + if (userInfo != nil) { + [dic setObject:userInfo forKey:@"userInfo"]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiWatchKitExtensionRequest object:self userInfo:dic]; } --(void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary*)userInfo +- (void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary *)userInfo { - if (pendingReplyHandlers == nil) { - DebugLog(@"[ERROR] No WatchKitExtensionRequest have been recieved yet"); - return; - } + if (pendingReplyHandlers == nil) { + DebugLog(@"[ERROR] No WatchKitExtensionRequest have been recieved yet"); + return; + } - if ([pendingReplyHandlers objectForKey:key]) { - void(^replyBlock)(NSDictionary *input); - replyBlock = [pendingReplyHandlers objectForKey:key]; - replyBlock(userInfo); - [pendingReplyHandlers removeObjectForKey:key]; - } else { - DebugLog(@"[ERROR] The specified WatchKitExtensionRequest Handler with ID: %@ has already expired or removed from the system", key); - } + if ([pendingReplyHandlers objectForKey:key]) { + void (^replyBlock)(NSDictionary *input); + replyBlock = [pendingReplyHandlers objectForKey:key]; + replyBlock(userInfo); + [pendingReplyHandlers removeObjectForKey:key]; + } else { + DebugLog(@"[ERROR] The specified WatchKitExtensionRequest Handler with ID: %@ has already expired or removed from the system", key); + } } #pragma mark - #pragma mark Helper Methods --(void)postNotificationwithKey:(NSMutableDictionary*)userInfo withNotificationName:(NSString*)notificationName{ - - //Check to see if the app booted and we still have the completionhandler in the system - NSString* key = [userInfo objectForKey:@"handlerId"] ; - BOOL shouldContinue = NO; - if ([key rangeOfString:@"Session"].location != NSNotFound) { - if ([backgroundTransferCompletionHandlers objectForKey:key] != nil) { - shouldContinue = YES; - } - }else if ([pendingCompletionHandlers objectForKey:key] != nil) { - shouldContinue = YES; - } - if (!shouldContinue) { - return; - } - if (appBooted ) { - [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo]; - } else { - //Try again in 2 sec. TODO: should we reduce this value ? - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self postNotificationwithKey:userInfo withNotificationName:notificationName]; - }); +- (void)postNotificationwithKey:(NSMutableDictionary *)userInfo withNotificationName:(NSString *)notificationName +{ + + //Check to see if the app booted and we still have the completionhandler in the system + NSString *key = [userInfo objectForKey:@"handlerId"]; + BOOL shouldContinue = NO; + if ([key rangeOfString:@"Session"].location != NSNotFound) { + if ([backgroundTransferCompletionHandlers objectForKey:key] != nil) { + shouldContinue = YES; } + } else if ([pendingCompletionHandlers objectForKey:key] != nil) { + shouldContinue = YES; + } + if (!shouldContinue) { + return; + } + if (appBooted) { + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo]; + } else { + //Try again in 2 sec. TODO: should we reduce this value ? + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self postNotificationwithKey:userInfo withNotificationName:notificationName]; + }); + } } //Clear out the pendingCompletionHandlerQueue --(void)flushCompletionHandlerQueue +- (void)flushCompletionHandlerQueue { - //FunctionName(); - if (pendingCompletionHandlers !=nil) { - for (id key in pendingCompletionHandlers) { - [self completionHandler:key withResult:2]; //UIBackgroundFetchResultFailed - } + //FunctionName(); + if (pendingCompletionHandlers != nil) { + for (id key in pendingCompletionHandlers) { + [self completionHandler:key withResult:2]; //UIBackgroundFetchResultFailed } - RELEASE_TO_NIL(pendingCompletionHandlers); + } + RELEASE_TO_NIL(pendingCompletionHandlers); } // This method gets called when the wall clock runs out and the completionhandler is still there. --(void)fireCompletionHandler:(NSTimer*)timer +- (void)fireCompletionHandler:(NSTimer *)timer { - //FunctionName(); - id key = timer.userInfo; - if ([pendingCompletionHandlers objectForKey:key]) { - [self completionHandler:key withResult:UIBackgroundFetchResultFailed]; - //Send a event signalling the that backgroundfetch ended. - } + //FunctionName(); + id key = timer.userInfo; + if ([pendingCompletionHandlers objectForKey:key]) { + [self completionHandler:key withResult:UIBackgroundFetchResultFailed]; + //Send a event signalling the that backgroundfetch ended. + } } // gets called when user ends finishes with backgrounding stuff. By default this would always be called with UIBackgroundFetchResultNoData. --(void)completionHandler:(id)key withResult:(int)result -{ - //FunctionName(); - if ([pendingCompletionHandlers objectForKey:key]) { - void (^completionHandler)(UIBackgroundFetchResult); - completionHandler = [pendingCompletionHandlers objectForKey:key]; - completionHandler(result); - [pendingCompletionHandlers removeObjectForKey:key]; - } else { - DebugLog(@"[ERROR] The specified Completion Handler with ID: %@ has already expired or removed from the system", key); - } +- (void)completionHandler:(id)key withResult:(int)result +{ + //FunctionName(); + if ([pendingCompletionHandlers objectForKey:key]) { + void (^completionHandler)(UIBackgroundFetchResult); + completionHandler = [pendingCompletionHandlers objectForKey:key]; + completionHandler(result); + [pendingCompletionHandlers removeObjectForKey:key]; + } else { + DebugLog(@"[ERROR] The specified Completion Handler with ID: %@ has already expired or removed from the system", key); + } } //Called to mark the end of background transfer while in the background. --(void)completionHandlerForBackgroundTransfer:(id)key +- (void)completionHandlerForBackgroundTransfer:(id)key { - if ([backgroundTransferCompletionHandlers objectForKey:key] != nil) { - void (^completionHandler)(); - completionHandler = [backgroundTransferCompletionHandlers objectForKey:key]; - [backgroundTransferCompletionHandlers removeObjectForKey:key]; - completionHandler(); - } else{ - DebugLog(@"[ERROR] The specified Completion Handler with ID: %@ has already expired or removed from the system", key); - } + if ([backgroundTransferCompletionHandlers objectForKey:key] != nil) { + void (^completionHandler)(); + completionHandler = [backgroundTransferCompletionHandlers objectForKey:key]; + [backgroundTransferCompletionHandlers removeObjectForKey:key]; + completionHandler(); + } else { + DebugLog(@"[ERROR] The specified Completion Handler with ID: %@ has already expired or removed from the system", key); + } } #pragma mark @@ -750,38 +735,38 @@ -(void)completionHandlerForBackgroundTransfer:(id)key //Delegate callback for Silent Remote Notification. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - //FunctionName(); - //Forward the callback - if ([self respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) { - [self application:application didReceiveRemoteNotification:userInfo]; - } - - //This only here for Simulator builds. - - NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - if ([backgroundModes containsObject:@"remote-notification"]) { - - // Generate unique key with timestamp. - id key = [NSString stringWithFormat:@"SilentPush-%f",[[NSDate date] timeIntervalSince1970]]; - - // Store the completionhandler till we can come back and send appropriate message. - if (pendingCompletionHandlers == nil) { - pendingCompletionHandlers = [[NSMutableDictionary alloc] init]; - } - - [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease ]forKey:key]; - - // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called - // the bridge completes processing of app.js (adding the event into notification center). - - NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil]; - [dict addEntriesFromDictionary:userInfo]; - [self postNotificationwithKey:dict withNotificationName:kTiSilentPushNotification]; - - // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. - NSTimer* flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO] ; - [[NSRunLoop mainRunLoop] addTimer:flushTimer forMode:NSDefaultRunLoopMode]; + //FunctionName(); + //Forward the callback + if ([self respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) { + [self application:application didReceiveRemoteNotification:userInfo]; + } + + //This only here for Simulator builds. + + NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; + if ([backgroundModes containsObject:@"remote-notification"]) { + + // Generate unique key with timestamp. + id key = [NSString stringWithFormat:@"SilentPush-%f", [[NSDate date] timeIntervalSince1970]]; + + // Store the completionhandler till we can come back and send appropriate message. + if (pendingCompletionHandlers == nil) { + pendingCompletionHandlers = [[NSMutableDictionary alloc] init]; } + + [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; + + // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called + // the bridge completes processing of app.js (adding the event into notification center). + + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil]; + [dict addEntriesFromDictionary:userInfo]; + [self postNotificationwithKey:dict withNotificationName:kTiSilentPushNotification]; + + // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. + NSTimer *flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:flushTimer forMode:NSDefaultRunLoopMode]; + } } #endif @@ -792,142 +777,139 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N //Delegate callback for Background Transfer completes. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { - //FunctionName(); - // Generate unique key with timestamp. - id key = [NSString stringWithFormat:@"Session-%f",[[NSDate date] timeIntervalSince1970]]; - - // Store the completionhandler till we can come back and send appropriate message. - if (backgroundTransferCompletionHandlers == nil) { - backgroundTransferCompletionHandlers = [[NSMutableDictionary alloc] init]; - } - - [backgroundTransferCompletionHandlers setObject:[[completionHandler copy] autorelease ]forKey:key]; - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:identifier, @"sessionId", - key, @"handlerId", nil]; - [self postNotificationwithKey:dict withNotificationName:kTiBackgroundTransfer]; + //FunctionName(); + // Generate unique key with timestamp. + id key = [NSString stringWithFormat:@"Session-%f", [[NSDate date] timeIntervalSince1970]]; + + // Store the completionhandler till we can come back and send appropriate message. + if (backgroundTransferCompletionHandlers == nil) { + backgroundTransferCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + [backgroundTransferCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:identifier, @"sessionId", + key, @"handlerId", nil]; + [self postNotificationwithKey:dict withNotificationName:kTiBackgroundTransfer]; } #pragma mark Background Transfer Service Delegates. //TODO: Move these delegates to the module post 3.2.0 --(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location -{ - //FunctionName(); - //copy downloaded file from location to tempFile (in NSTemporaryDirectory), because file in location will be removed after delegate completes - NSError *error; - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString *destinationFilename = location.lastPathComponent; - NSURL *destinationURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:destinationFilename]; - if ([fileManager fileExistsAtPath:[destinationURL path]]) { - [fileManager removeItemAtURL:destinationURL error:nil]; - } - BOOL success = [fileManager copyItemAtURL:location toURL:destinationURL error:&error]; - TiBlob* downloadedData; - if (!success) { - DebugLog(@"Unable to copy temp file. Error: %@", [error localizedDescription]); - downloadedData =[[[TiBlob alloc] initWithData:[NSData dataWithContentsOfURL:location] mimetype:[Mimetypes mimeTypeForExtension:[location absoluteString]]] autorelease]; - } - else { - downloadedData = [[[TiBlob alloc] initWithFile:[destinationURL path]] autorelease]; - } - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:downloadTask.taskIdentifier ],@"taskIdentifier", - downloadedData,@"data", nil]; - - if (session.configuration.identifier) { - [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLDownloadFinished object:self userInfo:dict]; +- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location +{ + //FunctionName(); + //copy downloaded file from location to tempFile (in NSTemporaryDirectory), because file in location will be removed after delegate completes + NSError *error; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *destinationFilename = location.lastPathComponent; + NSURL *destinationURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:destinationFilename]; + if ([fileManager fileExistsAtPath:[destinationURL path]]) { + [fileManager removeItemAtURL:destinationURL error:nil]; + } + BOOL success = [fileManager copyItemAtURL:location toURL:destinationURL error:&error]; + TiBlob *downloadedData; + if (!success) { + DebugLog(@"Unable to copy temp file. Error: %@", [error localizedDescription]); + downloadedData = [[[TiBlob alloc] initWithData:[NSData dataWithContentsOfURL:location] mimetype:[Mimetypes mimeTypeForExtension:[location absoluteString]]] autorelease]; + } else { + downloadedData = [[[TiBlob alloc] initWithFile:[destinationURL path]] autorelease]; + } + + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInteger:downloadTask.taskIdentifier], @"taskIdentifier", + downloadedData, @"data", nil]; + + if (session.configuration.identifier) { + [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLDownloadFinished object:self userInfo:dict]; } --(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite +- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:downloadTask.taskIdentifier], @"taskIdentifier", - [NSNumber numberWithUnsignedLongLong:bytesWritten], @"bytesWritten", - [NSNumber numberWithUnsignedLongLong:totalBytesWritten], @"totalBytesWritten", - [NSNumber numberWithUnsignedLongLong:totalBytesExpectedToWrite], @"totalBytesExpectedToWrite", nil]; + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInteger:downloadTask.taskIdentifier], @"taskIdentifier", + [NSNumber numberWithUnsignedLongLong:bytesWritten], @"bytesWritten", + [NSNumber numberWithUnsignedLongLong:totalBytesWritten], @"totalBytesWritten", + [NSNumber numberWithUnsignedLongLong:totalBytesExpectedToWrite], @"totalBytesExpectedToWrite", nil]; - if (session.configuration.identifier) { - [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLDowloadProgress object:self userInfo:dict]; + if (session.configuration.identifier) { + [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLDowloadProgress object:self userInfo:dict]; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent - totalBytesSent:(int64_t) totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:NUMUINTEGER(task.taskIdentifier),@"taskIdentifier", - [NSNumber numberWithUnsignedLongLong:bytesSent], @"bytesSent", - [NSNumber numberWithUnsignedLongLong:totalBytesSent], @"totalBytesSent", - [NSNumber numberWithUnsignedLongLong:totalBytesExpectedToSend], @"totalBytesExpectedToSend", nil]; - - if (session.configuration.identifier) { - [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLUploadProgress object:self userInfo:dict]; + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:NUMUINTEGER(task.taskIdentifier), @"taskIdentifier", + [NSNumber numberWithUnsignedLongLong:bytesSent], @"bytesSent", + [NSNumber numberWithUnsignedLongLong:totalBytesSent], @"totalBytesSent", + [NSNumber numberWithUnsignedLongLong:totalBytesExpectedToSend], @"totalBytesExpectedToSend", nil]; + + if (session.configuration.identifier) { + [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLUploadProgress object:self userInfo:dict]; } --(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - //FunctionName(); - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:task.taskIdentifier], @"taskIdentifier", - nil]; - - if (session.configuration.identifier) { - [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; - } - - if (error) { - NSDictionary * errorinfo = [NSDictionary dictionaryWithObjectsAndKeys:NUMBOOL(NO), @"success", - NUMINTEGER([error code]), @"errorCode", - [error localizedDescription], @"message", - nil]; - [dict addEntriesFromDictionary:errorinfo]; - } else { - NSDictionary * success = [NSDictionary dictionaryWithObjectsAndKeys:NUMBOOL(YES), @"success", - NUMINT(0), @"errorCode", - @"", @"message", - nil]; - [dict addEntriesFromDictionary:success]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLSessionCompleted object:self userInfo:dict]; + //FunctionName(); + + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInteger:task.taskIdentifier], @"taskIdentifier", + nil]; + + if (session.configuration.identifier) { + [dict setObject:session.configuration.identifier forKey:@"sessionIdentifier"]; + } + if (error) { + NSDictionary *errorinfo = [NSDictionary dictionaryWithObjectsAndKeys:NUMBOOL(NO), @"success", + NUMINTEGER([error code]), @"errorCode", + [error localizedDescription], @"message", + nil]; + [dict addEntriesFromDictionary:errorinfo]; + } else { + NSDictionary *success = [NSDictionary dictionaryWithObjectsAndKeys:NUMBOOL(YES), @"success", + NUMINT(0), @"errorCode", + @"", @"message", + nil]; + [dict addEntriesFromDictionary:success]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLSessionCompleted object:self userInfo:dict]; } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask - didResumeAtOffset:(int64_t)fileOffset -expectedTotalBytes:(int64_t)expectedTotalBytes { - + didResumeAtOffset:(int64_t)fileOffset + expectedTotalBytes:(int64_t)expectedTotalBytes +{ } - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { - NSDictionary *dict = nil; - - if (session.configuration.identifier) { - dict = @{@"sessionIdentifier": session.configuration.identifier}; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLSessionEventsCompleted object:self userInfo:dict]; + NSDictionary *dict = nil; + + if (session.configuration.identifier) { + dict = @{ @"sessionIdentifier" : session.configuration.identifier }; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiURLSessionEventsCompleted object:self userInfo:dict]; } #pragma mark #ifdef TI_USE_KROLL_THREAD --(void)waitForKrollProcessing +- (void)waitForKrollProcessing { - CGFloat timeLeft = [[UIApplication sharedApplication] backgroundTimeRemaining]-1.0; - /* + CGFloat timeLeft = [[UIApplication sharedApplication] backgroundTimeRemaining] - 1.0; + /* * In the extreme edge case of having come back to the app while * it's still waiting for Kroll Processing, * backgroundTimeRemaining becomes undefined, and so we have @@ -935,219 +917,218 @@ -(void)waitForKrollProcessing * The other reason for the timeLeft limit is to not starve * possible later calls for waitForKrollProcessing. */ - if (timeLeft > 3.0) { - timeLeft = 3.0; - } - else if(timeLeft < 0.0) { - return; - } - TiThreadProcessPendingMainThreadBlocks(timeLeft, NO, nil); + if (timeLeft > 3.0) { + timeLeft = 3.0; + } else if (timeLeft < 0.0) { + return; + } + TiThreadProcessPendingMainThreadBlocks(timeLeft, NO, nil); } #endif - (void)applicationWillTerminate:(UIApplication *)application { - NSNotificationCenter * theNotificationCenter = [NSNotificationCenter defaultCenter]; - _willTerminate = YES; - //This will send out the 'close' message. - [theNotificationCenter postNotificationName:kTiWillShutdownNotification object:self]; - NSCondition *condition = [[NSCondition alloc] init]; + NSNotificationCenter *theNotificationCenter = [NSNotificationCenter defaultCenter]; + _willTerminate = YES; + //This will send out the 'close' message. + [theNotificationCenter postNotificationName:kTiWillShutdownNotification object:self]; + NSCondition *condition = [[NSCondition alloc] init]; #ifdef USE_TI_UIWEBVIEW - [xhrBridge shutdown:nil]; -#endif + [xhrBridge shutdown:nil]; +#endif #ifdef KROLL_COVERAGE - [KrollCoverageObject releaseCoverage]; + [KrollCoverageObject releaseCoverage]; #endif - //These shutdowns return immediately, yes, but the main will still run the close that's in their queue. - [kjsBridge shutdown:condition]; + //These shutdowns return immediately, yes, but the main will still run the close that's in their queue. + [kjsBridge shutdown:condition]; #ifndef DISABLE_TI_LOG_SERVER - [TiLogServer stopServer]; + [TiLogServer stopServer]; #endif - // THE CODE BELOW IS WRONG. - // It only waits until ONE context has signialed that it has shut down; then we proceed along our merry way. - // This might lead to problems like contexts not getting cleaned up properly due to premature app termination. - // Plus, it blocks the main thread... meaning that we can have deadlocks if any context is currently executing - // a request that requires operations on the main thread. - [condition lock]; - [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:SHUTDOWN_TIMEOUT_IN_SEC]]; - [condition unlock]; - - //This will shut down the modules. - [theNotificationCenter postNotificationName:kTiShutdownNotification object:self]; + // THE CODE BELOW IS WRONG. + // It only waits until ONE context has signialed that it has shut down; then we proceed along our merry way. + // This might lead to problems like contexts not getting cleaned up properly due to premature app termination. + // Plus, it blocks the main thread... meaning that we can have deadlocks if any context is currently executing + // a request that requires operations on the main thread. + [condition lock]; + [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:SHUTDOWN_TIMEOUT_IN_SEC]]; + [condition unlock]; + + //This will shut down the modules. + [theNotificationCenter postNotificationName:kTiShutdownNotification object:self]; #ifdef TI_USE_KROLL_THREAD - [self waitForKrollProcessing]; + [self waitForKrollProcessing]; #endif - RELEASE_TO_NIL(condition); - RELEASE_TO_NIL(kjsBridge); -#ifdef USE_TI_UIWEBVIEW - RELEASE_TO_NIL(xhrBridge); -#endif - RELEASE_TO_NIL(remoteNotification); - RELEASE_TO_NIL(pendingCompletionHandlers); - RELEASE_TO_NIL(backgroundTransferCompletionHandlers); - RELEASE_TO_NIL(sessionId); + RELEASE_TO_NIL(condition); + RELEASE_TO_NIL(kjsBridge); +#ifdef USE_TI_UIWEBVIEW + RELEASE_TO_NIL(xhrBridge); +#endif + RELEASE_TO_NIL(remoteNotification); + RELEASE_TO_NIL(pendingCompletionHandlers); + RELEASE_TO_NIL(backgroundTransferCompletionHandlers); + RELEASE_TO_NIL(sessionId); } - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - applicationInMemoryPanic = YES; - [Webcolor flushCache]; - // don't worry about KrollBridge since he's already listening + applicationInMemoryPanic = YES; + [Webcolor flushCache]; +// don't worry about KrollBridge since he's already listening #ifdef USE_TI_UIWEBVIEW - [xhrBridge gc]; -#endif - [self performSelector:@selector(clearMemoryPanic) withObject:nil afterDelay:0.0]; + [xhrBridge gc]; +#endif + [self performSelector:@selector(clearMemoryPanic) + withObject:nil + afterDelay:0.0]; } --(void)applicationWillResignActive:(UIApplication *)application +- (void)applicationWillResignActive:(UIApplication *)application { - if([self forceSplashAsSnapshot]) { + if ([self forceSplashAsSnapshot]) { #ifdef LAUNCHSCREEN_STORYBOARD - UIStoryboard *sb = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil]; - UIViewController *vc = [sb instantiateInitialViewController]; - [[[self controller] topPresentedController] presentViewController:vc animated:NO completion:nil]; + UIStoryboard *sb = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil]; + UIViewController *vc = [sb instantiateInitialViewController]; + [[[self controller] topPresentedController] presentViewController:vc animated:NO completion:nil]; #else - [window addSubview:[self splashScreenImage]]; + [window addSubview:[self splashScreenImage]]; #endif - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiSuspendNotification object:self]; - - // suspend any image loading - [[ImageLoader sharedLoader] suspend]; - [kjsBridge gc]; - + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiSuspendNotification object:self]; + + // suspend any image loading + [[ImageLoader sharedLoader] suspend]; + [kjsBridge gc]; + #ifdef USE_TI_UIWEBVIEW - [xhrBridge gc]; -#endif + [xhrBridge gc]; +#endif #ifdef TI_USE_KROLL_THREAD - [self waitForKrollProcessing]; + [self waitForKrollProcessing]; #endif } - (void)applicationDidBecomeActive:(UIApplication *)application { - // We should think about placing this inside "applicationWillBecomeActive" instead to make - // the UI re-useable again more quickly - if([self forceSplashAsSnapshot]) { + // We should think about placing this inside "applicationWillBecomeActive" instead to make + // the UI re-useable again more quickly + if ([self forceSplashAsSnapshot]) { #ifdef LAUNCHSCREEN_STORYBOARD - [[[self controller] topPresentedController] dismissViewControllerAnimated:NO completion:nil]; + [[[self controller] topPresentedController] dismissViewControllerAnimated:NO + completion:nil]; #else - if(splashScreenImage != nil) { - [[self splashScreenImage] removeFromSuperview]; - RELEASE_TO_NIL(splashScreenImage); - } + if (splashScreenImage != nil) { + [[self splashScreenImage] removeFromSuperview]; + RELEASE_TO_NIL(splashScreenImage); + } #endif - } - - // NOTE: Have to fire a separate but non-'resume' event here because there is SOME information - // (like new URL) that is not passed through as part of the normal foregrounding process. - [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumedNotification object:self]; - - // resume any image loading - [[ImageLoader sharedLoader] resume]; -} - --(void)applicationDidEnterBackground:(UIApplication *)application -{ - //FunctionName(); - [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; - - if (backgroundServices==nil) - { - return; - } - - UIApplication* app = [UIApplication sharedApplication]; - TiApp *tiapp = self; - bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ - // Synchronize the cleanup call on the main thread in case - // the task actually finishes at around the same time. - TiThreadPerformOnMainThread( ^{ - if (bgTask != UIBackgroundTaskInvalid) - { - [app endBackgroundTask:bgTask]; - bgTask = UIBackgroundTaskInvalid; - } - }, NO); - }]; - // Start the long-running task and return immediately. - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - // Do the work associated with the task. - [tiapp beginBackgrounding]; - }); + } + + // NOTE: Have to fire a separate but non-'resume' event here because there is SOME information + // (like new URL) that is not passed through as part of the normal foregrounding process. + [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumedNotification object:self]; + + // resume any image loading + [[ImageLoader sharedLoader] resume]; +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + //FunctionName(); + [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; + + if (backgroundServices == nil) { + return; + } + + UIApplication *app = [UIApplication sharedApplication]; + TiApp *tiapp = self; + bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ + // Synchronize the cleanup call on the main thread in case + // the task actually finishes at around the same time. + TiThreadPerformOnMainThread(^{ + if (bgTask != UIBackgroundTaskInvalid) { + [app endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + } + }, + NO); + }]; + // Start the long-running task and return immediately. + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + // Do the work associated with the task. + [tiapp beginBackgrounding]; + }); #ifdef TI_USE_KROLL_THREAD - [self waitForKrollProcessing]; + [self waitForKrollProcessing]; #endif } --(void)applicationWillEnterForeground:(UIApplication *)application +- (void)applicationWillEnterForeground:(UIApplication *)application { - //FunctionName(); Uncomment to see function name printed when it is called. - [self flushCompletionHandlerQueue]; - [sessionId release]; - sessionId = [[TiUtils createUUID] retain]; - - //TIMOB-3432. Ensure url is cleared when resume event is fired. - [launchOptions removeObjectForKey:@"url"]; - [launchOptions removeObjectForKey:@"source"]; + //FunctionName(); Uncomment to see function name printed when it is called. + [self flushCompletionHandlerQueue]; + [sessionId release]; + sessionId = [[TiUtils createUUID] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumeNotification object:self]; - - if (backgroundServices==nil) - { - return; - } - - [self endBackgrounding]; + //TIMOB-3432. Ensure url is cleared when resume event is fired. + [launchOptions removeObjectForKey:@"url"]; + [launchOptions removeObjectForKey:@"source"]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumeNotification object:self]; + + if (backgroundServices == nil) { + return; + } + + [self endBackgrounding]; } #pragma mark Handoff Delegates #ifdef USE_TI_APPIOS - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity - restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"activityType": [userActivity activityType]}]; - if ([TiUtils isIOS9OrGreater] && [[userActivity activityType] isEqualToString:CSSearchableItemActionType]) { - if ([userActivity userInfo] != nil) { - [dict setObject:[[userActivity userInfo] objectForKey:CSSearchableItemActivityIdentifier] forKey:@"searchableItemActivityIdentifier"]; - } - } + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{ @"activityType" : [userActivity activityType] }]; - if ([userActivity title] != nil) { - [dict setObject:[userActivity title] forKey:@"title"]; - } - - if ([userActivity webpageURL] != nil) { - [dict setObject:[[userActivity webpageURL] absoluteString] forKey:@"webpageURL"]; - } - + if ([TiUtils isIOS9OrGreater] && [[userActivity activityType] isEqualToString:CSSearchableItemActionType]) { if ([userActivity userInfo] != nil) { - [dict setObject:[userActivity userInfo] forKey:@"userInfo"]; + [dict setObject:[[userActivity userInfo] objectForKey:CSSearchableItemActivityIdentifier] forKey:@"searchableItemActivityIdentifier"]; } - - // Update launchOptions so that we send only expected values rather than NSUserActivity - NSMutableDictionary* userActivityDict = [NSMutableDictionary dictionaryWithDictionary:launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]]; - [userActivityDict setObject:dict forKey:@"UIApplicationLaunchOptionsUserActivityKey"]; - [launchOptions setObject:userActivityDict forKey:UIApplicationLaunchOptionsUserActivityDictionaryKey]; - - if (appBooted) { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; - } else { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; - }); - } - - return YES; + } + + if ([userActivity title] != nil) { + [dict setObject:[userActivity title] forKey:@"title"]; + } + + if ([userActivity webpageURL] != nil) { + [dict setObject:[[userActivity webpageURL] absoluteString] forKey:@"webpageURL"]; + } + + if ([userActivity userInfo] != nil) { + [dict setObject:[userActivity userInfo] forKey:@"userInfo"]; + } + + // Update launchOptions so that we send only expected values rather than NSUserActivity + NSMutableDictionary *userActivityDict = [NSMutableDictionary dictionaryWithDictionary:launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]]; + [userActivityDict setObject:dict forKey:@"UIApplicationLaunchOptionsUserActivityKey"]; + [launchOptions setObject:userActivityDict forKey:UIApplicationLaunchOptionsUserActivityDictionaryKey]; + + if (appBooted) { + [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; + } else { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; + }); + } + + return YES; } #endif @@ -1157,352 +1138,346 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { - // NOTE: this is called when the app is *running* after receiving a push notification - // otherwise, if the app is started from a push notification, this method will not be - // called - RELEASE_TO_NIL(remoteNotification); - [self generateNotification:userInfo]; - - if (remoteNotificationDelegate!=nil) - { - [remoteNotificationDelegate performSelector:@selector(application:didReceiveRemoteNotification:) withObject:application withObject:remoteNotification]; - } + // NOTE: this is called when the app is *running* after receiving a push notification + // otherwise, if the app is started from a push notification, this method will not be + // called + RELEASE_TO_NIL(remoteNotification); + [self generateNotification:userInfo]; + + if (remoteNotificationDelegate != nil) { + [remoteNotificationDelegate performSelector:@selector(application:didReceiveRemoteNotification:) withObject:application withObject:remoteNotification]; + } } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken -{ - NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<"withString:@""] - stringByReplacingOccurrencesOfString:@">" withString:@""] - stringByReplacingOccurrencesOfString: @" " withString: @""]; - - RELEASE_TO_NIL(remoteDeviceUUID); - remoteDeviceUUID = [token copy]; - - NSString *curKey = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; - if (curKey==nil || ![curKey isEqualToString:remoteDeviceUUID]) - { - // this is the first time being registered, we need to indicate to our backend that we have a - // new registered device to enable this device to receive notifications from the cloud - [[NSUserDefaults standardUserDefaults] setObject:remoteDeviceUUID forKey:@"APNSRemoteDeviceUUID"]; - NSDictionary *userInfo = [NSDictionary dictionaryWithObject:remoteDeviceUUID forKey:@"deviceid"]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteDeviceUUIDNotification object:self userInfo:userInfo]; - DebugLog(@"[DEBUG] Registered new device for remote push notifications: %@",remoteDeviceUUID); - } - - if (remoteNotificationDelegate!=nil) - { - [remoteNotificationDelegate performSelector:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:) withObject:application withObject:deviceToken]; - } +{ + NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<" withString:@""] + stringByReplacingOccurrencesOfString:@">" + withString:@""] + stringByReplacingOccurrencesOfString:@" " + withString:@""]; + + RELEASE_TO_NIL(remoteDeviceUUID); + remoteDeviceUUID = [token copy]; + + NSString *curKey = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; + if (curKey == nil || ![curKey isEqualToString:remoteDeviceUUID]) { + // this is the first time being registered, we need to indicate to our backend that we have a + // new registered device to enable this device to receive notifications from the cloud + [[NSUserDefaults standardUserDefaults] setObject:remoteDeviceUUID forKey:@"APNSRemoteDeviceUUID"]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:remoteDeviceUUID forKey:@"deviceid"]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteDeviceUUIDNotification object:self userInfo:userInfo]; + DebugLog(@"[DEBUG] Registered new device for remote push notifications: %@", remoteDeviceUUID); + } + + if (remoteNotificationDelegate != nil) { + [remoteNotificationDelegate performSelector:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:) withObject:application withObject:deviceToken]; + } } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { - if (remoteNotificationDelegate!=nil) - { - [remoteNotificationDelegate performSelector:@selector(application:didFailToRegisterForRemoteNotificationsWithError:) withObject:application withObject:error]; - } + if (remoteNotificationDelegate != nil) { + [remoteNotificationDelegate performSelector:@selector(application:didFailToRegisterForRemoteNotificationsWithError:) withObject:application withObject:error]; + } } #endif //TODO: this should be compiled out in production mode --(void)showModalError:(NSString*)message +- (void)showModalError:(NSString *)message { - if (TI_APPLICATION_SHOW_ERROR_CONTROLLER == NO) - { - NSLog(@"[ERROR] Application received error: %@",message); - return; - } - ENSURE_UI_THREAD(showModalError,message); - TiErrorController *error = [[[TiErrorController alloc] initWithError:message] autorelease]; - [self showModalController:error animated:YES]; + if (TI_APPLICATION_SHOW_ERROR_CONTROLLER == NO) { + NSLog(@"[ERROR] Application received error: %@", message); + return; + } + ENSURE_UI_THREAD(showModalError, message); + TiErrorController *error = [[[TiErrorController alloc] initWithError:message] autorelease]; + [self showModalController:error animated:YES]; } --(void)showModalController:(UIViewController*)modalController animated:(BOOL)animated +- (void)showModalController:(UIViewController *)modalController animated:(BOOL)animated { - [controller showControllerModal:modalController animated:animated]; + [controller showControllerModal:modalController animated:animated]; } --(void)hideModalController:(UIViewController*)modalController animated:(BOOL)animated +- (void)hideModalController:(UIViewController *)modalController animated:(BOOL)animated { - [controller hideControllerModal:modalController animated:animated]; + [controller hideControllerModal:modalController animated:animated]; } - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { - if ([self windowIsKeyWindow]) { - return [controller supportedOrientationsForAppDelegate]; - } - - //UIInterfaceOrientationMaskAll = 30; - return 30; + if ([self windowIsKeyWindow]) { + return [controller supportedOrientationsForAppDelegate]; + } + + //UIInterfaceOrientationMaskAll = 30; + return 30; } -- (void)dealloc +- (void)dealloc { - RELEASE_TO_NIL(kjsBridge); + RELEASE_TO_NIL(kjsBridge); #ifdef USE_TI_UIWEBVIEW - RELEASE_TO_NIL(xhrBridge); -#endif - RELEASE_TO_NIL(loadView); - RELEASE_TO_NIL(window); - RELEASE_TO_NIL(launchOptions); - RELEASE_TO_NIL(controller); - RELEASE_TO_NIL(userAgent); - RELEASE_TO_NIL(remoteDeviceUUID); - RELEASE_TO_NIL(remoteNotification); - RELEASE_TO_NIL(splashScreenImage); + RELEASE_TO_NIL(xhrBridge); +#endif + RELEASE_TO_NIL(loadView); + RELEASE_TO_NIL(window); + RELEASE_TO_NIL(launchOptions); + RELEASE_TO_NIL(controller); + RELEASE_TO_NIL(userAgent); + RELEASE_TO_NIL(remoteDeviceUUID); + RELEASE_TO_NIL(remoteNotification); + RELEASE_TO_NIL(splashScreenImage); #ifndef USE_JSCORE_FRAMEWORK - if ([self debugMode]) { - TiDebuggerStop(); - } + if ([self debugMode]) { + TiDebuggerStop(); + } #endif - RELEASE_TO_NIL(backgroundServices); - RELEASE_TO_NIL(localNotification); - [super dealloc]; + RELEASE_TO_NIL(backgroundServices); + RELEASE_TO_NIL(localNotification); + [super dealloc]; } -- (NSString*)systemUserAgent +- (NSString *)systemUserAgent { - UIDevice *currentDevice = [UIDevice currentDevice]; - NSString *currentLocaleIdentifier = [[NSLocale currentLocale] localeIdentifier]; - NSString *currentDeviceInfo = [NSString stringWithFormat:@"%@/%@; %@; %@;",[currentDevice model],[currentDevice systemVersion],[currentDevice systemName],currentLocaleIdentifier]; - NSString *kTitaniumUserAgentPrefix = [NSString stringWithFormat:@"%s%s%s %s%s","Appc","eler","ator","Tita","nium"]; - return [NSString stringWithFormat:@"%@/%s (%@)",kTitaniumUserAgentPrefix,TI_VERSION_STR,currentDeviceInfo]; + UIDevice *currentDevice = [UIDevice currentDevice]; + NSString *currentLocaleIdentifier = [[NSLocale currentLocale] localeIdentifier]; + NSString *currentDeviceInfo = [NSString stringWithFormat:@"%@/%@; %@; %@;", [currentDevice model], [currentDevice systemVersion], [currentDevice systemName], currentLocaleIdentifier]; + NSString *kTitaniumUserAgentPrefix = [NSString stringWithFormat:@"%s%s%s %s%s", "Appc", "eler", "ator", "Tita", "nium"]; + return [NSString stringWithFormat:@"%@/%s (%@)", kTitaniumUserAgentPrefix, TI_VERSION_STR, currentDeviceInfo]; } -- (NSString*)userAgent +- (NSString *)userAgent { - return !userAgent ? [self systemUserAgent] : userAgent; + return !userAgent ? [self systemUserAgent] : userAgent; } --(NSString*)remoteDeviceUUID +- (NSString *)remoteDeviceUUID { - return remoteDeviceUUID; + return remoteDeviceUUID; } --(NSString*)sessionId +- (NSString *)sessionId { - return sessionId; + return sessionId; } --(KrollBridge*)krollBridge +- (KrollBridge *)krollBridge { - return kjsBridge; + return kjsBridge; } #pragma mark Backgrounding --(void)beginBackgrounding +- (void)beginBackgrounding { - if (runningServices == nil) { - runningServices = [[NSMutableArray alloc] initWithCapacity:[backgroundServices count]]; - } - - for (TiProxy *proxy in backgroundServices) - { - [runningServices addObject:proxy]; - [proxy performSelector:@selector(beginBackground)]; - } - [self checkBackgroundServices]; + if (runningServices == nil) { + runningServices = [[NSMutableArray alloc] initWithCapacity:[backgroundServices count]]; + } + + for (TiProxy *proxy in backgroundServices) { + [runningServices addObject:proxy]; + [proxy performSelector:@selector(beginBackground)]; + } + [self checkBackgroundServices]; } --(void)endBackgrounding +- (void)endBackgrounding { - for (TiProxy *proxy in backgroundServices) - { - [proxy performSelector:@selector(endBackground)]; - [runningServices removeObject:proxy]; - } + for (TiProxy *proxy in backgroundServices) { + [proxy performSelector:@selector(endBackground)]; + [runningServices removeObject:proxy]; + } - [self checkBackgroundServices]; - RELEASE_TO_NIL(runningServices); + [self checkBackgroundServices]; + RELEASE_TO_NIL(runningServices); } --(BOOL)handleShortcutItem:(UIApplicationShortcutItem*) shortcutItem - waitForBootIfNotLaunched:(BOOL) bootWait { - - - if(shortcutItem.type == nil) { - NSLog(@"[ERROR] The shortcut type property is required"); - return NO; - } - - NSMutableDictionary *dict = [NSMutableDictionary - dictionaryWithObjectsAndKeys:shortcutItem.type,@"type", - nil]; - - if (shortcutItem.localizedTitle !=nil) { - [dict setObject:shortcutItem.localizedTitle forKey:@"title" ]; - } - - if (shortcutItem.localizedSubtitle !=nil) { - [dict setObject:shortcutItem.localizedSubtitle forKey:@"subtitle" ]; - } - - if(shortcutItem.userInfo !=nil) { - [dict setObject:shortcutItem.userInfo forKey:@"userInfo"]; - } - - // Update launchOptions to include the mapped dictionary-shortcut instead of the UIShortcutItem - [launchOptions setObject:dict forKey:UIApplicationLaunchOptionsShortcutItemKey]; - - if (appBooted) { +- (BOOL)handleShortcutItem:(UIApplicationShortcutItem *)shortcutItem + waitForBootIfNotLaunched:(BOOL)bootWait +{ + + if (shortcutItem.type == nil) { + NSLog(@"[ERROR] The shortcut type property is required"); + return NO; + } + + NSMutableDictionary *dict = [NSMutableDictionary + dictionaryWithObjectsAndKeys:shortcutItem.type, @"type", + nil]; + + if (shortcutItem.localizedTitle != nil) { + [dict setObject:shortcutItem.localizedTitle forKey:@"title"]; + } + + if (shortcutItem.localizedSubtitle != nil) { + [dict setObject:shortcutItem.localizedSubtitle forKey:@"subtitle"]; + } + + if (shortcutItem.userInfo != nil) { + [dict setObject:shortcutItem.userInfo forKey:@"userInfo"]; + } + + // Update launchOptions to include the mapped dictionary-shortcut instead of the UIShortcutItem + [launchOptions setObject:dict forKey:UIApplicationLaunchOptionsShortcutItemKey]; + + if (appBooted) { + [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationShortcut + object:self + userInfo:dict]; + } else { + if (bootWait) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationShortcut - object:self userInfo:dict]; - } else { - if(bootWait) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationShortcut - object:self userInfo:dict]; - }); - } + object:self + userInfo:dict]; + }); } - - return YES; + } + + return YES; } - (void)application:(UIApplication *)application -performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem - completionHandler:(void (^)(BOOL succeeded))completionHandler + performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler { - - BOOL handledShortCutItem = [self handleShortcutItem:shortcutItem waitForBootIfNotLaunched:NO]; - completionHandler(handledShortCutItem); - + + BOOL handledShortCutItem = [self handleShortcutItem:shortcutItem waitForBootIfNotLaunched:NO]; + completionHandler(handledShortCutItem); } --(void)registerBackgroundService:(TiProxy*)proxy +- (void)registerBackgroundService:(TiProxy *)proxy { - if (backgroundServices==nil) - { - backgroundServices = [[NSMutableArray alloc] initWithCapacity:1]; - } - - //Only add if it isn't already added - if (![backgroundServices containsObject:proxy]) { - [backgroundServices addObject:proxy]; - } + if (backgroundServices == nil) { + backgroundServices = [[NSMutableArray alloc] initWithCapacity:1]; + } + + //Only add if it isn't already added + if (![backgroundServices containsObject:proxy]) { + [backgroundServices addObject:proxy]; + } } --(void)checkBackgroundServices +- (void)checkBackgroundServices { - if ([runningServices count] == 0) - { - // Synchronize the cleanup call on the main thread in case - // the expiration handler is fired at the same time. - TiThreadPerformOnMainThread( ^{ - if (bgTask != UIBackgroundTaskInvalid) - { - [[UIApplication sharedApplication] endBackgroundTask:bgTask]; - bgTask = UIBackgroundTaskInvalid; - } - }, NO); - } + if ([runningServices count] == 0) { + // Synchronize the cleanup call on the main thread in case + // the expiration handler is fired at the same time. + TiThreadPerformOnMainThread(^{ + if (bgTask != UIBackgroundTaskInvalid) { + [[UIApplication sharedApplication] endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + } + }, + NO); + } } --(void)unregisterBackgroundService:(TiProxy*)proxy +- (void)unregisterBackgroundService:(TiProxy *)proxy { - [backgroundServices removeObject:proxy]; - [runningServices removeObject:proxy]; - [self checkBackgroundServices]; + [backgroundServices removeObject:proxy]; + [runningServices removeObject:proxy]; + [self checkBackgroundServices]; } --(void)stopBackgroundService:(TiProxy *)proxy +- (void)stopBackgroundService:(TiProxy *)proxy { - [runningServices removeObject:proxy]; - [self checkBackgroundServices]; + [runningServices removeObject:proxy]; + [self checkBackgroundServices]; } -#define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) +#define NOTNIL(v) ((v == nil) ? (id)[NSNull null] : v) #if IS_XCODE_8 -+ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier: (NSString *)identifier -{ - if (notification == nil) { - return nil; - } - NSMutableDictionary* event = [NSMutableDictionary dictionary]; - - [event setObject:NOTNIL([notification date]) forKey:@"date"]; - [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; - [event setObject:NOTNIL([[[notification request] content] body]) forKey:@"alertBody"]; - [event setObject:NOTNIL([[[notification request] content] title]) forKey:@"alertTitle"]; - [event setObject:NOTNIL([[[notification request] content] subtitle]) forKey:@"alertSubtitle"]; - [event setObject:NOTNIL([[[notification request] content] launchImageName]) forKey:@"alertLaunchImage"]; - [event setObject:NOTNIL([[[notification request] content] sound]) forKey:@"sound"]; - [event setObject:NOTNIL([[[notification request] content] badge]) forKey:@"badge"]; - [event setObject:NOTNIL([[[notification request] content] userInfo]) forKey:@"userInfo"]; - [event setObject:NOTNIL([[[notification request] content] categoryIdentifier]) forKey:@"category"]; - [event setObject:NOTNIL([[notification request] identifier]) forKey:@"identifier"]; - - return event; ++ (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier:(NSString *)identifier +{ + if (notification == nil) { + return nil; + } + NSMutableDictionary *event = [NSMutableDictionary dictionary]; + + [event setObject:NOTNIL([notification date]) forKey:@"date"]; + [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; + [event setObject:NOTNIL([[[notification request] content] body]) forKey:@"alertBody"]; + [event setObject:NOTNIL([[[notification request] content] title]) forKey:@"alertTitle"]; + [event setObject:NOTNIL([[[notification request] content] subtitle]) forKey:@"alertSubtitle"]; + [event setObject:NOTNIL([[[notification request] content] launchImageName]) forKey:@"alertLaunchImage"]; + [event setObject:NOTNIL([[[notification request] content] sound]) forKey:@"sound"]; + [event setObject:NOTNIL([[[notification request] content] badge]) forKey:@"badge"]; + [event setObject:NOTNIL([[[notification request] content] userInfo]) forKey:@"userInfo"]; + [event setObject:NOTNIL([[[notification request] content] categoryIdentifier]) forKey:@"category"]; + [event setObject:NOTNIL([[notification request] identifier]) forKey:@"identifier"]; + + return event; } #endif -+ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier: (NSString *)identifier ++ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier:(NSString *)identifier { - if (notification == nil) { - return nil; - } - NSMutableDictionary* event = [NSMutableDictionary dictionary]; - [event setObject:NOTNIL([notification fireDate]) forKey:@"date"]; - [event setObject:NOTNIL([[notification timeZone] name]) forKey:@"timezone"]; - [event setObject:NOTNIL([notification alertBody]) forKey:@"alertBody"]; - [event setObject:NOTNIL([notification alertAction]) forKey:@"alertAction"]; - [event setObject:NOTNIL([notification alertLaunchImage]) forKey:@"alertLaunchImage"]; - [event setObject:NOTNIL([notification soundName]) forKey:@"sound"]; - [event setObject:NUMINTEGER([notification applicationIconBadgeNumber]) forKey:@"badge"]; - [event setObject:NOTNIL([notification userInfo]) forKey:@"userInfo"]; - - // Include category for iOS 8 - if ([TiUtils isIOS8OrGreater]) { - [event setObject:NOTNIL([notification category]) forKey:@"category"]; - } - - // Include title for iOS 8.2 - if ([TiUtils isIOS82rGreater]) { - [event setObject:NOTNIL([notification alertTitle]) forKey:@"alertTitle"]; - } - - return event; + if (notification == nil) { + return nil; + } + NSMutableDictionary *event = [NSMutableDictionary dictionary]; + [event setObject:NOTNIL([notification fireDate]) forKey:@"date"]; + [event setObject:NOTNIL([[notification timeZone] name]) forKey:@"timezone"]; + [event setObject:NOTNIL([notification alertBody]) forKey:@"alertBody"]; + [event setObject:NOTNIL([notification alertAction]) forKey:@"alertAction"]; + [event setObject:NOTNIL([notification alertLaunchImage]) forKey:@"alertLaunchImage"]; + [event setObject:NOTNIL([notification soundName]) forKey:@"sound"]; + [event setObject:NUMINTEGER([notification applicationIconBadgeNumber]) forKey:@"badge"]; + [event setObject:NOTNIL([notification userInfo]) forKey:@"userInfo"]; + + // Include category for iOS 8 + if ([TiUtils isIOS8OrGreater]) { + [event setObject:NOTNIL([notification category]) forKey:@"category"]; + } + + // Include title for iOS 8.2 + if ([TiUtils isIOS82rGreater]) { + [event setObject:NOTNIL([notification alertTitle]) forKey:@"alertTitle"]; + } + + return event; } // Returns an NSDictionary with the properties from tiapp.xml // this is called from Ti.App.Properties and other places. -+(NSDictionary *)tiAppProperties -{ - static NSDictionary* props; - - if(props == nil) { - // Get the props from the encrypted json file - NSString *tiAppPropertiesPath = [[TiHost resourcePath] stringByAppendingPathComponent:@"_app_props_.json"]; - NSData *jsonData = [TiUtils loadAppResource: [NSURL fileURLWithPath:tiAppPropertiesPath]]; - - if (jsonData==nil) { - // Not found in encrypted file, this means we're in development mode, get it from the filesystem - jsonData = [NSData dataWithContentsOfFile:tiAppPropertiesPath]; - } - - NSString *errorString = nil; - // Get the JSON data and create the NSDictionary. - if(jsonData) { - NSError *error = nil; - props = [[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error] retain]; - errorString = [error localizedDescription]; - } else { - // If we have no data... - // This should never happen on a Titanium app using the node.js CLI - errorString = @"File not found"; - } - if(errorString != nil) { - // Let the developer know that we could not load the tiapp.xml properties. - DebugLog(@"[ERROR] Could not load tiapp.xml properties, error was %@", errorString); - // Create an empty dictioary to avoid running this code over and over again. - props = [[NSDictionary dictionary] retain]; - } ++ (NSDictionary *)tiAppProperties +{ + static NSDictionary *props; + + if (props == nil) { + // Get the props from the encrypted json file + NSString *tiAppPropertiesPath = [[TiHost resourcePath] stringByAppendingPathComponent:@"_app_props_.json"]; + NSData *jsonData = [TiUtils loadAppResource:[NSURL fileURLWithPath:tiAppPropertiesPath]]; + + if (jsonData == nil) { + // Not found in encrypted file, this means we're in development mode, get it from the filesystem + jsonData = [NSData dataWithContentsOfFile:tiAppPropertiesPath]; + } + + NSString *errorString = nil; + // Get the JSON data and create the NSDictionary. + if (jsonData) { + NSError *error = nil; + props = [[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error] retain]; + errorString = [error localizedDescription]; + } else { + // If we have no data... + // This should never happen on a Titanium app using the node.js CLI + errorString = @"File not found"; + } + if (errorString != nil) { + // Let the developer know that we could not load the tiapp.xml properties. + DebugLog(@"[ERROR] Could not load tiapp.xml properties, error was %@", errorString); + // Create an empty dictioary to avoid running this code over and over again. + props = [[NSDictionary dictionary] retain]; } - return props; + } + return props; } @end diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index 6f3176a8d64..b3351fb2ff3 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -12,15 +12,14 @@ #endif @interface TiAppiOSLocalNotificationProxy : TiProxy { -@private - id _notification; + @private + id _notification; } -@property(nonatomic,retain) id notification; +@property (nonatomic, retain) id notification; --(void)cancel:(id)used; +- (void)cancel:(id)used; @end - #endif diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 82e609e8055..1ea6091c3ef 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -13,33 +13,34 @@ @implementation TiAppiOSLocalNotificationProxy @synthesize notification = _notification; --(void)dealloc +- (void)dealloc { - RELEASE_TO_NIL(_notification); - [super dealloc]; + RELEASE_TO_NIL(_notification); + [super dealloc]; } --(NSString*)apiName +- (NSString *)apiName { - return @"Ti.App.iOS.LocalNotification"; + return @"Ti.App.iOS.LocalNotification"; } --(void)cancel:(id)unused +- (void)cancel:(id)unused { - DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); - - if ([TiUtils isIOS10OrGreater]) { + DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); - return; + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + return; #endif - } else { - UILocalNotification * cancelledNotification = [self.notification retain]; - TiThreadPerformOnMainThread(^{ - [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; - [cancelledNotification release]; - }, NO); - } + } else { + UILocalNotification *cancelledNotification = [self.notification retain]; + TiThreadPerformOnMainThread(^{ + [[UIApplication sharedApplication] cancelLocalNotification:cancelledNotification]; + [cancelledNotification release]; + }, + NO); + } } @end diff --git a/iphone/Classes/TiAppiOSProxy.h b/iphone/Classes/TiAppiOSProxy.h index 2724e1a51fe..9065a6b4bee 100644 --- a/iphone/Classes/TiAppiOSProxy.h +++ b/iphone/Classes/TiAppiOSProxy.h @@ -11,11 +11,11 @@ #import "TiAppiOSBackgroundServiceProxy.h" @interface TiAppiOSProxy : TiProxy { -@private - NSMutableDictionary *backgroundServices; - + @private + NSMutableDictionary *backgroundServices; + #ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER - TiProxy *UserNotificationCenter; + TiProxy *UserNotificationCenter; #endif } @property (nonatomic, readonly) NSString *EVENT_ACCESSIBILITY_LAYOUT_CHANGED; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 0a99aeef85e..c2977c4d2cd 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -6,19 +6,19 @@ */ #import "TiAppiOSProxy.h" -#import "TiUtils.h" #import "TiApp.h" +#import "TiUtils.h" #ifdef USE_TI_APPIOS #import "TiAppiOSBackgroundServiceProxy.h" #import "TiAppiOSLocalNotificationProxy.h" -#import "TiAppiOSUserNotificationActionProxy.h" -#import "TiAppiOSUserNotificationCategoryProxy.h" -#import "TiAppiOSUserDefaultsProxy.h" -#import "TiAppiOSUserActivityProxy.h" +#import "TiAppiOSSearchableIndexProxy.h" #import "TiAppiOSSearchableItemAttributeSetProxy.h" #import "TiAppiOSSearchableItemProxy.h" -#import "TiAppiOSSearchableIndexProxy.h" +#import "TiAppiOSUserActivityProxy.h" +#import "TiAppiOSUserDefaultsProxy.h" +#import "TiAppiOSUserNotificationActionProxy.h" +#import "TiAppiOSUserNotificationCategoryProxy.h" #ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER #import "TiAppiOSUserNotificationCenterProxy.h" @@ -34,1295 +34,1314 @@ #endif #endif -#import #import +#import @implementation TiAppiOSProxy --(void)dealloc +- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - RELEASE_TO_NIL(backgroundServices); - [super dealloc]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + RELEASE_TO_NIL(backgroundServices); + [super dealloc]; } --(NSString*)apiName +- (NSString *)apiName { - return @"Ti.App.iOS"; + return @"Ti.App.iOS"; } --(void)_listenerAdded:(NSString*)type count:(int)count +- (void)_listenerAdded:(NSString *)type count:(int)count { - if (count == 1 && [type isEqual:@"notification"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:kTiLocalNotification object:nil]; - } - if (count == 1 && [type isEqual:@"localnotificationaction"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotificationAction:) name:kTiLocalNotificationAction object:nil]; - } - if (count == 1 && [type isEqual:@"remotenotificationaction"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveRemoteNotificationAction:) name:kTiRemoteNotificationAction object:nil]; - } - if (count == 1 && [type isEqual:@"remoteextentionwillexpire"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteExtensionWillExpire:) name:kTiRemoteExtentionWillExpire object:nil]; - } - if ((count == 1) && [type isEqual:@"backgroundfetch"]) { - NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - if ([backgroundModes containsObject:@"fetch"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveBackgroundFetchNotification:) name:kTiBackgroundFetchNotification object:nil]; - } else { - DebugLog(@"[ERROR] Cannot add backgroundfetch eventListener. Please add `fetch` to UIBackgroundModes inside info.plist "); - } - } - if ((count == 1) && [type isEqual:@"silentpush"]) { - NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - if ([backgroundModes containsObject:@"remote-notification"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSilentPushNotification:) name:kTiSilentPushNotification object:nil]; - } else { - DebugLog(@"[ERROR] Cannot add silentpush eventListener. Please add `remote-notification` to UIBackgroundModes inside info.plist "); - } - } - if ((count == 1) && [type isEqual:@"backgroundtransfer"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveBackgroundTransferNotification:) name:kTiBackgroundTransfer object:nil]; - } - if ((count == 1) && [type isEqual:@"downloadcompleted"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveDownloadFinishedNotification:) name:kTiURLDownloadFinished object:nil]; - } - if ((count == 1) && [type isEqual:@"sessioncompleted"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSessionCompletedNotification:) name:kTiURLSessionCompleted object:nil]; - } - if ((count ==1) && [type isEqual:@"sessioneventscompleted"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSessionEventsCompletedNotification:) name:kTiURLSessionEventsCompleted object:nil]; - } - if ((count == 1) && [type isEqual:@"downloadprogress"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveDownloadProgressNotification:) name:kTiURLDowloadProgress object:nil]; - } - if ((count == 1) && [type isEqual:@"uploadprogress"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveUploadProgressNotification:) name:kTiURLUploadProgress object:nil]; - } - if ([TiUtils isIOS8OrGreater]){ - if ((count == 1) && [type isEqual:@"usernotificationsettings"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector - (didRegisterUserNotificationSettingsNotification:) name:kTiUserNotificationSettingsNotification object:nil]; - } - if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didReceiveWatchExtensionRequestNotification:) name:kTiWatchKitExtensionRequest object:nil]; - } - if ((count == 1) && [type isEqual:@"continueactivity"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveContinueActivityNotification:) name:kTiContinueActivity object:nil]; - } - } - - if([TiUtils isIOS9OrGreater]){ - if ((count == 1) && [type isEqual:@"shortcutitemclick"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector - (didReceiveApplicationShortcutNotification:) name:kTiApplicationShortcut object:nil]; - } - } - - if ((count == 1) && [type isEqual:@"handleurl"]) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didHandleURL:) - name:kTiApplicationLaunchedFromURL - object:nil]; + if (count == 1 && [type isEqual:@"notification"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:kTiLocalNotification object:nil]; + } + if (count == 1 && [type isEqual:@"localnotificationaction"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotificationAction:) name:kTiLocalNotificationAction object:nil]; + } + if (count == 1 && [type isEqual:@"remotenotificationaction"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveRemoteNotificationAction:) name:kTiRemoteNotificationAction object:nil]; + } + if (count == 1 && [type isEqual:@"remoteextentionwillexpire"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteExtensionWillExpire:) name:kTiRemoteExtentionWillExpire object:nil]; + } + if ((count == 1) && [type isEqual:@"backgroundfetch"]) { + NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; + if ([backgroundModes containsObject:@"fetch"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveBackgroundFetchNotification:) name:kTiBackgroundFetchNotification object:nil]; + } else { + DebugLog(@"[ERROR] Cannot add backgroundfetch eventListener. Please add `fetch` to UIBackgroundModes inside info.plist "); } + } + if ((count == 1) && [type isEqual:@"silentpush"]) { + NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; + if ([backgroundModes containsObject:@"remote-notification"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSilentPushNotification:) name:kTiSilentPushNotification object:nil]; + } else { + DebugLog(@"[ERROR] Cannot add silentpush eventListener. Please add `remote-notification` to UIBackgroundModes inside info.plist "); + } + } + if ((count == 1) && [type isEqual:@"backgroundtransfer"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveBackgroundTransferNotification:) name:kTiBackgroundTransfer object:nil]; + } + if ((count == 1) && [type isEqual:@"downloadcompleted"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveDownloadFinishedNotification:) name:kTiURLDownloadFinished object:nil]; + } + if ((count == 1) && [type isEqual:@"sessioncompleted"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSessionCompletedNotification:) name:kTiURLSessionCompleted object:nil]; + } + if ((count == 1) && [type isEqual:@"sessioneventscompleted"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveSessionEventsCompletedNotification:) name:kTiURLSessionEventsCompleted object:nil]; + } + if ((count == 1) && [type isEqual:@"downloadprogress"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveDownloadProgressNotification:) name:kTiURLDowloadProgress object:nil]; + } + if ((count == 1) && [type isEqual:@"uploadprogress"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveUploadProgressNotification:) name:kTiURLUploadProgress object:nil]; + } + if ([TiUtils isIOS8OrGreater]) { + if ((count == 1) && [type isEqual:@"usernotificationsettings"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector + (didRegisterUserNotificationSettingsNotification:) + name:kTiUserNotificationSettingsNotification + object:nil]; + } + if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveWatchExtensionRequestNotification:) + name:kTiWatchKitExtensionRequest + object:nil]; + } + if ((count == 1) && [type isEqual:@"continueactivity"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveContinueActivityNotification:) name:kTiContinueActivity object:nil]; + } + } + + if ([TiUtils isIOS9OrGreater]) { + if ((count == 1) && [type isEqual:@"shortcutitemclick"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector + (didReceiveApplicationShortcutNotification:) + name:kTiApplicationShortcut + object:nil]; + } + } + + if ((count == 1) && [type isEqual:@"handleurl"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didHandleURL:) + name:kTiApplicationLaunchedFromURL + object:nil]; + } +} + +- (void)_listenerRemoved:(NSString *)type count:(int)count +{ + if (count == 0 && [type isEqual:@"notification"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiLocalNotification object:nil]; + } + if (count == 0 && [type isEqual:@"localnotificationaction"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiLocalNotificationAction object:nil]; + } + if (count == 0 && [type isEqual:@"remotenotificationaction"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiRemoteNotificationAction object:nil]; + } + + if ((count == 1) && [type isEqual:@"backgroundfetch"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundFetchNotification object:nil]; + } + if ((count == 1) && [type isEqual:@"sessioneventscompleted"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLSessionEventsCompleted object:nil]; + } + if ((count == 1) && [type isEqual:@"silentpush"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiSilentPushNotification object:nil]; + } + if ((count == 1) && [type isEqual:@"backgroundtransfer"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundTransfer object:nil]; + } + if ((count == 1) && [type isEqual:@"sessioncompleted"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLSessionCompleted object:nil]; + } + if ((count == 1) && [type isEqual:@"downloadfinished"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLDownloadFinished object:nil]; + } + if ((count == 1) && [type isEqual:@"downloadprogress"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLDowloadProgress object:nil]; + } + if ((count == 1) && [type isEqual:@"uploadprogress"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLUploadProgress object:nil]; + } + + if ([TiUtils isIOS8OrGreater]) { + if ((count == 1) && [type isEqual:@"usernotificationsetting"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiUserNotificationSettingsNotification object:nil]; + } + if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiWatchKitExtensionRequest object:nil]; + } + if ((count == 1) && [type isEqual:@"continueactivity"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiContinueActivity object:nil]; + } + } + + if ([TiUtils isIOS9OrGreater]) { + if ((count == 1) && [type isEqual:@"shortcutitemclick"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiApplicationShortcut object:nil]; + } + } } --(void)_listenerRemoved:(NSString*)type count:(int)count +#pragma mark Public + +- (void)didReceiveApplicationShortcutNotification:(NSNotification *)info { - if (count == 0 && [type isEqual:@"notification"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiLocalNotification object:nil]; - } - if (count == 0 && [type isEqual:@"localnotificationaction"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiLocalNotificationAction object:nil]; - } - if (count == 0 && [type isEqual:@"remotenotificationaction"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiRemoteNotificationAction object:nil]; - } + NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary:@{ + @"title" : [[info userInfo] valueForKey:@"title"], + @"itemtype" : [[info userInfo] valueForKey:@"type"] + }]; - if ((count == 1) && [type isEqual:@"backgroundfetch"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundFetchNotification object:nil]; - } - if ((count == 1) && [type isEqual:@"sessioneventscompleted"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLSessionEventsCompleted object:nil]; - } - if ((count == 1) && [type isEqual:@"silentpush"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiSilentPushNotification object:nil]; - } - if ((count == 1) && [type isEqual:@"backgroundtransfer"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundTransfer object:nil]; - } - if ((count == 1) && [type isEqual:@"sessioncompleted"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLSessionCompleted object:nil]; - } - if ((count == 1) && [type isEqual:@"downloadfinished"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLDownloadFinished object:nil]; - } - if ((count == 1) && [type isEqual:@"downloadprogress"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLDowloadProgress object:nil]; - } - if ((count == 1) && [type isEqual:@"uploadprogress"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLUploadProgress object:nil]; - } - - if ([TiUtils isIOS8OrGreater]){ - if ((count == 1) && [type isEqual:@"usernotificationsetting"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiUserNotificationSettingsNotification object:nil]; - } - if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiWatchKitExtensionRequest object:nil]; - } - if ((count == 1) && [type isEqual:@"continueactivity"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiContinueActivity object:nil]; - } - } - - if([TiUtils isIOS9OrGreater]){ - if ((count == 1) && [type isEqual:@"shortcutitemclick"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiApplicationShortcut object:nil]; - } - } - -} + if ([[info userInfo] valueForKey:@"subtitle"] != nil) { + [event setValue:[[info userInfo] valueForKey:@"subtitle"] forKey:@"subtitle"]; + } -#pragma mark Public + if ([[info userInfo] objectForKey:@"userInfo"] != nil) { + [event setValue:[[info userInfo] objectForKey:@"userInfo"] forKey:@"userInfo"]; + } --(void)didReceiveApplicationShortcutNotification:(NSNotification*)info -{ - NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary: @{ - @"title" : [[info userInfo] valueForKey:@"title"], - @"itemtype" : [[info userInfo] valueForKey:@"type"] - }]; - - if ([[info userInfo] valueForKey:@"subtitle"] != nil) { - [event setValue:[[info userInfo] valueForKey:@"subtitle"] forKey:@"subtitle"]; - } - - if ([[info userInfo] objectForKey:@"userInfo"] != nil) { - [event setValue:[[info userInfo] objectForKey:@"userInfo"] forKey:@"userInfo"]; - } - - [self fireEvent:@"shortcutitemclick" withObject:event]; - RELEASE_TO_NIL(event); + [self fireEvent:@"shortcutitemclick" withObject:event]; + RELEASE_TO_NIL(event); } #ifdef USE_TI_APPIOSUSERNOTIFICATIONCENTER --(id)UserNotificationCenter +- (id)UserNotificationCenter { - if (UserNotificationCenter == nil) { - UserNotificationCenter = [[TiAppiOSUserNotificationCenterProxy alloc] _initWithPageContext:[self executionContext]]; - [self rememberProxy:UserNotificationCenter]; - } - return UserNotificationCenter; + if (UserNotificationCenter == nil) { + UserNotificationCenter = [[TiAppiOSUserNotificationCenterProxy alloc] _initWithPageContext:[self executionContext]]; + [self rememberProxy:UserNotificationCenter]; + } + return UserNotificationCenter; } #endif --(void)didHandleURL:(NSNotification*)info +- (void)didHandleURL:(NSNotification *)info { - [self fireEvent:@"handleurl" withObject:@{ - @"launchOptions": [info userInfo] - }]; + [self fireEvent:@"handleurl" + withObject:@{ + @"launchOptions" : [info userInfo] + }]; } #ifdef USE_TI_APPIOSSEARCHABLEINDEX --(id)createSearchableIndex:(id)unused +- (id)createSearchableIndex:(id)unused { - if (![TiUtils isIOS9OrGreater]) { - return nil; - } - - return [[[TiAppiOSSearchableIndexProxy alloc]init] autorelease];; + if (![TiUtils isIOS9OrGreater]) { + return nil; + } + + return [[[TiAppiOSSearchableIndexProxy alloc] init] autorelease]; + ; } #endif #ifdef USE_TI_APPIOSSEARCHABLEITEM --(id)createSearchableItem:(id)args +- (id)createSearchableItem:(id)args { - if (![TiUtils isIOS9OrGreater]) { - return nil; - } - if (![NSThread isMainThread]) { - __block id result; - TiThreadPerformOnMainThread(^{result = [[self createSearchableItem:args] retain];}, YES); - return [result autorelease]; - } - - ENSURE_SINGLE_ARG(args,NSDictionary); - - NSString* uniqueIdentifier = nil; - ENSURE_ARG_FOR_KEY(uniqueIdentifier, args, @"uniqueIdentifier", NSString); - - NSString* domainIdentifier = nil; - ENSURE_ARG_FOR_KEY(domainIdentifier, args, @"domainIdentifier", NSString); - - TiAppiOSSearchableItemAttributeSetProxy *attributeSet = nil; - ENSURE_ARG_FOR_KEY(attributeSet, args, @"attributeSet", TiAppiOSSearchableItemAttributeSetProxy); - - TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc] initWithUniqueIdentifier:uniqueIdentifier - withDomainIdentifier:domainIdentifier - withAttributeSet:attributeSet.attributes] autorelease]; - return proxy; + if (![TiUtils isIOS9OrGreater]) { + return nil; + } + if (![NSThread isMainThread]) { + __block id result; + TiThreadPerformOnMainThread(^{ + result = [[self createSearchableItem:args] retain]; + }, + YES); + return [result autorelease]; + } + + ENSURE_SINGLE_ARG(args, NSDictionary); + + NSString *uniqueIdentifier = nil; + ENSURE_ARG_FOR_KEY(uniqueIdentifier, args, @"uniqueIdentifier", NSString); + + NSString *domainIdentifier = nil; + ENSURE_ARG_FOR_KEY(domainIdentifier, args, @"domainIdentifier", NSString); + + TiAppiOSSearchableItemAttributeSetProxy *attributeSet = nil; + ENSURE_ARG_FOR_KEY(attributeSet, args, @"attributeSet", TiAppiOSSearchableItemAttributeSetProxy); + + TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc] initWithUniqueIdentifier:uniqueIdentifier + withDomainIdentifier:domainIdentifier + withAttributeSet:attributeSet.attributes] autorelease]; + return proxy; } #endif #ifdef USE_TI_APPIOSSEARCHABLEITEMATTRIBUTESET --(id)createSearchableItemAttributeSet:(id)args +- (id)createSearchableItemAttributeSet:(id)args { - if (![TiUtils isIOS9OrGreater]) { - return nil; - } - if (![NSThread isMainThread]) { - __block id result; - TiThreadPerformOnMainThread(^{result = [[self createSearchableItemAttributeSet:args] retain];}, YES); - return [result autorelease]; - } - ENSURE_SINGLE_ARG(args,NSDictionary); - NSString* itemContentType = nil; - ENSURE_ARG_FOR_KEY(itemContentType, args, @"itemContentType", NSString); - - NSMutableDictionary *props = [NSMutableDictionary dictionaryWithDictionary:args]; - [props removeObjectForKey:@"itemContentType"]; //remove to avoid duplication - - TiAppiOSSearchableItemAttributeSetProxy *proxy = [[[TiAppiOSSearchableItemAttributeSetProxy alloc] initWithItemContentType:itemContentType withProps:props] autorelease]; - - return proxy; + if (![TiUtils isIOS9OrGreater]) { + return nil; + } + if (![NSThread isMainThread]) { + __block id result; + TiThreadPerformOnMainThread(^{ + result = [[self createSearchableItemAttributeSet:args] retain]; + }, + YES); + return [result autorelease]; + } + ENSURE_SINGLE_ARG(args, NSDictionary); + NSString *itemContentType = nil; + ENSURE_ARG_FOR_KEY(itemContentType, args, @"itemContentType", NSString); + + NSMutableDictionary *props = [NSMutableDictionary dictionaryWithDictionary:args]; + [props removeObjectForKey:@"itemContentType"]; //remove to avoid duplication + + TiAppiOSSearchableItemAttributeSetProxy *proxy = [[[TiAppiOSSearchableItemAttributeSetProxy alloc] initWithItemContentType:itemContentType withProps:props] autorelease]; + + return proxy; } #endif #if IS_XCODE_8 #ifdef USE_TI_APPIOSSEARCHQUERY --(id)createSearchQuery:(id)args +- (id)createSearchQuery:(id)args { - if (![TiUtils isIOS10OrGreater]) { - NSLog(@"[ERROR] Search-Queries are only available in iOS 10 and later."); - return nil; - } - if (![NSThread isMainThread]) { - __block id result; - TiThreadPerformOnMainThread(^{result = [[self createSearchQuery:args] retain];}, YES); - return [result autorelease]; - } - - ENSURE_SINGLE_ARG(args, NSDictionary); - - return [[[TiAppiOSSearchQueryProxy alloc] _initWithPageContext:[self pageContext] andArguments:args] autorelease]; + if (![TiUtils isIOS10OrGreater]) { + NSLog(@"[ERROR] Search-Queries are only available in iOS 10 and later."); + return nil; + } + if (![NSThread isMainThread]) { + __block id result; + TiThreadPerformOnMainThread(^{ + result = [[self createSearchQuery:args] retain]; + }, + YES); + return [result autorelease]; + } + + ENSURE_SINGLE_ARG(args, NSDictionary); + + return [[[TiAppiOSSearchQueryProxy alloc] _initWithPageContext:[self pageContext] andArguments:args] autorelease]; } #endif #endif #ifdef USE_TI_APPIOSUSERACTIVITY --(id)createUserActivity:(id)args +- (id)createUserActivity:(id)args { - if (![NSThread isMainThread]) { - __block id result; - TiThreadPerformOnMainThread(^{result = [[self createUserActivity:args] retain];}, YES); - return [result autorelease]; - } - NSString* activityType; - ENSURE_SINGLE_ARG(args,NSDictionary); - ENSURE_ARG_FOR_KEY(activityType, args, @"activityType", NSString); - - TiAppiOSUserActivityProxy *userActivityProxy = [[[TiAppiOSUserActivityProxy alloc] initWithOptions:args] autorelease]; + if (![NSThread isMainThread]) { + __block id result; + TiThreadPerformOnMainThread(^{ + result = [[self createUserActivity:args] retain]; + }, + YES); + return [result autorelease]; + } + NSString *activityType; + ENSURE_SINGLE_ARG(args, NSDictionary); + ENSURE_ARG_FOR_KEY(activityType, args, @"activityType", NSString); + + TiAppiOSUserActivityProxy *userActivityProxy = [[[TiAppiOSUserActivityProxy alloc] initWithOptions:args] autorelease]; - return userActivityProxy; + return userActivityProxy; } #endif --(id)createUserDefaults:(id)args -{ - NSString *suiteName; - ENSURE_SINGLE_ARG(args,NSDictionary); - ENSURE_ARG_FOR_KEY(suiteName, args, @"suiteName", NSString); - - NSUserDefaults *defaultsObject = [[[NSUserDefaults alloc] initWithSuiteName:suiteName] autorelease]; - - TiAppiOSUserDefaultsProxy *userDefaultsProxy = [[[TiAppiOSUserDefaultsProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - - userDefaultsProxy.defaultsObject = defaultsObject; - - return userDefaultsProxy; -} - --(id)registerBackgroundService:(id)args -{ - NSDictionary* a = nil; - ENSURE_ARG_AT_INDEX(a, args, 0, NSDictionary) - - NSString* urlString = [[TiUtils toURL:[a objectForKey:@"url"] proxy:self]absoluteString]; - - if ([urlString length] == 0) { - return nil; - } - - if (backgroundServices == nil) { - backgroundServices = [[NSMutableDictionary alloc]init]; - } - - TiAppiOSBackgroundServiceProxy *proxy = [backgroundServices objectForKey:urlString]; - - if (proxy == nil) { - proxy = [[[TiAppiOSBackgroundServiceProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; - [backgroundServices setValue:proxy forKey:urlString]; - } - - [[TiApp app] registerBackgroundService:proxy]; - return proxy; -} - --(void)registerUserNotificationSettings:(id)args -{ - if (![TiUtils isIOS8OrGreater]) return; - - ENSURE_SINGLE_ARG(args, NSDictionary); - - NSArray *categories; - NSArray *typesRequested; - ENSURE_ARG_OR_NIL_FOR_KEY(categories, args, @"categories", NSArray); - ENSURE_ARG_OR_NIL_FOR_KEY(typesRequested, args, @"types", NSArray); - - NSMutableArray *nativeCategories = [NSMutableArray arrayWithCapacity:[categories count]]; - if (categories != nil) { - for (id category in categories) { - ENSURE_TYPE(category, TiAppiOSUserNotificationCategoryProxy); - [nativeCategories addObject:[(TiAppiOSUserNotificationCategoryProxy*)category notificationCategory]]; - } - } - - NSUInteger types = UIUserNotificationTypeNone; - -#if IS_XCODE_8 - if ([TiUtils isIOS10OrGreater]) { - types = UNAuthorizationOptionNone; +- (id)createUserDefaults:(id)args +{ + NSString *suiteName; + ENSURE_SINGLE_ARG(args, NSDictionary); + ENSURE_ARG_FOR_KEY(suiteName, args, @"suiteName", NSString); + + NSUserDefaults *defaultsObject = [[[NSUserDefaults alloc] initWithSuiteName:suiteName] autorelease]; + + TiAppiOSUserDefaultsProxy *userDefaultsProxy = [[[TiAppiOSUserDefaultsProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + + userDefaultsProxy.defaultsObject = defaultsObject; + + return userDefaultsProxy; +} + +- (id)registerBackgroundService:(id)args +{ + NSDictionary *a = nil; + ENSURE_ARG_AT_INDEX(a, args, 0, NSDictionary) + + NSString *urlString = [[TiUtils toURL:[a objectForKey:@"url"] proxy:self] absoluteString]; + + if ([urlString length] == 0) { + return nil; + } + + if (backgroundServices == nil) { + backgroundServices = [[NSMutableDictionary alloc] init]; + } + + TiAppiOSBackgroundServiceProxy *proxy = [backgroundServices objectForKey:urlString]; + + if (proxy == nil) { + proxy = [[[TiAppiOSBackgroundServiceProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; + [backgroundServices setValue:proxy forKey:urlString]; + } + + [[TiApp app] registerBackgroundService:proxy]; + return proxy; +} + +- (void)registerUserNotificationSettings:(id)args +{ + if (![TiUtils isIOS8OrGreater]) + return; + + ENSURE_SINGLE_ARG(args, NSDictionary); + + NSArray *categories; + NSArray *typesRequested; + ENSURE_ARG_OR_NIL_FOR_KEY(categories, args, @"categories", NSArray); + ENSURE_ARG_OR_NIL_FOR_KEY(typesRequested, args, @"types", NSArray); + + NSMutableArray *nativeCategories = [NSMutableArray arrayWithCapacity:[categories count]]; + if (categories != nil) { + for (id category in categories) { + ENSURE_TYPE(category, TiAppiOSUserNotificationCategoryProxy); + [nativeCategories addObject:[(TiAppiOSUserNotificationCategoryProxy *)category notificationCategory]]; } + } + + NSUInteger types = UIUserNotificationTypeNone; + +#if IS_XCODE_8 + if ([TiUtils isIOS10OrGreater]) { + types = UNAuthorizationOptionNone; + } #endif - - if (typesRequested != nil) { - for (id thisTypeRequested in typesRequested) - { - if ([TiUtils isIOS10OrGreater]) { + + if (typesRequested != nil) { + for (id thisTypeRequested in typesRequested) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - switch([TiUtils intValue:thisTypeRequested]) - { - case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE - { - types |= UNAuthorizationOptionBadge; - break; - } - case UNAuthorizationOptionAlert: // USER_NOTIFICATION_TYPE_ALERT - { - types |= UNAuthorizationOptionAlert; - break; - } - case UNAuthorizationOptionSound: // USER_NOTIFICATION_TYPE_SOUND - { - types |= UNAuthorizationOptionSound; - break; - } - case UNAuthorizationOptionCarPlay: // USER_NOTIFICATION_TYPE_CAR_PLAY - { - types |= UNAuthorizationOptionCarPlay; - break; - } - } + switch ([TiUtils intValue:thisTypeRequested]) { + case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE + { + types |= UNAuthorizationOptionBadge; + break; + } + case UNAuthorizationOptionAlert: // USER_NOTIFICATION_TYPE_ALERT + { + types |= UNAuthorizationOptionAlert; + break; + } + case UNAuthorizationOptionSound: // USER_NOTIFICATION_TYPE_SOUND + { + types |= UNAuthorizationOptionSound; + break; + } + case UNAuthorizationOptionCarPlay: // USER_NOTIFICATION_TYPE_CAR_PLAY + { + types |= UNAuthorizationOptionCarPlay; + break; + } + } #endif - } else { - switch([TiUtils intValue:thisTypeRequested]) { - case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE - { - types |= UIUserNotificationTypeBadge; - break; - } - case UIUserNotificationTypeAlert: // USER_NOTIFICATION_TYPE_ALERT - { - types |= UIUserNotificationTypeAlert; - break; - } - case UIUserNotificationTypeSound: // USER_NOTIFICATION_TYPE_SOUND - { - types |= UIUserNotificationTypeSound; - break; - } - } - } + } else { + switch ([TiUtils intValue:thisTypeRequested]) { + case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE + { + types |= UIUserNotificationTypeBadge; + break; } + case UIUserNotificationTypeAlert: // USER_NOTIFICATION_TYPE_ALERT + { + types |= UIUserNotificationTypeAlert; + break; + } + case UIUserNotificationTypeSound: // USER_NOTIFICATION_TYPE_SOUND + { + types |= UIUserNotificationTypeSound; + break; + } + } + } } - - if ([TiUtils isIOS10OrGreater]) { + } + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler: ^(BOOL granted, NSError *error) { - if (granted == YES) { - [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithArray:nativeCategories]]; - } - - if ([self _hasListeners:@"usernotificationsettings"]) { - NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{@"success": NUMBOOL(granted)}]; - - if (error) { - [event setValue:[error localizedDescription] forKey:@"error"]; - [event setValue:NUMINTEGER([error code]) forKey:@"code"]; - } - - [self fireEvent:@"usernotificationsettings" withObject:event]; - } - }]; + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types + completionHandler:^(BOOL granted, NSError *error) { + if (granted == YES) { + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithArray:nativeCategories]]; + } + + if ([self _hasListeners:@"usernotificationsettings"]) { + NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{ @"success" : NUMBOOL(granted) }]; + + if (error) { + [event setValue:[error localizedDescription] forKey:@"error"]; + [event setValue:NUMINTEGER([error code]) forKey:@"code"]; + } + + [self fireEvent:@"usernotificationsettings" withObject:event]; + } + }]; #endif - } else { - UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types - categories:[NSSet setWithArray:nativeCategories]]; - TiThreadPerformOnMainThread(^{ - [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; - }, NO); - } + } else { + UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types + categories:[NSSet setWithArray:nativeCategories]]; + TiThreadPerformOnMainThread(^{ + [[UIApplication sharedApplication] registerUserNotificationSettings:notif]; + }, + NO); + } } --(id)createUserNotificationAction:(id)args +- (id)createUserNotificationAction:(id)args { - return [[[TiAppiOSUserNotificationActionProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; + return [[[TiAppiOSUserNotificationActionProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } - --(id)createUserNotificationCategory:(id)args +- (id)createUserNotificationCategory:(id)args { - return [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; + return [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } --(NSArray*)supportedUserActivityTypes -{ - if (![TiUtils isIOS8OrGreater]) { - return nil; - } - - NSArray *supportedActivityTypes = [[NSBundle mainBundle] - objectForInfoDictionaryKey:@"NSUserActivityTypes"]; - - return supportedActivityTypes; -} +- (NSArray *)supportedUserActivityTypes +{ + if (![TiUtils isIOS8OrGreater]) { + return nil; + } + + NSArray *supportedActivityTypes = [[NSBundle mainBundle] + objectForInfoDictionaryKey:@"NSUserActivityTypes"]; + return supportedActivityTypes; +} --(NSDictionary*)currentUserNotificationSettings +- (NSDictionary *)currentUserNotificationSettings { - if (![TiUtils isIOS8OrGreater]) { - return nil; - } - - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); - - if ([TiUtils isIOS10OrGreater]) { + if (![TiUtils isIOS8OrGreater]) { + return nil; + } + + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); - return; + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); + return; #endif + } else { + __block NSDictionary *returnVal = nil; + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, + YES); + + return [returnVal autorelease]; + } +} + +- (NSDictionary *)formatUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings +{ + if (![NSThread isMainThread]) { + __block NSDictionary *result = nil; + TiThreadPerformOnMainThread(^{ + result = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, + YES); + return [result autorelease]; + } + NSMutableArray *typesArray = [NSMutableArray array]; + NSMutableArray *categoriesArray = [NSMutableArray array]; + + NSUInteger types = notificationSettings.types; + NSSet *categories = notificationSettings.categories; + + // Types + if ((types & UIUserNotificationTypeBadge) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeBadge)]; + } + if ((types & UIUserNotificationTypeAlert) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeAlert)]; + } + if ((types & UIUserNotificationTypeSound) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeSound)]; + } + + // Categories + for (id cat in categories) { + TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + categoryProxy.notificationCategory = cat; + [categoriesArray addObject:categoryProxy]; + } + return [NSDictionary dictionaryWithObjectsAndKeys: + typesArray, @"types", + categoriesArray, @"categories", + nil]; +} + +- (id)scheduleLocalNotification:(id)args +{ + ENSURE_SINGLE_ARG(args, NSDictionary); + + id repeat = [args objectForKey:@"repeat"]; + id date = [args objectForKey:@"date"]; + id region = [args objectForKey:@"region"]; + id alertTitle = [args objectForKey:@"alertTitle"]; + id alertBody = [args objectForKey:@"alertBody"]; + id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; + id badge = [args objectForKey:@"badge"]; + id userInfo = [args objectForKey:@"userInfo"]; + id sound = [args objectForKey:@"sound"]; + + TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + + if ([TiUtils isIOS10OrGreater]) { +#if IS_XCODE_8 + id identifier = [args objectForKey:@"identifier"]; + id alertSubtitle = [args objectForKey:@"alertSubtitle"]; + id category = [args objectForKey:@"category"]; + id attachments = [args objectForKey:@"attachments"]; + + UNNotificationTrigger *trigger; + + if (date) { + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + + // Per default, use all components and don't repeat + NSCalendarUnit components = NSYearCalendarUnit | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + + if (repeat != nil) { + if ([repeat isEqual:@"weekly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"daily"]) { + components = NSCalendarUnitDay; + } else if ([repeat isEqual:@"yearly"]) { + components = NSCalendarUnitYear; + } else if ([repeat isEqual:@"monthly"]) { + components = NSCalendarUnitMonth; + } else { + NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); + } + } + + trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components + fromDate:date] + repeats:(repeat != nil)]; + RELEASE_TO_NIL(calendar); + } else if (region) { + BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; + + CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) + radius:radius + identifier:[TiUtils stringValue:@"identifier"] ?: @"notification"]; + + trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion + repeats:triggersOnce]; + RELEASE_TO_NIL(circularRegion); } else { - __block NSDictionary* returnVal = nil; - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; - }, YES); - - return [returnVal autorelease]; + DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); + return; } -} --(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings -{ - if (![NSThread isMainThread]) { - __block NSDictionary*result = nil; - TiThreadPerformOnMainThread(^{ - result = [[self formatUserNotificationSettings:notificationSettings] retain]; - }, YES); - return [result autorelease]; - + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + + if (alertTitle) { + [content setTitle:[TiUtils stringValue:alertTitle]]; } - NSMutableArray *typesArray = [NSMutableArray array]; - NSMutableArray *categoriesArray = [NSMutableArray array]; - - NSUInteger types = notificationSettings.types; - NSSet *categories = notificationSettings.categories; - - // Types - if ((types & UIUserNotificationTypeBadge)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeBadge)]; + + if (alertSubtitle) { + [content setSubtitle:[TiUtils stringValue:alertSubtitle]]; } - if ((types & UIUserNotificationTypeAlert)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeAlert)]; + + if (alertBody) { + [content setBody:[TiUtils stringValue:alertBody]]; } - if ((types & UIUserNotificationTypeSound)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeSound)]; + + if (alertLaunchImage) { + [content setLaunchImageName:[TiUtils stringValue:alertLaunchImage]]; } - - // Categories - for (id cat in categories) { - TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - categoryProxy.notificationCategory = cat; - [categoriesArray addObject:categoryProxy]; + + if (badge) { + [content setBadge:[TiUtils numberFromObject:badge]]; } - return [NSDictionary dictionaryWithObjectsAndKeys: - typesArray, @"types", - categoriesArray, @"categories", - nil]; -} --(id)scheduleLocalNotification:(id)args -{ - ENSURE_SINGLE_ARG(args,NSDictionary); + if (userInfo) { + [content setUserInfo:userInfo]; + } - id repeat = [args objectForKey:@"repeat"]; - id date = [args objectForKey:@"date"]; - id region = [args objectForKey:@"region"]; - id alertTitle = [args objectForKey:@"alertTitle"]; - id alertBody = [args objectForKey:@"alertBody"]; - id alertLaunchImage = [args objectForKey:@"alertLaunchImage"]; - id badge = [args objectForKey:@"badge"]; - id userInfo = [args objectForKey:@"userInfo"]; - id sound = [args objectForKey:@"sound"]; + if (attachments) { + NSMutableArray *_attachments = [NSMutableArray arrayWithCapacity:[attachments count]]; + for (id attachment in attachments) { + NSString *_identifier; + NSString *_url; + NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} + NSError *error = nil; - TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); + ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); + ENSURE_ARG_OR_NIL_FOR_KEY(_options, attachment, @"options", NSDictionary); - if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 - id identifier = [args objectForKey:@"identifier"]; - id alertSubtitle = [args objectForKey:@"alertSubtitle"]; - id category = [args objectForKey:@"category"]; - id attachments = [args objectForKey:@"attachments"]; - - UNNotificationTrigger *trigger; - - if (date) { - NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - - // Per default, use all components and don't repeat - NSCalendarUnit components = NSYearCalendarUnit|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond; - - if (repeat != nil) { - if ([repeat isEqual:@"weekly"]) { - components = NSCalendarUnitYear; - } else if ([repeat isEqual:@"daily"]) { - components = NSCalendarUnitDay; - } else if ([repeat isEqual:@"yearly"]) { - components = NSCalendarUnitYear; - } else if ([repeat isEqual:@"monthly"]) { - components = NSCalendarUnitMonth; - } else { - NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); - } - } - - trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:[calendar components:components - fromDate:date] - repeats:(repeat != nil)]; - RELEASE_TO_NIL(calendar); - } else if (region) { - BOOL triggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; - - CLRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) - radius:radius - identifier:[TiUtils stringValue:@"identifier"] ?: @"notification"]; - - trigger = [UNLocationNotificationTrigger triggerWithRegion:circularRegion - repeats:triggersOnce]; - RELEASE_TO_NIL(circularRegion); + UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier + URL:[TiUtils toURL:_url proxy:self] + options:_options + error:&error]; + if (error != nil) { + NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); } else { - DebugLog(@"[ERROR] Notifications in iOS 10 require the either a `date` or `region` property to be set."); - return; - } - - UNMutableNotificationContent *content = [UNMutableNotificationContent new]; - - if (alertTitle) { - [content setTitle:[TiUtils stringValue:alertTitle]]; - } - - if (alertSubtitle) { - [content setSubtitle:[TiUtils stringValue:alertSubtitle]]; - } - - if (alertBody) { - [content setBody:[TiUtils stringValue:alertBody]]; - } - - if (alertLaunchImage) { - [content setLaunchImageName:[TiUtils stringValue:alertLaunchImage]]; - } - - if (badge) { - [content setBadge:[TiUtils numberFromObject:badge]]; + [_attachments addObject:_attachment]; } - - if (userInfo) { - [content setUserInfo:userInfo]; - } - - if (attachments) { - NSMutableArray *_attachments = [NSMutableArray arrayWithCapacity:[attachments count]]; - for (id attachment in attachments) { - NSString *_identifier; - NSString *_url; - NSDictionary *_options; // e.g. {"UNNotificationAttachmentOptionsTypeHintKey": "test"} - NSError *error = nil; - - ENSURE_ARG_FOR_KEY(_identifier, attachment, @"identifier", NSString); - ENSURE_ARG_FOR_KEY(_url, attachment, @"url", NSString); - ENSURE_ARG_OR_NIL_FOR_KEY(_options, attachment, @"options", NSDictionary); - - UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier - URL:[TiUtils toURL:_url proxy:self] - options:_options - error:&error]; - if (error != nil) { - NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); - } else { - [_attachments addObject:_attachment]; - } - } - [content setAttachments:_attachments]; - } - - if (sound) { - if ([sound isEqual:@"default"]) { - [content setSound:[UNNotificationSound defaultSound]]; - } else { - [content setSound:[UNNotificationSound soundNamed:sound]]; - } - } - - if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { - [content setCategoryIdentifier:[(TiAppiOSUserNotificationCategoryProxy*)category identifier]]; - } else if (category != nil && [category isKindOfClass:[NSString class]]) { - [content setCategoryIdentifier:[TiUtils stringValue:category]]; - } - - UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] ?: @"notification" - content:content - trigger:trigger]; - - TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request - withCompletionHandler:^(NSError *error) { - if (error) { - DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); - } - }]; - }, NO); - - lp.notification = content; - [content release]; - - return lp; + } + [content setAttachments:_attachments]; + } + + if (sound) { + if ([sound isEqual:@"default"]) { + [content setSound:[UNNotificationSound defaultSound]]; + } else { + [content setSound:[UNNotificationSound soundNamed:sound]]; + } + } + + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + [content setCategoryIdentifier:[(TiAppiOSUserNotificationCategoryProxy *)category identifier]]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + [content setCategoryIdentifier:[TiUtils stringValue:category]]; + } + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[TiUtils stringValue:identifier] ?: @"notification" + content:content + trigger:trigger]; + + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request + withCompletionHandler:^(NSError *error) { + if (error) { + DebugLog(@"[ERROR] The notification could not be scheduled: %@", [error localizedDescription]); + } + }]; + }, + NO); + + lp.notification = content; + [content release]; + + return lp; #endif - } else { - UILocalNotification *content = [UILocalNotification new]; - id alertAction = [args objectForKey:@"alertAction"]; - - if (date!=nil) { - content.fireDate = date; - content.timeZone = [NSTimeZone defaultTimeZone]; - } - - if (repeat != nil) { - if ([repeat isEqual:@"weekly"]) { - content.repeatInterval = NSWeekCalendarUnit; - } else if ([repeat isEqual:@"daily"]) { - content.repeatInterval = NSDayCalendarUnit; - } else if ([repeat isEqual:@"yearly"]) { - content.repeatInterval = NSYearCalendarUnit; - } else if ([repeat isEqual:@"monthly"]) { - content.repeatInterval = NSMonthCalendarUnit; - } - } - - if (alertBody != nil) { - content.alertBody = alertBody; - } + } else { + UILocalNotification *content = [UILocalNotification new]; + id alertAction = [args objectForKey:@"alertAction"]; - if (alertTitle != nil && [TiUtils isIOS82rGreater]) { - content.alertTitle = alertTitle; - } - - if (alertAction != nil) { - content.alertAction = alertAction; - } + if (date != nil) { + content.fireDate = date; + content.timeZone = [NSTimeZone defaultTimeZone]; + } - if (alertLaunchImage != nil) { - content.alertLaunchImage = alertLaunchImage; - } + if (repeat != nil) { + if ([repeat isEqual:@"weekly"]) { + content.repeatInterval = NSWeekCalendarUnit; + } else if ([repeat isEqual:@"daily"]) { + content.repeatInterval = NSDayCalendarUnit; + } else if ([repeat isEqual:@"yearly"]) { + content.repeatInterval = NSYearCalendarUnit; + } else if ([repeat isEqual:@"monthly"]) { + content.repeatInterval = NSMonthCalendarUnit; + } + } - if (badge != nil) { - content.applicationIconBadgeNumber = [TiUtils intValue:badge]; - } - - if (region != nil) { - ENSURE_TYPE(region, NSDictionary); - - BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; - - CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); - - if (!CLLocationCoordinate2DIsValid(center)) { - NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); - RELEASE_TO_NIL(content); - return; - } - - content.region = [[[CLCircularRegion alloc] initWithCenter:center - radius:radius - identifier:[TiUtils stringValue:@"identifier" - properties:args - def:@"notification"]] autorelease]; - - content.regionTriggersOnce = regionTriggersOnce; - } + if (alertBody != nil) { + content.alertBody = alertBody; + } - if (sound) { - if ([sound isEqual:@"default"]) { - content.soundName = UILocalNotificationDefaultSoundName; - } else { - content.soundName = sound; - } - } + if (alertTitle != nil && [TiUtils isIOS82rGreater]) { + content.alertTitle = alertTitle; + } - if (userInfo) { - content.userInfo = userInfo; - } + if (alertAction != nil) { + content.alertAction = alertAction; + } - if ([TiUtils isIOS8OrGreater]) { - id category = [args objectForKey:@"category"]; - if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { - content.category = [(TiAppiOSUserNotificationCategoryProxy*)category identifier]; - } else if (category != nil && [category isKindOfClass:[NSString class]]) { - content.category = category; - } - } - - TiThreadPerformOnMainThread(^{ - if (date != nil || region != nil) { - [[UIApplication sharedApplication] scheduleLocalNotification:content]; - } else { - [[UIApplication sharedApplication] presentLocalNotificationNow:content]; - } - }, NO); - - lp.notification = content; - [content release]; - - return lp; + if (alertLaunchImage != nil) { + content.alertLaunchImage = alertLaunchImage; + } + + if (badge != nil) { + content.applicationIconBadgeNumber = [TiUtils intValue:badge]; + } + + if (region != nil) { + ENSURE_TYPE(region, NSDictionary); + + BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; + double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; + double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; + double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; + + CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); + + if (!CLLocationCoordinate2DIsValid(center)) { + NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); + RELEASE_TO_NIL(content); + return; + } + + content.region = [[[CLCircularRegion alloc] initWithCenter:center + radius:radius + identifier:[TiUtils stringValue:@"identifier" + properties:args + def:@"notification"]] autorelease]; + + content.regionTriggersOnce = regionTriggersOnce; + } + + if (sound) { + if ([sound isEqual:@"default"]) { + content.soundName = UILocalNotificationDefaultSoundName; + } else { + content.soundName = sound; + } + } + + if (userInfo) { + content.userInfo = userInfo; } + + if ([TiUtils isIOS8OrGreater]) { + id category = [args objectForKey:@"category"]; + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + content.category = [(TiAppiOSUserNotificationCategoryProxy *)category identifier]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + content.category = category; + } + } + + TiThreadPerformOnMainThread(^{ + if (date != nil || region != nil) { + [[UIApplication sharedApplication] scheduleLocalNotification:content]; + } else { + [[UIApplication sharedApplication] presentLocalNotificationNow:content]; + } + }, + NO); + + lp.notification = content; + [content release]; + + return lp; + } } --(void)cancelAllLocalNotifications:(id)unused +- (void)cancelAllLocalNotifications:(id)unused { - ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); + ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); + + DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); - DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); - - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removeAllPendingNotifications in iOS 10 and later."); + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removeAllPendingNotifications in iOS 10 and later."); #endif - } else { - [[UIApplication sharedApplication] cancelAllLocalNotifications]; - } + } else { + [[UIApplication sharedApplication] cancelAllLocalNotifications]; + } } --(void)cancelLocalNotification:(id)args +- (void)cancelLocalNotification:(id)args { - ENSURE_SINGLE_ARG(args,NSObject); - ENSURE_UI_THREAD(cancelLocalNotification,args); - - DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); - - if ([TiUtils isIOS10OrGreater]) { + ENSURE_SINGLE_ARG(args, NSObject); + ENSURE_UI_THREAD(cancelLocalNotification, args); + + DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers in iOS 10 and later."); + DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers in iOS 10 and later."); #endif - } else { - NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; - if (notifications!=nil) - { - for (UILocalNotification *notification in notifications) - { - if([[[notification userInfo] objectForKey:@"id"] isEqual:args]) - { - [[UIApplication sharedApplication] cancelLocalNotification:notification]; - return; - } - } + } else { + NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; + if (notifications != nil) { + for (UILocalNotification *notification in notifications) { + if ([[[notification userInfo] objectForKey:@"id"] isEqual:args]) { + [[UIApplication sharedApplication] cancelLocalNotification:notification]; + return; } + } } + } } --(void)didReceiveContinueActivityNotification:(NSNotification*)notif +- (void)didReceiveContinueActivityNotification:(NSNotification *)notif { - NSDictionary *notification = [notif userInfo]; - [self fireEvent:@"continueactivity" withObject:notification]; + NSDictionary *notification = [notif userInfo]; + [self fireEvent:@"continueactivity" withObject:notification]; } --(void)didReceiveLocalNotification:(NSNotification*)note +- (void)didReceiveLocalNotification:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"notification" withObject:notification]; + NSDictionary *notification = [note object]; + [self fireEvent:@"notification" withObject:notification]; } --(void)didReceiveLocalNotificationAction:(NSNotification*)note +- (void)didReceiveLocalNotificationAction:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"localnotificationaction" withObject:notification]; + NSDictionary *notification = [note object]; + [self fireEvent:@"localnotificationaction" withObject:notification]; } --(void)didReceiveRemoteNotificationAction:(NSNotification*)note +- (void)didReceiveRemoteNotificationAction:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"remotenotificationaction" withObject:notification]; + NSDictionary *notification = [note object]; + [self fireEvent:@"remotenotificationaction" withObject:notification]; } --(void)remoteExtensionWillExpire:(NSNotification*)note +- (void)remoteExtensionWillExpire:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"remoteextentionwillexpire" withObject:notification]; + NSDictionary *notification = [note object]; + [self fireEvent:@"remoteextentionwillexpire" withObject:notification]; } --(void)didReceiveBackgroundFetchNotification:(NSNotification*)note +- (void)didReceiveBackgroundFetchNotification:(NSNotification *)note { - [self fireEvent:@"backgroundfetch" withObject:[note userInfo]]; + [self fireEvent:@"backgroundfetch" withObject:[note userInfo]]; } --(void)didReceiveSilentPushNotification:(NSNotification*)note +- (void)didReceiveSilentPushNotification:(NSNotification *)note { - [self fireEvent:@"silentpush" withObject:[note userInfo]]; + [self fireEvent:@"silentpush" withObject:[note userInfo]]; } --(void)didReceiveBackgroundTransferNotification:(NSNotification*)note +- (void)didReceiveBackgroundTransferNotification:(NSNotification *)note { - [self fireEvent:@"backgroundtransfer" withObject:[note userInfo]]; + [self fireEvent:@"backgroundtransfer" withObject:[note userInfo]]; } --(void)didReceiveDownloadFinishedNotification:(NSNotification*)note +- (void)didReceiveDownloadFinishedNotification:(NSNotification *)note { - [self fireEvent:@"downloadcompleted" withObject:[note userInfo]]; + [self fireEvent:@"downloadcompleted" withObject:[note userInfo]]; } --(void)didReceiveSessionCompletedNotification:(NSNotification*)note +- (void)didReceiveSessionCompletedNotification:(NSNotification *)note { - [self fireEvent:@"sessioncompleted" withObject:[note userInfo]]; + [self fireEvent:@"sessioncompleted" withObject:[note userInfo]]; } --(void)didReceiveSessionEventsCompletedNotification:(NSNotification*)note +- (void)didReceiveSessionEventsCompletedNotification:(NSNotification *)note { - [self fireEvent:@"sessioneventscompleted" withObject:[note userInfo]]; + [self fireEvent:@"sessioneventscompleted" withObject:[note userInfo]]; } --(void)didReceiveDownloadProgressNotification:(NSNotification*)note +- (void)didReceiveDownloadProgressNotification:(NSNotification *)note { - [self fireEvent:@"downloadprogress" withObject:[note userInfo]]; + [self fireEvent:@"downloadprogress" withObject:[note userInfo]]; } --(void)didReceiveUploadProgressNotification:(NSNotification*)note +- (void)didReceiveUploadProgressNotification:(NSNotification *)note { - [self fireEvent:@"uploadprogress" withObject:[note userInfo]]; + [self fireEvent:@"uploadprogress" withObject:[note userInfo]]; } --(void)didRegisterUserNotificationSettingsNotification:(NSNotification*)notificationSettings +- (void)didRegisterUserNotificationSettingsNotification:(NSNotification *)notificationSettings { - [self fireEvent:@"usernotificationsettings" - withObject:[self formatUserNotificationSettings:(UIUserNotificationSettings*)[notificationSettings object]]]; + [self fireEvent:@"usernotificationsettings" + withObject:[self formatUserNotificationSettings:(UIUserNotificationSettings *)[notificationSettings object]]]; } #pragma mark Apple Watchkit notifications --(void)didReceiveWatchExtensionRequestNotification:(NSNotification*)notif +- (void)didReceiveWatchExtensionRequestNotification:(NSNotification *)notif { - if ([TiUtils isIOS9OrGreater]) { - DebugLog(@"[WARN] Deprecated. Please use Ti.App.iOS.WatchConnectivity instead"); - } - [self fireEvent:@"watchkitextensionrequest" withObject:[notif userInfo]]; + if ([TiUtils isIOS9OrGreater]) { + DebugLog(@"[WARN] Deprecated. Please use Ti.App.iOS.WatchConnectivity instead"); + } + [self fireEvent:@"watchkitextensionrequest" withObject:[notif userInfo]]; } #pragma mark Apple Watchkit handleWatchKitExtensionRequest reply --(void)sendWatchExtensionReply:(id)args +- (void)sendWatchExtensionReply:(id)args { - if ([TiUtils isIOS9OrGreater]) { - DebugLog(@"[WARN] Deprecated. Please use Ti.App.iOS.WatchConnectivity instead"); - } - if(![TiUtils isIOS8OrGreater]) { - return; - } - - enum Args { - kArgKey = 0, - kArgCount, - kArgUserInfo = kArgCount - }; - - ENSURE_TYPE(args,NSArray); - ENSURE_ARG_COUNT(args, kArgCount); - - NSString *key = [TiUtils stringValue:[args objectAtIndex:kArgKey]]; - - if([args count] > 1){ - [[TiApp app] watchKitExtensionRequestHandler:key withUserInfo:[args objectAtIndex:kArgUserInfo]]; - }else{ - [[TiApp app] watchKitExtensionRequestHandler:key withUserInfo:nil]; - } + if ([TiUtils isIOS9OrGreater]) { + DebugLog(@"[WARN] Deprecated. Please use Ti.App.iOS.WatchConnectivity instead"); + } + if (![TiUtils isIOS8OrGreater]) { + return; + } + + enum Args { + kArgKey = 0, + kArgCount, + kArgUserInfo = kArgCount + }; + + ENSURE_TYPE(args, NSArray); + ENSURE_ARG_COUNT(args, kArgCount); + + NSString *key = [TiUtils stringValue:[args objectAtIndex:kArgKey]]; + + if ([args count] > 1) { + [[TiApp app] watchKitExtensionRequestHandler:key withUserInfo:[args objectAtIndex:kArgUserInfo]]; + } else { + [[TiApp app] watchKitExtensionRequestHandler:key withUserInfo:nil]; + } } --(void)setMinimumBackgroundFetchInterval:(id)value +- (void)setMinimumBackgroundFetchInterval:(id)value { - ENSURE_TYPE(value, NSNumber); - double fetchInterval = [TiUtils doubleValue:value]; - fetchInterval = MAX(MIN(fetchInterval, UIApplicationBackgroundFetchIntervalNever),UIApplicationBackgroundFetchIntervalMinimum); - [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:fetchInterval]; + ENSURE_TYPE(value, NSNumber); + double fetchInterval = [TiUtils doubleValue:value]; + fetchInterval = MAX(MIN(fetchInterval, UIApplicationBackgroundFetchIntervalNever), UIApplicationBackgroundFetchIntervalMinimum); + [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:fetchInterval]; } --(void)endBackgroundHandler:(id)arg +- (void)endBackgroundHandler:(id)arg { - ENSURE_SINGLE_ARG(arg, NSString); - if ([arg rangeOfString:@"Session"].location != NSNotFound) { - [[TiApp app] completionHandlerForBackgroundTransfer:arg]; - } else { - [[TiApp app] completionHandler:arg withResult:1]; - } + ENSURE_SINGLE_ARG(arg, NSString); + if ([arg rangeOfString:@"Session"].location != NSNotFound) { + [[TiApp app] completionHandlerForBackgroundTransfer:arg]; + } else { + [[TiApp app] completionHandler:arg withResult:1]; + } } --(NSNumber*)BACKGROUNDFETCHINTERVAL_MIN { - return NUMDOUBLE(UIApplicationBackgroundFetchIntervalMinimum); +- (NSNumber *)BACKGROUNDFETCHINTERVAL_MIN +{ + return NUMDOUBLE(UIApplicationBackgroundFetchIntervalMinimum); } --(NSNumber*)BACKGROUNDFETCHINTERVAL_NEVER { - return NUMDOUBLE(UIApplicationBackgroundFetchIntervalNever); +- (NSNumber *)BACKGROUNDFETCHINTERVAL_NEVER +{ + return NUMDOUBLE(UIApplicationBackgroundFetchIntervalNever); } --(NSNumber*)USER_NOTIFICATION_TYPE_NONE +- (NSNumber *)USER_NOTIFICATION_TYPE_NONE { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNAuthorizationOptionNone); + return NUMINT(UNAuthorizationOptionNone); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeNone); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeNone); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_TYPE_BADGE +- (NSNumber *)USER_NOTIFICATION_TYPE_BADGE { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNAuthorizationOptionBadge); + return NUMINT(UNAuthorizationOptionBadge); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeBadge); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeBadge); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_TYPE_SOUND +- (NSNumber *)USER_NOTIFICATION_TYPE_SOUND { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNAuthorizationOptionSound); + return NUMINT(UNAuthorizationOptionSound); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeSound); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeSound); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_TYPE_ALERT +- (NSNumber *)USER_NOTIFICATION_TYPE_ALERT { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNAuthorizationOptionAlert); + return NUMINT(UNAuthorizationOptionAlert); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeAlert); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationTypeAlert); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_TYPE_CAR_PLAY +- (NSNumber *)USER_NOTIFICATION_TYPE_CAR_PLAY { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNAuthorizationOptionCarPlay); + return NUMINT(UNAuthorizationOptionCarPlay); #endif - } - return NUMINT(0); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND +- (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNNotificationActionOptionNone); + return NUMINT(UNNotificationActionOptionNone); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationActivationModeBackground); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationActivationModeBackground); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND +- (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - return NUMINT(UNNotificationActionOptionForeground); + return NUMINT(UNNotificationActionOptionForeground); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationActivationModeForeground); - } - return NUMINT(0); + } else if ([TiUtils isIOS8OrGreater]) { + return NUMINT(UIUserNotificationActivationModeForeground); + } + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_BEHAVIOR_DEFAULT +- (NSNumber *)USER_NOTIFICATION_BEHAVIOR_DEFAULT { - if ([TiUtils isIOS9OrGreater]) { - return NUMINT(UIUserNotificationActionBehaviorDefault); - } + if ([TiUtils isIOS9OrGreater]) { + return NUMINT(UIUserNotificationActionBehaviorDefault); + } - return NUMINT(0); + return NUMINT(0); } --(NSNumber*)USER_NOTIFICATION_BEHAVIOR_TEXTINPUT +- (NSNumber *)USER_NOTIFICATION_BEHAVIOR_TEXTINPUT { - if ([TiUtils isIOS9OrGreater]) { - return NUMINT(UIUserNotificationActionBehaviorTextInput); - } + if ([TiUtils isIOS9OrGreater]) { + return NUMINT(UIUserNotificationActionBehaviorTextInput); + } - return NUMINT(0); + return NUMINT(0); } #pragma mark UTI Text Type Constants --(CFStringRef)UTTYPE_TEXT +- (CFStringRef)UTTYPE_TEXT { - return kUTTypeText; + return kUTTypeText; } --(CFStringRef)UTTYPE_PLAIN_TEXT +- (CFStringRef)UTTYPE_PLAIN_TEXT { - return kUTTypePlainText; + return kUTTypePlainText; } --(CFStringRef)UTTYPE_UTF8_PLAIN_TEXT +- (CFStringRef)UTTYPE_UTF8_PLAIN_TEXT { - return kUTTypeUTF8PlainText; + return kUTTypeUTF8PlainText; } --(CFStringRef)UTTYPE_UTF16_EXTERNAL_PLAIN_TEXT +- (CFStringRef)UTTYPE_UTF16_EXTERNAL_PLAIN_TEXT { - return kUTTypeUTF16ExternalPlainText; + return kUTTypeUTF16ExternalPlainText; } --(CFStringRef)UTTYPE_UTF16_PLAIN_TEXT +- (CFStringRef)UTTYPE_UTF16_PLAIN_TEXT { - return kUTTypeUTF16PlainText; + return kUTTypeUTF16PlainText; } --(CFStringRef)UTTYPE_RTF +- (CFStringRef)UTTYPE_RTF { - return kUTTypeRTF; + return kUTTypeRTF; } --(CFStringRef)UTTYPE_HTML +- (CFStringRef)UTTYPE_HTML { - return kUTTypeHTML; + return kUTTypeHTML; } --(CFStringRef)UTTYPE_XML +- (CFStringRef)UTTYPE_XML { - return kUTTypeXML; + return kUTTypeXML; } --(CFStringRef)UTTYPE_SOURCE_CODE +- (CFStringRef)UTTYPE_SOURCE_CODE { - return kUTTypeSourceCode; + return kUTTypeSourceCode; } --(CFStringRef)UTTYPE_C_SOURCE +- (CFStringRef)UTTYPE_C_SOURCE { - return kUTTypeCSource; + return kUTTypeCSource; } --(CFStringRef)UTTYPE_OBJECTIVE_C_SOURCE +- (CFStringRef)UTTYPE_OBJECTIVE_C_SOURCE { - return kUTTypeObjectiveCSource; + return kUTTypeObjectiveCSource; } --(CFStringRef)UTTYPE_C_PLUS_PLUS_SOURCE +- (CFStringRef)UTTYPE_C_PLUS_PLUS_SOURCE { - return kUTTypeCPlusPlusSource; + return kUTTypeCPlusPlusSource; } --(CFStringRef)UTTYPE_OBJECTIVE_C_PLUS_PLUS_SOURCE +- (CFStringRef)UTTYPE_OBJECTIVE_C_PLUS_PLUS_SOURCE { - return kUTTypeObjectiveCPlusPlusSource; + return kUTTypeObjectiveCPlusPlusSource; } --(CFStringRef)UTTYPE_C_HEADER +- (CFStringRef)UTTYPE_C_HEADER { - return kUTTypeCHeader; + return kUTTypeCHeader; } --(CFStringRef)UTTYPE_C_PLUS_PLUS_HEADER +- (CFStringRef)UTTYPE_C_PLUS_PLUS_HEADER { - return kUTTypeCPlusPlusHeader; + return kUTTypeCPlusPlusHeader; } --(CFStringRef)UTTYPE_JAVA_SOURCE +- (CFStringRef)UTTYPE_JAVA_SOURCE { - return kUTTypeJavaSource; + return kUTTypeJavaSource; } #pragma mark UTI Composite Content Type Constants --(CFStringRef)UTTYPE_PDF +- (CFStringRef)UTTYPE_PDF { - return kUTTypePDF; + return kUTTypePDF; } --(CFStringRef)UTTYPE_RTFD +- (CFStringRef)UTTYPE_RTFD { - return kUTTypeRTFD; + return kUTTypeRTFD; } --(CFStringRef)UTTYPE_FLAT_RTFD +- (CFStringRef)UTTYPE_FLAT_RTFD { - return kUTTypeFlatRTFD; + return kUTTypeFlatRTFD; } --(CFStringRef)UTTYPE_TXN_TEXT_AND_MULTIMEDIA_DATA +- (CFStringRef)UTTYPE_TXN_TEXT_AND_MULTIMEDIA_DATA { - return kUTTypeTXNTextAndMultimediaData; + return kUTTypeTXNTextAndMultimediaData; } --(CFStringRef)UTTYPE_WEB_ARCHIVE +- (CFStringRef)UTTYPE_WEB_ARCHIVE { - return kUTTypeWebArchive; + return kUTTypeWebArchive; } #pragma mark UTI Image Content Types --(CFStringRef)UTTYPE_IMAGE +- (CFStringRef)UTTYPE_IMAGE { - return kUTTypeImage; + return kUTTypeImage; } --(CFStringRef)UTTYPE_JPEG +- (CFStringRef)UTTYPE_JPEG { - return kUTTypeJPEG; + return kUTTypeJPEG; } --(CFStringRef)UTTYPE_JPEG2000 +- (CFStringRef)UTTYPE_JPEG2000 { - return kUTTypeJPEG2000; + return kUTTypeJPEG2000; } --(CFStringRef)UTTYPE_TIFF +- (CFStringRef)UTTYPE_TIFF { - return kUTTypeTIFF; + return kUTTypeTIFF; } --(CFStringRef)UTTYPE_PICT +- (CFStringRef)UTTYPE_PICT { - return kUTTypePICT; + return kUTTypePICT; } --(CFStringRef)UTTYPE_GIF +- (CFStringRef)UTTYPE_GIF { - return kUTTypeGIF; + return kUTTypeGIF; } --(CFStringRef)UTTYPE_PNG +- (CFStringRef)UTTYPE_PNG { - return kUTTypePNG; + return kUTTypePNG; } --(CFStringRef)UTTYPE_QUICKTIME_IMAGE +- (CFStringRef)UTTYPE_QUICKTIME_IMAGE { - return kUTTypeQuickTimeImage; + return kUTTypeQuickTimeImage; } --(CFStringRef)UTTYPE_APPLE_ICNS +- (CFStringRef)UTTYPE_APPLE_ICNS { - return kUTTypeAppleICNS; + return kUTTypeAppleICNS; } --(CFStringRef)UTTYPE_BMP +- (CFStringRef)UTTYPE_BMP { - return kUTTypeBMP; + return kUTTypeBMP; } --(CFStringRef)UTTYPE_ICO +- (CFStringRef)UTTYPE_ICO { - return kUTTypeICO; + return kUTTypeICO; } #pragma mark UTI Audio Visual Content Types --(CFStringRef)UTTYPE_AUDIO_VISUAL_CONTENT +- (CFStringRef)UTTYPE_AUDIO_VISUAL_CONTENT { - return kUTTypeAudiovisualContent; + return kUTTypeAudiovisualContent; } --(CFStringRef)UTTYPE_MOVIE +- (CFStringRef)UTTYPE_MOVIE { - return kUTTypeMovie; + return kUTTypeMovie; } --(CFStringRef)UTTYPE_VIDEO +- (CFStringRef)UTTYPE_VIDEO { - return kUTTypeVideo; + return kUTTypeVideo; } --(CFStringRef)UTTYPE_AUDIO +- (CFStringRef)UTTYPE_AUDIO { - return kUTTypeAudio; + return kUTTypeAudio; } --(CFStringRef)UTTYPE_QUICKTIME_MOVIE +- (CFStringRef)UTTYPE_QUICKTIME_MOVIE { - return kUTTypeQuickTimeMovie; + return kUTTypeQuickTimeMovie; } --(CFStringRef)UTTYPE_MPEG +- (CFStringRef)UTTYPE_MPEG { - return kUTTypeMPEG; + return kUTTypeMPEG; } --(CFStringRef)UTTYPE_MPEG4 +- (CFStringRef)UTTYPE_MPEG4 { - return kUTTypeMPEG4; + return kUTTypeMPEG4; } --(CFStringRef)UTTYPE_MP3 +- (CFStringRef)UTTYPE_MP3 { - return kUTTypeMP3; + return kUTTypeMP3; } --(CFStringRef)UTTYPE_MPEG4_AUDIO +- (CFStringRef)UTTYPE_MPEG4_AUDIO { - return kUTTypeMPEG4Audio; + return kUTTypeMPEG4Audio; } --(CFStringRef)UTTYPE_APPLE_PROTECTED_MPEG4_AUDIO +- (CFStringRef)UTTYPE_APPLE_PROTECTED_MPEG4_AUDIO { - return kUTTypeAppleProtectedMPEG4Audio; + return kUTTypeAppleProtectedMPEG4Audio; } --(NSString*)applicationOpenSettingsURL +- (NSString *)applicationOpenSettingsURL { - if ([TiUtils isIOS8OrGreater]) { - return UIApplicationOpenSettingsURLString; - } - return nil; + if ([TiUtils isIOS8OrGreater]) { + return UIApplicationOpenSettingsURLString; + } + return nil; } -MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_LAYOUT_CHANGED,@"accessibilitylayoutchanged"); -MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_SCREEN_CHANGED,@"accessibilityscreenchanged"); +MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_LAYOUT_CHANGED, @"accessibilitylayoutchanged"); +MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_SCREEN_CHANGED, @"accessibilityscreenchanged"); MAKE_SYSTEM_PROP(FETCH_NEWDATA, 0); //UIBackgroundFetchResultNewData MAKE_SYSTEM_PROP(FETCH_NODATA, 1); //UIBackgroundFetchResultNoData diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h index 8a123794057..f47ba7640fd 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h @@ -14,9 +14,8 @@ @interface TiAppiOSUserNotificationActionProxy : TiProxy -@property(nonatomic,retain) id notificationAction; +@property (nonatomic, retain) id notificationAction; @end - #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index bcf4ba34ee8..326d71a5a36 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -12,68 +12,68 @@ @implementation TiAppiOSUserNotificationActionProxy --(void)dealloc +- (void)dealloc { - RELEASE_TO_NIL(_notificationAction); - [super dealloc]; + RELEASE_TO_NIL(_notificationAction); + [super dealloc]; } --(NSString*)apiName +- (NSString *)apiName { - return @"Ti.App.iOS.UserNotificationAction"; + return @"Ti.App.iOS.UserNotificationAction"; } --(void)_initWithProperties:(NSDictionary *)properties +- (void)_initWithProperties:(NSDictionary *)properties { - if (_notificationAction == nil) { - - if ([TiUtils isIOS10OrGreater]) { + if (_notificationAction == nil) { + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - id identifier = [properties valueForKey:@"identifier"]; - id title = [properties valueForKey:@"title"]; - id activationMode = [properties valueForKey:@"activationMode"]; - id authenticationRequired = [properties valueForKey:@"authenticationRequired"]; - id destructive = [properties valueForKey:@"destructive"]; - id behavior = [properties valueForKey:@"behavior"]; - id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; - id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; - - UNNotificationActionOptions options = UNNotificationActionOptionNone; - - if (destructive) { - options |= UNNotificationActionOptionDestructive; - } - - if (authenticationRequired) { - options |= UNNotificationActionOptionAuthenticationRequired; - } - - if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { - _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier - title:title - options:options - textInputButtonTitle:textInputButtonTitle - textInputPlaceholder:textInputButtonPlaceholder] retain]; - - [super _initWithProperties:properties]; - return; - } else { - _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier - title:title - options:[TiUtils intValue:activationMode]] retain]; - } + id identifier = [properties valueForKey:@"identifier"]; + id title = [properties valueForKey:@"title"]; + id activationMode = [properties valueForKey:@"activationMode"]; + id authenticationRequired = [properties valueForKey:@"authenticationRequired"]; + id destructive = [properties valueForKey:@"destructive"]; + id behavior = [properties valueForKey:@"behavior"]; + id textInputButtonTitle = [properties valueForKey:@"textInputButtonTitle"]; + id textInputButtonPlaceholder = [properties valueForKey:@"textInputButtonPlaceholder"]; + + UNNotificationActionOptions options = UNNotificationActionOptionNone; + + if (destructive) { + options |= UNNotificationActionOptionDestructive; + } + + if (authenticationRequired) { + options |= UNNotificationActionOptionAuthenticationRequired; + } + + if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { + _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier + title:title + options:options + textInputButtonTitle:textInputButtonTitle + textInputPlaceholder:textInputButtonPlaceholder] retain]; + + [super _initWithProperties:properties]; + return; + } else { + _notificationAction = [[UNNotificationAction actionWithIdentifier:identifier + title:title + options:[TiUtils intValue:activationMode]] retain]; + } #endif - } else { - _notificationAction = [[UIMutableUserNotificationAction new] retain]; - } + } else { + _notificationAction = [[UIMutableUserNotificationAction new] retain]; } - - [super _initWithProperties:properties]; + } + + [super _initWithProperties:properties]; } - (id)notificationAction { - return _notificationAction; + return _notificationAction; } #pragma mark Public API's @@ -81,32 +81,32 @@ - (id)notificationAction #if !defined(IS_XCODE_8) - (void)setIdentifier:(id)value { - [[self notificationAction] setIdentifier:value]; + [[self notificationAction] setIdentifier:value]; } - (void)setTitle:(id)value { - [[self notificationAction] setTitle:value]; + [[self notificationAction] setTitle:value]; } - (void)setActivationMode:(id)value { - [[self notificationAction] setActivationMode:[TiUtils intValue:value]]; + [[self notificationAction] setActivationMode:[TiUtils intValue:value]]; } - (void)setBehavior:(id)value { - [[self notificationAction] setBehavior:[TiUtils intValue:value]]; + [[self notificationAction] setBehavior:[TiUtils intValue:value]]; } - (void)setDestructive:(id)value { - [[self notificationAction] setDestructive:[TiUtils boolValue:value]]; + [[self notificationAction] setDestructive:[TiUtils boolValue:value]]; } - (void)setAuthenticationRequired:(id)value { - [[self notificationAction] setAuthenticationRequired:[TiUtils boolValue:value]]; + [[self notificationAction] setAuthenticationRequired:[TiUtils boolValue:value]]; } #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index 6d8ee3ac2d8..b97c35a190a 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -13,8 +13,8 @@ @interface TiAppiOSUserNotificationCategoryProxy : TiProxy -@property (nonatomic,retain) id notificationCategory; -@property (nonatomic,readonly) NSString *identifier; +@property (nonatomic, retain) id notificationCategory; +@property (nonatomic, readonly) NSString *identifier; - (id)notificationCategory; diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 30841153d2a..8e252474540 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -13,75 +13,75 @@ @implementation TiAppiOSUserNotificationCategoryProxy --(void)dealloc +- (void)dealloc { - RELEASE_TO_NIL(_notificationCategory); - [super dealloc]; + RELEASE_TO_NIL(_notificationCategory); + [super dealloc]; } --(NSString*)apiName +- (NSString *)apiName { - return @"Ti.App.iOS.UserNotificationCategory"; + return @"Ti.App.iOS.UserNotificationCategory"; } --(void)_initWithProperties:(NSDictionary *)properties +- (void)_initWithProperties:(NSDictionary *)properties { - if (_notificationCategory == nil) { - - id identifier = [properties valueForKey:@"identifier"]; - id actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; - id actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; - id intentIdentifiers = [properties valueForKey:@"intentIdentifiers"]; - - NSMutableArray *defaultActions = [NSMutableArray new]; - NSMutableArray *minimalActions = [NSMutableArray new]; - - for (TiAppiOSUserNotificationActionProxy *action in actionsForDefaultContext) { - [defaultActions addObject:[action notificationAction]]; - } - - for (TiAppiOSUserNotificationActionProxy *action in actionsForMinimalContext) { - [minimalActions addObject:[action notificationAction]]; - } - - if (intentIdentifiers) { - for (id itentIdentifier in intentIdentifiers) { - if (![itentIdentifier isKindOfClass:[NSString class]]) { - NSLog(@"[ERROR] All elements in itentIdentifiers must be a String, \"%@\" is not!", itentIdentifier); - } - } + if (_notificationCategory == nil) { + + id identifier = [properties valueForKey:@"identifier"]; + id actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; + id actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; + id intentIdentifiers = [properties valueForKey:@"intentIdentifiers"]; + + NSMutableArray *defaultActions = [NSMutableArray new]; + NSMutableArray *minimalActions = [NSMutableArray new]; + + for (TiAppiOSUserNotificationActionProxy *action in actionsForDefaultContext) { + [defaultActions addObject:[action notificationAction]]; + } + + for (TiAppiOSUserNotificationActionProxy *action in actionsForMinimalContext) { + [minimalActions addObject:[action notificationAction]]; + } + + if (intentIdentifiers) { + for (id itentIdentifier in intentIdentifiers) { + if (![itentIdentifier isKindOfClass:[NSString class]]) { + NSLog(@"[ERROR] All elements in itentIdentifiers must be a String, \"%@\" is not!", itentIdentifier); } - - if ([TiUtils isIOS10OrGreater]) { + } + } + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier - actions:defaultActions - intentIdentifiers:intentIdentifiers ?: @[] - options:UNNotificationCategoryOptionCustomDismissAction] retain]; + _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier + actions:defaultActions + intentIdentifiers:intentIdentifiers ?: @[] + options:UNNotificationCategoryOptionCustomDismissAction] retain]; #endif - } else { - _notificationCategory = [UIMutableUserNotificationCategory new]; - - [_notificationCategory setIdentifier:identifier]; - [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; - [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; - } - - RELEASE_TO_NIL(minimalActions); - RELEASE_TO_NIL(defaultActions); + } else { + _notificationCategory = [UIMutableUserNotificationCategory new]; + + [_notificationCategory setIdentifier:identifier]; + [_notificationCategory setActions:defaultActions forContext:UIUserNotificationActionContextDefault]; + [_notificationCategory setActions:minimalActions forContext:UIUserNotificationActionContextMinimal]; } - - [super _initWithProperties:properties]; + + RELEASE_TO_NIL(minimalActions); + RELEASE_TO_NIL(defaultActions); + } + + [super _initWithProperties:properties]; } --(id)notificationCategory +- (id)notificationCategory { - return _notificationCategory; + return _notificationCategory; } --(NSString*)identifier +- (NSString *)identifier { - return [[self notificationCategory] identifier]; + return [[self notificationCategory] identifier]; } @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index 20b1e4694f6..254648f47d0 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -6,8 +6,8 @@ */ #ifdef USE_TI_APPIOS -#import "TiProxy.h" #import "TiApp.h" +#import "TiProxy.h" #if IS_XCODE_8 #import #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index c31a172ad05..797d1fbcc63 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -7,286 +7,290 @@ #ifdef USE_TI_APPIOS #import "TiAppiOSUserNotificationCenterProxy.h" -#import "TiAppiOSUserNotificationCategoryProxy.h" #import "TiAppiOSLocalNotificationProxy.h" +#import "TiAppiOSUserNotificationCategoryProxy.h" #import -#define NOTNIL(v) ((v==nil) ? (id)[NSNull null] : v) +#define NOTNIL(v) ((v == nil) ? (id)[NSNull null] : v) @implementation TiAppiOSUserNotificationCenterProxy - (void)getPendingNotifications:(id)args { - KrollCallback *callback = nil; - ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); - - if ([TiUtils isIOS10OrGreater]) { + KrollCallback *callback = nil; + ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[self dictionaryWithUserNotificationRequest:request]]; - } - - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; - }, NO); -#endif - } else { - NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; - - for (UILocalNotification *notification in notifications) { - [result addObject:[TiApp dictionaryWithLocalNotification:notification withIdentifier: nil]]; + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; } - - NSDictionary * propertiesDict = @{ - @"notifications": result + + NSDictionary *propertiesDict = @{ + @"notifications" : result }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - + NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + [callback call:invocationArray thisObject:self]; [invocationArray release]; + }]; + }, + NO); +#endif + } else { + NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; + + for (UILocalNotification *notification in notifications) { + [result addObject:[TiApp dictionaryWithLocalNotification:notification withIdentifier:nil]]; } + + NSDictionary *propertiesDict = @{ + @"notifications" : result + }; + NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + } } - (void)getDeliveredNotifications:(id)args { - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - KrollCallback *callback = nil; - ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); - - TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; - - for (UNNotificationRequest *request in requests) { - [result addObject:[self dictionaryWithUserNotificationRequest:request]]; - } - - NSDictionary * propertiesDict = @{ - @"notifications": result - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; - }, NO); + KrollCallback *callback = nil; + ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); + + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray *requests) { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; + + for (UNNotificationRequest *request in requests) { + [result addObject:[self dictionaryWithUserNotificationRequest:request]]; + } + + NSDictionary *propertiesDict = @{ + @"notifications" : result + }; + NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; + }, + NO); #endif - } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); - } + } else { + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); + } } - (void)removePendingNotifications:(id)args { - ENSURE_TYPE(args, NSArray); + ENSURE_TYPE(args, NSArray); - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - TiThreadPerformOnMainThread(^{ - if ([args count] == 0) { - [center removeAllPendingNotificationRequests]; - return; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + TiThreadPerformOnMainThread(^{ + if ([args count] == 0) { + [center removeAllPendingNotificationRequests]; + return; + } + + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + + // Loop through current notification requests + for (UNNotificationRequest *request in requests) { + + // Loop throigh provided notifications + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + + if ([request content] == [(TiAppiOSLocalNotificationProxy *)notification notification]) { + [center removePendingNotificationRequestsWithIdentifiers:@[ [request identifier] ]]; } - - [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - - // Loop through current notification requests - for (UNNotificationRequest *request in requests) { - - // Loop throigh provided notifications - for (id notification in args) { - ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); - - if ([request content] == [(TiAppiOSLocalNotificationProxy*)notification notification]) { - [center removePendingNotificationRequestsWithIdentifiers:@[[request identifier]]]; - } - } - } - }]; - }, NO); + } + } + }]; + }, + NO); #endif - } else { - TiThreadPerformOnMainThread(^{ - if ([args count] == 0) { - [[UIApplication sharedApplication] cancelAllLocalNotifications]; - return; - } - - for (id notification in args) { - ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); - [[UIApplication sharedApplication] cancelLocalNotification:[(TiAppiOSLocalNotificationProxy*)notification notification]]; - } - }, NO); - } + } else { + TiThreadPerformOnMainThread(^{ + if ([args count] == 0) { + [[UIApplication sharedApplication] cancelAllLocalNotifications]; + return; + } + + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + [[UIApplication sharedApplication] cancelLocalNotification:[(TiAppiOSLocalNotificationProxy *)notification notification]]; + } + }, + NO); + } } - (void)removeDeliveredNotifications:(id)args { - ENSURE_TYPE(args, NSArray); + ENSURE_TYPE(args, NSArray); - if ([TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - TiThreadPerformOnMainThread(^{ - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - - if ([args count] == 0) { - [center removeAllDeliveredNotifications]; - return; + TiThreadPerformOnMainThread(^{ + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + + if ([args count] == 0) { + [center removeAllDeliveredNotifications]; + return; + } + + [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { + + // Loop through current notification requests + for (UNNotificationRequest *request in requests) { + + // Loop throigh provided notifications + for (id notification in args) { + ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); + + if ([request content] == [(TiAppiOSLocalNotificationProxy *)notification notification]) { + [center removeDeliveredNotificationsWithIdentifiers:@[ [request identifier] ]]; } - - [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - - // Loop through current notification requests - for (UNNotificationRequest *request in requests) { - - // Loop throigh provided notifications - for (id notification in args) { - ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); - - if ([request content] == [(TiAppiOSLocalNotificationProxy*)notification notification]) { - [center removeDeliveredNotificationsWithIdentifiers:@[[request identifier]]]; - } - } - } - }]; - }, NO); + } + } + }]; + }, + NO); #endif - } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only avaible in iOS 10 and later."); - } + } else { + NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only avaible in iOS 10 and later."); + } } - (void)requestUserNotificationSettings:(id)args { - ENSURE_SINGLE_ARG(args, NSArray); - ENSURE_TYPE([args objectAtIndex:0], KrollCallback); - - KrollCallback *callback = [args objectAtIndex:0]; - - if ([TiUtils isIOS10OrGreater]) { + ENSURE_SINGLE_ARG(args, NSArray); + ENSURE_TYPE([args objectAtIndex:0], KrollCallback); + + KrollCallback *callback = [args objectAtIndex:0]; + + if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - TiThreadPerformOnMainThread(^{ - [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { - NSDictionary * propertiesDict = @{ - @"authorizationStatus": NUMINTEGER([settings authorizationStatus]), - @"soundSetting": NUMINTEGER([settings soundSetting]), - @"badgeSetting": NUMINTEGER([settings badgeSetting]), - @"alertSetting": NUMINTEGER([settings alertSetting]), - @"notificationCenterSetting": NUMINTEGER([settings notificationCenterSetting]), - @"lockScreenSetting": NUMINTEGER([settings lockScreenSetting]), - @"carPlaySetting": NUMINTEGER([settings carPlaySetting]), - @"alertStyle": NUMINTEGER([settings alertStyle]) - }; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }]; - }, NO); + TiThreadPerformOnMainThread(^{ + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + NSDictionary *propertiesDict = @{ + @"authorizationStatus" : NUMINTEGER([settings authorizationStatus]), + @"soundSetting" : NUMINTEGER([settings soundSetting]), + @"badgeSetting" : NUMINTEGER([settings badgeSetting]), + @"alertSetting" : NUMINTEGER([settings alertSetting]), + @"notificationCenterSetting" : NUMINTEGER([settings notificationCenterSetting]), + @"lockScreenSetting" : NUMINTEGER([settings lockScreenSetting]), + @"carPlaySetting" : NUMINTEGER([settings carPlaySetting]), + @"alertStyle" : NUMINTEGER([settings alertStyle]) + }; + NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }]; + }, + NO); #endif - } else { - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - - NSDictionary * propertiesDict = [self formatUserNotificationSettings:settings]; - NSArray * invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; - - [callback call:invocationArray thisObject:self]; - [invocationArray release]; - }, YES); - } + } else { + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + + NSDictionary *propertiesDict = [self formatUserNotificationSettings:settings]; + NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; + + [callback call:invocationArray thisObject:self]; + [invocationArray release]; + }, + YES); + } } #pragma mark Utilities #if IS_XCODE_8 -- (NSDictionary*)dictionaryWithUserNotificationRequest:(UNNotificationRequest*)request +- (NSDictionary *)dictionaryWithUserNotificationRequest:(UNNotificationRequest *)request { - NSMutableDictionary* event = [NSMutableDictionary dictionary]; - - [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; - [event setObject:NOTNIL([[request content] body]) forKey:@"alertBody"]; - [event setObject:NOTNIL([[request content] title]) forKey:@"alertTitle"]; - [event setObject:NOTNIL([[request content] subtitle]) forKey:@"alertSubtitle"]; - [event setObject:NOTNIL([[request content] launchImageName]) forKey:@"alertLaunchImage"]; - [event setObject:NOTNIL([[request content] sound]) forKey:@"sound"]; - [event setObject:NOTNIL([[request content] badge]) forKey:@"badge"]; - [event setObject:NOTNIL([[request content] userInfo]) forKey:@"userInfo"]; - [event setObject:NOTNIL([[request content] categoryIdentifier]) forKey:@"category"]; - [event setObject:NOTNIL([request identifier]) forKey:@"identifier"]; - - if ([[request trigger] isKindOfClass:[UNCalendarNotificationTrigger class]]) { - [event setObject:NOTNIL([(UNCalendarNotificationTrigger*)[request trigger] nextTriggerDate]) forKey:@"date"]; - } else if ([[request trigger] isKindOfClass:[UNLocationNotificationTrigger class]]) { - CLCircularRegion *region = (CLCircularRegion*)[(UNLocationNotificationTrigger*)[request trigger] region]; - - NSDictionary *dict = @{ - @"latitude": NUMDOUBLE(region.center.latitude), - @"longitude": NUMDOUBLE(region.center.longitude), - @"radius": NUMDOUBLE(region.radius), - @"identifier": region.identifier - }; - [event setObject:dict forKey:@"region"]; - } - - return event; + NSMutableDictionary *event = [NSMutableDictionary dictionary]; + + [event setObject:[[NSTimeZone defaultTimeZone] name] forKey:@"timezone"]; + [event setObject:NOTNIL([[request content] body]) forKey:@"alertBody"]; + [event setObject:NOTNIL([[request content] title]) forKey:@"alertTitle"]; + [event setObject:NOTNIL([[request content] subtitle]) forKey:@"alertSubtitle"]; + [event setObject:NOTNIL([[request content] launchImageName]) forKey:@"alertLaunchImage"]; + [event setObject:NOTNIL([[request content] sound]) forKey:@"sound"]; + [event setObject:NOTNIL([[request content] badge]) forKey:@"badge"]; + [event setObject:NOTNIL([[request content] userInfo]) forKey:@"userInfo"]; + [event setObject:NOTNIL([[request content] categoryIdentifier]) forKey:@"category"]; + [event setObject:NOTNIL([request identifier]) forKey:@"identifier"]; + + if ([[request trigger] isKindOfClass:[UNCalendarNotificationTrigger class]]) { + [event setObject:NOTNIL([(UNCalendarNotificationTrigger *)[request trigger] nextTriggerDate]) forKey:@"date"]; + } else if ([[request trigger] isKindOfClass:[UNLocationNotificationTrigger class]]) { + CLCircularRegion *region = (CLCircularRegion *)[(UNLocationNotificationTrigger *)[request trigger] region]; + + NSDictionary *dict = @{ + @"latitude" : NUMDOUBLE(region.center.latitude), + @"longitude" : NUMDOUBLE(region.center.longitude), + @"radius" : NUMDOUBLE(region.radius), + @"identifier" : region.identifier + }; + [event setObject:dict forKey:@"region"]; + } + + return event; } #endif --(NSDictionary*)formatUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings +- (NSDictionary *)formatUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { - if (![NSThread isMainThread]) { - __block NSDictionary*result = nil; - TiThreadPerformOnMainThread(^{ - result = [[self formatUserNotificationSettings:notificationSettings] retain]; - }, YES); - return [result autorelease]; - - } - NSMutableArray *typesArray = [NSMutableArray array]; - NSMutableArray *categoriesArray = [NSMutableArray array]; - - NSUInteger types = notificationSettings.types; - NSSet *categories = notificationSettings.categories; - - // Types - if ((types & UIUserNotificationTypeBadge)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeBadge)]; - } - if ((types & UIUserNotificationTypeAlert)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeAlert)]; - } - if ((types & UIUserNotificationTypeSound)!=0) - { - [typesArray addObject:NUMINT(UIUserNotificationTypeSound)]; - } - - // Categories - for (id cat in categories) { - TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; - categoryProxy.notificationCategory = cat; - [categoriesArray addObject:categoryProxy]; - } - - return @{ - @"types": typesArray, - @"categories": categoriesArray - }; + if (![NSThread isMainThread]) { + __block NSDictionary *result = nil; + TiThreadPerformOnMainThread(^{ + result = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, + YES); + return [result autorelease]; + } + NSMutableArray *typesArray = [NSMutableArray array]; + NSMutableArray *categoriesArray = [NSMutableArray array]; + + NSUInteger types = notificationSettings.types; + NSSet *categories = notificationSettings.categories; + + // Types + if ((types & UIUserNotificationTypeBadge) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeBadge)]; + } + if ((types & UIUserNotificationTypeAlert) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeAlert)]; + } + if ((types & UIUserNotificationTypeSound) != 0) { + [typesArray addObject:NUMINT(UIUserNotificationTypeSound)]; + } + + // Categories + for (id cat in categories) { + TiAppiOSUserNotificationCategoryProxy *categoryProxy = [[[TiAppiOSUserNotificationCategoryProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; + categoryProxy.notificationCategory = cat; + [categoriesArray addObject:categoryProxy]; + } + + return @{ + @"types" : typesArray, + @"categories" : categoriesArray + }; } @end diff --git a/iphone/Classes/TiUtils.h b/iphone/Classes/TiUtils.h index 75bf542fe9c..e61403f4c9f 100644 --- a/iphone/Classes/TiUtils.h +++ b/iphone/Classes/TiUtils.h @@ -581,7 +581,7 @@ typedef enum { Whether or not the current OS version is equal to or greater than 8.2. @return _YES_ if the current OS version is equal to or greater thann 8.2, _NO_ otherwise. */ -+(BOOL)isIOS82rGreater; ++ (BOOL)isIOS82rGreater; /** Whether or not the current OS version is equal to or greater than 9.0. From 37a693eae5433d989e1a6c64e9a2777b5b006466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 09:26:50 +0100 Subject: [PATCH 24/44] Update docs --- .../Titanium/App/iOS/NotificationCenter.yml | 16 +++++----- apidoc/Titanium/App/iOS/iOS.yml | 32 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index 1f3f1981cd0..360acd29cfb 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -7,7 +7,7 @@ summary: | extends: Titanium.Module platforms: [iphone, ipad] osver: {ios: {min: "8.0"}} -since: "6.1.0" +since: "7.1.0" methods: - name: getPendingNotifications @@ -18,7 +18,7 @@ methods: The function that is being called after the notifications have been fetched. type: Callback - since: "6.1.0" + since: "7.1.0" - name: getDeliveredNotifications summary: Fetches the delivered notifications asynchronously. @@ -29,27 +29,27 @@ methods: have been fetched. type: Callback osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: removePendingNotifications summary: | Removes the specified pending notifications to prevent them from being triggered. If no notifications are specified, all pending notifications will be removed. - since: "6.1.0" + since: "7.1.0" - name: removeDeliveredNotifications summary: | Removes the specified delivered notifications from the notification-center. If no notifications are specified, all delivered notifications will be removed. osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: requestUserNotificationSettings summary: | Notification types and user notification categories the application is registered to use (available on iOS 8 and later). type: UserNotificationSettings - since: "6.1.0" + since: "7.1.0" --- name: UserNotificationCallbackResponse @@ -57,7 +57,7 @@ summary: | Response when receiving pending or local notifications in and . -since: "6.1.0" +since: "7.1.0" properties: - name: notifications type: Array @@ -70,7 +70,7 @@ summary: | when receiving pending or local notifications in and . -since: "6.1.0" +since: "7.1.0" properties: - name: alertTitle summary: Title of the notification. diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index 434e2c25f7c..134cc30f508 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -319,7 +319,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED summary: The application is authorized to post user notifications. @@ -329,7 +329,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED summary: The application is not authorized to post user notifications. @@ -339,7 +339,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_SETTING_NOT_SUPPORTED summary: The application does not support this notification type. @@ -349,7 +349,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_SETTING_ENABLED summary: The notification setting is turned on. @@ -359,7 +359,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_SETTING_DISABLED summary: The notification setting is turned off. @@ -369,7 +369,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_NONE summary: No banner or alert dialog is presented when the notification is received. @@ -379,7 +379,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_ALERT summary: A alert dialog is presented when the notification is received. @@ -389,7 +389,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: USER_NOTIFICATION_ALERT_STYLE_BANNER summary: A banner is presented when the notification is received. @@ -399,7 +399,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: UTTYPE_TEXT summary: | @@ -669,7 +669,7 @@ properties: type: UserNotificationSettings permission: read-only deprecated: - since: "6.1.0" + since: "7.1.0" notes: Use instead. osver: {ios: {min: "8.0"}} since: "3.4.0" @@ -1252,7 +1252,7 @@ properties: summary: The notification identifier. description: This property is required in iOS 10 and later. optional: false - since: "6.1.0" + since: "7.1.0" - name: alertAction summary: | @@ -1271,14 +1271,14 @@ properties: type: String optional: true osver: {ios: {min: "8.2"}} - since: "6.1.0" + since: "7.1.0" - name: alertSubtitle summary: Alert subtitle to display. type: String optional: true osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: alertLaunchImage summary: Image to display instead of `Default.png` when launching the application. @@ -1290,7 +1290,7 @@ properties: type: Array optional: true osver: {ios: {min: "10.0"}} - since: "6.1.0" + since: "7.1.0" - name: badge summary: Application badge value. @@ -1340,7 +1340,7 @@ properties: type: Dictionary optional: true osver: {ios: {min: "8.0"}} - since: "6.1.0" + since: "7.1.0" --- name: UserNotificationAttachment @@ -1348,7 +1348,7 @@ summary: | Provide at least the property `identifier` and `url` property to identify a local image, sound or video. If your media is invalid, the API will throw an error log and skip the invalid attachment. -since: "6.1.0" +since: "7.1.0" platforms: [iphone, ipad] osver: {ios: {min: "10.0"}} From 8be344e1813991836cea34c7d41f1505134106f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 09:38:43 +0100 Subject: [PATCH 25/44] Resolve deprecations caused by merge --- iphone/Classes/GeolocationModule.m | 4 ++-- iphone/Classes/TiAppiOSProxy.m | 12 ++++++------ iphone/iphone/Titanium.xcodeproj/project.pbxproj | 4 ---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/iphone/Classes/GeolocationModule.m b/iphone/Classes/GeolocationModule.m index b443b30373e..d52464a4efc 100644 --- a/iphone/Classes/GeolocationModule.m +++ b/iphone/Classes/GeolocationModule.m @@ -733,7 +733,7 @@ - (void)restart:(id)arg #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_2 MAKE_SYSTEM_PROP(AUTHORIZATION_UNKNOWN, kCLAuthorizationStatusNotDetermined); -MAKE_SYSTEM_PROP(AUTHORIZATION_AUTHORIZED, kCLAuthorizationStatusAuthorized); +MAKE_SYSTEM_PROP(AUTHORIZATION_AUTHORIZED, kCLAuthorizationStatusAuthorizedAlways); MAKE_SYSTEM_PROP(AUTHORIZATION_DENIED, kCLAuthorizationStatusDenied); MAKE_SYSTEM_PROP(AUTHORIZATION_RESTRICTED, kCLAuthorizationStatusRestricted); #else @@ -823,7 +823,7 @@ - (void)requestLocationPermissions:(id)args if (requestedAuthorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) { if ([GeolocationModule hasWhenInUsePermissionKeys]) { - if ((currentPermissionLevel == kCLAuthorizationStatusAuthorizedAlways) || (currentPermissionLevel == kCLAuthorizationStatusAuthorized)) { + if (currentPermissionLevel == kCLAuthorizationStatusAuthorizedAlways) { errorMessage = @"Cannot change already granted permission from AUTHORIZATION_ALWAYS to the lower permission-level AUTHORIZATION_WHEN_IN_USE"; } else { TiThreadPerformOnMainThread(^{ diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index c2977c4d2cd..82e700ff203 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -609,10 +609,10 @@ - (id)scheduleLocalNotification:(id)args UNNotificationTrigger *trigger; if (date) { - NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; // Per default, use all components and don't repeat - NSCalendarUnit components = NSYearCalendarUnit | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + NSCalendarUnit components = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; if (repeat != nil) { if ([repeat isEqual:@"weekly"]) { @@ -745,13 +745,13 @@ - (id)scheduleLocalNotification:(id)args if (repeat != nil) { if ([repeat isEqual:@"weekly"]) { - content.repeatInterval = NSWeekCalendarUnit; + content.repeatInterval = NSCalendarUnitWeekOfYear; } else if ([repeat isEqual:@"daily"]) { - content.repeatInterval = NSDayCalendarUnit; + content.repeatInterval = NSCalendarUnitDay; } else if ([repeat isEqual:@"yearly"]) { - content.repeatInterval = NSYearCalendarUnit; + content.repeatInterval = NSCalendarUnitYear; } else if ([repeat isEqual:@"monthly"]) { - content.repeatInterval = NSMonthCalendarUnit; + content.repeatInterval = NSCalendarUnitMonth; } } diff --git a/iphone/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/iphone/Titanium.xcodeproj/project.pbxproj index 4aa9218f190..3dee716fab5 100644 --- a/iphone/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/iphone/Titanium.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ 15CB44151C4ED54E00D81480 /* TiUIiOSSystemButtonProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 15CB44141C4ED54E00D81480 /* TiUIiOSSystemButtonProxy.m */; }; 15CB44191C4EEFF500D81480 /* TiUIiOSSystemIconProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 15CB44181C4EEFF500D81480 /* TiUIiOSSystemIconProxy.m */; }; 1953DD631E0A5E6E00414348 /* TiAppiOSUserActivityProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1953DD621E0A5E6E00414348 /* TiAppiOSUserActivityProxy.m */; }; - 1953DD641E0A5EBA00414348 /* TiAppiOSUserActivityProxy.h in Sources */ = {isa = PBXBuildFile; fileRef = 1953DD611E0A5E6E00414348 /* TiAppiOSUserActivityProxy.h */; }; 1D0061C1160283820016BBEE /* TiBindingRunLoop.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0061C0160283820016BBEE /* TiBindingRunLoop.m */; }; 1D1029A815F9769200372EC0 /* TiBindingEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D1029A715F9769100372EC0 /* TiBindingEvent.m */; }; 1D19459613FF3BC400E2B4D0 /* TIDOMDOMImplementationProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D19459513FF3BC400E2B4D0 /* TIDOMDOMImplementationProxy.m */; }; @@ -1095,8 +1094,6 @@ BB26FC7F19AB13B9007A35AF /* TiAppiOSUserNotificationCategoryProxy.m */, 3A3BBAF31D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.h */, 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */, - 83924E861B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.h */, - 83924E871B4C3FA200C3F3E8 /* TiAppiOSUserActivityProxy.m */, CEBC156F1A95452000CB7B66 /* TiAppiOSUserDefaultsProxy.h */, CEBC15701A95452000CB7B66 /* TiAppiOSUserDefaultsProxy.m */, CA0D39E31B7F55C6009D534C /* TiAppiOSSearchableItemAttributeSetProxy.h */, @@ -2528,7 +2525,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1953DD641E0A5EBA00414348 /* TiAppiOSUserActivityProxy.h in Sources */, AD3174C21D015DA9000D5F1A /* TiCalendarAttendee.m in Sources */, 243ECCB21126984E00639DF4 /* TiUITableViewAction.m in Sources */, 243ECCB71126986F00639DF4 /* TiFile.m in Sources */, From 11dbaa2a8ccbc617e27c89b8bd79e14f13afa246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 09:52:39 +0100 Subject: [PATCH 26/44] Fix warnings --- iphone/Classes/KrollBridge.m | 2 +- iphone/Classes/TiApp.m | 5 +++-- iphone/Classes/TiAppiOSLocalNotificationProxy.m | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/iphone/Classes/KrollBridge.m b/iphone/Classes/KrollBridge.m index 695de69c493..565fb9fa837 100644 --- a/iphone/Classes/KrollBridge.m +++ b/iphone/Classes/KrollBridge.m @@ -69,7 +69,7 @@ - (id)initWithContext:(KrollContext *)context_ host:(TiHost *)host_ context:(id< [sharedAnalytics performSelector:@selector(setBuildType:) withObject:TI_APPLICATION_BUILD_TYPE]; } [sharedAnalytics performSelector:@selector(setSDKVersion:) withObject:[NSString stringWithFormat:@"ti.%@", [module performSelector:@selector(version)]]]; - [sharedAnalytics enableWithAppKey:TI_APPLICATION_GUID andDeployType:TI_APPLICATION_DEPLOYTYPE]; + [sharedAnalytics performSelector:@selector(enableWithAppKey:andDeployType:) withObject:TI_APPLICATION_GUID withObject:TI_APPLICATION_DEPLOYTYPE]; } } return self; diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 2f488d63edd..91bb1d2f09b 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -532,7 +532,8 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); } -- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response + withCompletionHandler:(void (^)(void))completionHandler { /*RELEASE_TO_NIL(remoteNotification); [self generateNotification:userInfo]; @@ -775,7 +776,7 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N #pragma mark Background Transfer Service iOS 7 //Delegate callback for Background Transfer completes. -- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler +- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler { //FunctionName(); // Generate unique key with timestamp. diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 1ea6091c3ef..5401e97d06a 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -26,12 +26,12 @@ - (NSString *)apiName - (void)cancel:(id)unused { - DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"7.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); - return; + NSString *identifier = [(UNMutableNotificationContent *)self.notification categoryIdentifier] ?: @"notification"; + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifier]]; #endif } else { UILocalNotification *cancelledNotification = [self.notification retain]; From 2e0a13b0f7ffba170b941193cf6be183cfe36758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 10:16:18 +0100 Subject: [PATCH 27/44] Restore TiApp --- iphone/Classes/TiApp.h | 11 +- iphone/Classes/TiApp.m | 235 +++++++++++++++++++++-------------------- 2 files changed, 127 insertions(+), 119 deletions(-) diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index 11029092828..b1959180163 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -6,9 +6,11 @@ */ #import + #if IS_XCODE_8 #import #endif + #import "KrollBridge.h" #import "TiHost.h" #ifdef USE_TI_UIWEBVIEW @@ -30,13 +32,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on TiApp represents an instance of an application. There is always only one instance per application which could be accessed through class method. @see app */ - -#if IS_XCODE_8 -@interface TiApp : TiHost -#else -@interface TiApp : TiHost -#endif -{ +@interface TiApp : TiHost { UIWindow *window; UIImageView *loadView; UIImageView *splashScreenImage; @@ -63,6 +59,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on NSMutableDictionary *pendingCompletionHandlers; NSMutableDictionary *pendingReplyHandlers; NSMutableDictionary *backgroundTransferCompletionHandlers; + NSMutableDictionary *queuedBootEvents; BOOL appBooted; NSString *sessionId; diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 91bb1d2f09b..76df32df9e8 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -130,6 +130,15 @@ + (TiContextGroupRef)contextGroup return [sharedApp contextGroup]; } +- (NSMutableDictionary *)queuedBootEvents +{ + if (queuedBootEvents == nil) { + queuedBootEvents = [[[NSMutableDictionary alloc] init] retain]; + } + + return queuedBootEvents; +} + - (void)startNetwork { ENSURE_UI_THREAD_0_ARGS; @@ -306,13 +315,17 @@ - (void)booted:(id)bridge appBooted = YES; if (launchedShortcutItem != nil) { - [self handleShortcutItem:launchedShortcutItem waitForBootIfNotLaunched:YES]; + [self handleShortcutItem:launchedShortcutItem queueToBootIfNotLaunched:YES]; RELEASE_TO_NIL(launchedShortcutItem); } - if (localNotification != nil) { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; + if (queuedBootEvents != nil) { + for (NSString *notificationName in queuedBootEvents) { + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:[queuedBootEvents objectForKey:notificationName]]; + } + RELEASE_TO_NIL(queuedBootEvents); } + TiThreadPerformOnMainThread(^{ [self validator]; }, @@ -346,24 +359,6 @@ - (UIImageView *)splashScreenImage (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation] resultingOrientation:&imageOrientation idiom:&imageIdiom]; - if ([TiUtils isIPad] && ![TiUtils isIOS8OrGreater]) { - CGAffineTransform transform; - switch ([[UIApplication sharedApplication] statusBarOrientation]) { - case UIInterfaceOrientationPortraitUpsideDown: - transform = CGAffineTransformMakeRotation(M_PI); - break; - case UIInterfaceOrientationLandscapeLeft: - transform = CGAffineTransformMakeRotation(-M_PI_2); - break; - case UIInterfaceOrientationLandscapeRight: - transform = CGAffineTransformMakeRotation(M_PI_2); - break; - default: - transform = CGAffineTransformIdentity; - break; - } - [splashScreenImage setTransform:transform]; - } [splashScreenImage setImage:defaultImage]; [splashScreenImage setFrame:[[UIScreen mainScreen] bounds]]; } @@ -424,7 +419,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [launchOptions setObject:NUMBOOL([[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey] boolValue]) forKey:@"launchOptionsLocationKey"]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocationKey]; - localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] withIdentifier:nil] retain]; + localNotification = [[[self class] dictionaryWithLocalNotification:[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]] retain]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; // reset these to be a little more common if we have them @@ -489,7 +484,6 @@ - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceAppl - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { - //Only for simulator builds NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; if ([backgroundModes containsObject:@"fetch"]) { @@ -504,10 +498,8 @@ - (void)application:(UIApplication *)application performFetchWithCompletionHandl [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; - // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called - // the bridge completes processing of app.js (adding the event into notification center). - - [self postNotificationwithKey:[NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil] withNotificationName:kTiBackgroundFetchNotification]; + [self tryToPostBackgroundModeNotification:[NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil] + withNotificationName:kTiBackgroundFetchNotification]; // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. NSTimer *flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO]; @@ -521,7 +513,9 @@ - (void)application:(UIApplication *)application performFetchWithCompletionHandl - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification object:notificationSettings userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification + object:self + userInfo:@{ @"userNotificationSettings" : notificationSettings }]; } #if IS_XCODE_8 @@ -533,22 +527,22 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response - withCompletionHandler:(void (^)(void))completionHandler + withCompletionHandler:(void (^)(void))completionHandler { /*RELEASE_TO_NIL(remoteNotification); - [self generateNotification:userInfo]; - NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; - event[@"data"] = remoteNotification; - if (identifier != nil) { - event[@"identifier"] = identifier; - } - NSString *category = remoteNotification[@"category"]; - if (category != nil) { - event[@"category"] = category; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; - [event autorelease]; - completionHandler();*/ + [self generateNotification:userInfo]; + NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; + event[@"data"] = remoteNotification; + if (identifier != nil) { + event[@"identifier"] = identifier; + } + NSString *category = remoteNotification[@"category"]; + if (category != nil) { + event[@"category"] = category; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; + [event autorelease]; + completionHandler();*/ // TODO: Find out where the payload is stored to handle the above @@ -573,39 +567,31 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNoti - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; + localNotification = [[TiApp dictionaryWithLocalNotification:notification withIdentifier:identifier] retain]; if ([TiUtils isIOS9OrGreater] == YES) { [localNotification setValue:responseInfo[UIUserNotificationActionResponseTypedTextKey] forKey:@"typedText"]; } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; - completionHandler(); + [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotificationAction completionHandler:completionHandler]; } -- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification +// iOS 9+ +- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { - RELEASE_TO_NIL(localNotification); - localNotification = [[[self class] dictionaryWithLocalNotification:notification withIdentifier:nil] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotification object:localNotification userInfo:nil]; + [self handleRemoteNotificationWithIdentifier:identifier + andUserInfo:userInfo + responseInfo:responseInfo + completionHandler:completionHandler]; } +// iOS < 9 - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { - RELEASE_TO_NIL(remoteNotification); - [self generateNotification:userInfo]; - NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; - event[@"data"] = remoteNotification; - if (identifier != nil) { - event[@"identifier"] = identifier; - } - NSString *category = remoteNotification[@"category"]; - if (category != nil) { - event[@"category"] = category; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; - [event autorelease]; - completionHandler(); + [self handleRemoteNotificationWithIdentifier:identifier + andUserInfo:userInfo + responseInfo:nil // iOS 9+ only + completionHandler:completionHandler]; } #pragma mark Apple Watchkit handleWatchKitExtensionRequest @@ -653,9 +639,27 @@ - (void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary *)use #pragma mark Helper Methods -- (void)postNotificationwithKey:(NSMutableDictionary *)userInfo withNotificationName:(NSString *)notificationName +- (void)tryToPostNotification:(NSDictionary *)_notification withNotificationName:(NSString *)_notificationName completionHandler:(void (^)())completionHandler { + typedef void (^NotificationBlock)(); + NotificationBlock myNotificationBlock = ^void() { + [[NSNotificationCenter defaultCenter] postNotificationName:_notificationName object:self userInfo:_notification]; + + if (completionHandler != nil) { + completionHandler(); + } + }; + + if (appBooted) { + myNotificationBlock(); + } else { + [[self queuedBootEvents] setObject:_notification forKey:_notificationName]; + } +} + +- (void)tryToPostBackgroundModeNotification:(NSMutableDictionary *)userInfo withNotificationName:(NSString *)notificationName +{ //Check to see if the app booted and we still have the completionhandler in the system NSString *key = [userInfo objectForKey:@"handlerId"]; BOOL shouldContinue = NO; @@ -672,17 +676,13 @@ - (void)postNotificationwithKey:(NSMutableDictionary *)userInfo withNotification if (appBooted) { [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo]; } else { - //Try again in 2 sec. TODO: should we reduce this value ? - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self postNotificationwithKey:userInfo withNotificationName:notificationName]; - }); + [[self queuedBootEvents] setObject:userInfo forKey:notificationName]; } } //Clear out the pendingCompletionHandlerQueue - (void)flushCompletionHandlerQueue { - //FunctionName(); if (pendingCompletionHandlers != nil) { for (id key in pendingCompletionHandlers) { [self completionHandler:key withResult:2]; //UIBackgroundFetchResultFailed @@ -694,7 +694,6 @@ - (void)flushCompletionHandlerQueue // This method gets called when the wall clock runs out and the completionhandler is still there. - (void)fireCompletionHandler:(NSTimer *)timer { - //FunctionName(); id key = timer.userInfo; if ([pendingCompletionHandlers objectForKey:key]) { [self completionHandler:key withResult:UIBackgroundFetchResultFailed]; @@ -702,10 +701,9 @@ - (void)fireCompletionHandler:(NSTimer *)timer } } -// gets called when user ends finishes with backgrounding stuff. By default this would always be called with UIBackgroundFetchResultNoData. +// Gets called when user ends finishes with backgrounding stuff. By default this would always be called with UIBackgroundFetchResultNoData. - (void)completionHandler:(id)key withResult:(int)result { - //FunctionName(); if ([pendingCompletionHandlers objectForKey:key]) { void (^completionHandler)(UIBackgroundFetchResult); completionHandler = [pendingCompletionHandlers objectForKey:key]; @@ -733,11 +731,10 @@ - (void)completionHandlerForBackgroundTransfer:(id)key #pragma mark Remote Notifications iOS 7 #ifdef USE_TI_SILENTPUSH -//Delegate callback for Silent Remote Notification. +// Delegate callback for Silent Remote Notification. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - //FunctionName(); - //Forward the callback + // Forward the callback if ([self respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) { [self application:application didReceiveRemoteNotification:userInfo]; } @@ -757,12 +754,11 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N [pendingCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; - // Handling the case, where the app is not running and backgroundfetch launches the app into background. In this case, the delegate gets called - // the bridge completes processing of app.js (adding the event into notification center). - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil]; [dict addEntriesFromDictionary:userInfo]; - [self postNotificationwithKey:dict withNotificationName:kTiSilentPushNotification]; + + [self tryToPostBackgroundModeNotification:dict + withNotificationName:kTiSilentPushNotification]; // We will go ahead and keeper a timer just in case the user returns the value too late - this is the worst case scenario. NSTimer *flushTimer = [NSTimer timerWithTimeInterval:TI_BACKGROUNDFETCH_MAX_INTERVAL target:self selector:@selector(fireCompletionHandler:) userInfo:key repeats:NO]; @@ -778,7 +774,6 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N //Delegate callback for Background Transfer completes. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler { - //FunctionName(); // Generate unique key with timestamp. id key = [NSString stringWithFormat:@"Session-%f", [[NSDate date] timeIntervalSince1970]]; @@ -790,7 +785,7 @@ - (void)application:(UIApplication *)application handleEventsForBackgroundURLSes [backgroundTransferCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:identifier, @"sessionId", key, @"handlerId", nil]; - [self postNotificationwithKey:dict withNotificationName:kTiBackgroundTransfer]; + [self tryToPostBackgroundModeNotification:dict withNotificationName:kTiBackgroundTransfer]; } #pragma mark Background Transfer Service Delegates. @@ -799,8 +794,7 @@ - (void)application:(UIApplication *)application handleEventsForBackgroundURLSes - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { - //FunctionName(); - //copy downloaded file from location to tempFile (in NSTemporaryDirectory), because file in location will be removed after delegate completes + // Copy downloaded file from location to tempFile (in NSTemporaryDirectory), because file in location will be removed after delegate completes NSError *error; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *destinationFilename = location.lastPathComponent; @@ -861,8 +855,6 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSend - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - //FunctionName(); - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithUnsignedInteger:task.taskIdentifier], @"taskIdentifier", nil]; @@ -1038,7 +1030,6 @@ - (void)applicationDidBecomeActive:(UIApplication *)application - (void)applicationDidEnterBackground:(UIApplication *)application { - //FunctionName(); [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; if (backgroundServices == nil) { @@ -1071,7 +1062,6 @@ - (void)applicationDidEnterBackground:(UIApplication *)application - (void)applicationWillEnterForeground:(UIApplication *)application { - //FunctionName(); Uncomment to see function name printed when it is called. [self flushCompletionHandlerQueue]; [sessionId release]; sessionId = [[TiUtils createUUID] retain]; @@ -1124,9 +1114,7 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct if (appBooted) { [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; } else { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; - }); + [[self queuedBootEvents] setObject:dict forKey:kTiContinueActivity]; } return YES; @@ -1296,10 +1284,16 @@ - (void)endBackgrounding RELEASE_TO_NIL(runningServices); } -- (BOOL)handleShortcutItem:(UIApplicationShortcutItem *)shortcutItem - waitForBootIfNotLaunched:(BOOL)bootWait +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { + RELEASE_TO_NIL(localNotification); + localNotification = [[[self class] dictionaryWithLocalNotification:notification] retain]; + [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotification completionHandler:nil]; +} + +- (BOOL)handleShortcutItem:(UIApplicationShortcutItem *)shortcutItem queueToBootIfNotLaunched:(BOOL)bootWait +{ if (shortcutItem.type == nil) { NSLog(@"[ERROR] The shortcut type property is required"); return NO; @@ -1328,25 +1322,44 @@ - (BOOL)handleShortcutItem:(UIApplicationShortcutItem *)shortcutItem [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationShortcut object:self userInfo:dict]; - } else { - if (bootWait) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationShortcut - object:self - userInfo:dict]; - }); - } + } else if (bootWait) { + [[self queuedBootEvents] setObject:dict forKey:kTiApplicationShortcut]; } return YES; } +- (void)handleRemoteNotificationWithIdentifier:(NSString *)identifier + andUserInfo:(NSDictionary *)userInfo + responseInfo:(NSDictionary *)responseInfo + completionHandler:(void (^)())completionHandler +{ + RELEASE_TO_NIL(remoteNotification); + [self generateNotification:userInfo]; + + NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; + NSString *category = remoteNotification[@"category"]; + + event[@"data"] = remoteNotification; + + if (identifier != nil) { + event[@"identifier"] = identifier; + } + if (responseInfo[UIUserNotificationActionResponseTypedTextKey] != nil) { + event[@"typedText"] = responseInfo[UIUserNotificationActionResponseTypedTextKey]; + } + if (category != nil) { + event[@"category"] = category; + } + + [self tryToPostNotification:[event autorelease] withNotificationName:kTiRemoteNotificationAction completionHandler:completionHandler]; +} + - (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler { - - BOOL handledShortCutItem = [self handleShortcutItem:shortcutItem waitForBootIfNotLaunched:NO]; + BOOL handledShortCutItem = [self handleShortcutItem:shortcutItem queueToBootIfNotLaunched:NO]; completionHandler(handledShortCutItem); } @@ -1424,25 +1437,23 @@ + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notific NSMutableDictionary *event = [NSMutableDictionary dictionary]; [event setObject:NOTNIL([notification fireDate]) forKey:@"date"]; [event setObject:NOTNIL([[notification timeZone] name]) forKey:@"timezone"]; + [event setObject:NOTNIL([notification alertTitle]) forKey:@"alertTitle"]; [event setObject:NOTNIL([notification alertBody]) forKey:@"alertBody"]; [event setObject:NOTNIL([notification alertAction]) forKey:@"alertAction"]; [event setObject:NOTNIL([notification alertLaunchImage]) forKey:@"alertLaunchImage"]; [event setObject:NOTNIL([notification soundName]) forKey:@"sound"]; [event setObject:NUMINTEGER([notification applicationIconBadgeNumber]) forKey:@"badge"]; [event setObject:NOTNIL([notification userInfo]) forKey:@"userInfo"]; - - // Include category for iOS 8 - if ([TiUtils isIOS8OrGreater]) { - [event setObject:NOTNIL([notification category]) forKey:@"category"]; - } - - // Include title for iOS 8.2 - if ([TiUtils isIOS82rGreater]) { - [event setObject:NOTNIL([notification alertTitle]) forKey:@"alertTitle"]; - } + [event setObject:NOTNIL([notification category]) forKey:@"category"]; + [event setObject:NOTNIL(identifier) forKey:@"identifier"]; + [event setObject:NUMBOOL([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) forKey:@"inBackground"]; return event; } ++ (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification +{ + return [self dictionaryWithLocalNotification:notification withIdentifier:nil]; +} // Returns an NSDictionary with the properties from tiapp.xml // this is called from Ti.App.Properties and other places. From 9d76105bd7da52680b7a60c8c47f0f1d747c1b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 10:23:57 +0100 Subject: [PATCH 28/44] Remove old statements --- iphone/Classes/TiAppiOSProxy.m | 116 ++++++++++++--------------------- 1 file changed, 42 insertions(+), 74 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 82e700ff203..f8c557a11a5 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -99,25 +99,22 @@ - (void)_listenerAdded:(NSString *)type count:(int)count if ((count == 1) && [type isEqual:@"uploadprogress"]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveUploadProgressNotification:) name:kTiURLUploadProgress object:nil]; } - if ([TiUtils isIOS8OrGreater]) { - if ((count == 1) && [type isEqual:@"usernotificationsettings"]) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector - (didRegisterUserNotificationSettingsNotification:) - name:kTiUserNotificationSettingsNotification - object:nil]; - } - if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didReceiveWatchExtensionRequestNotification:) - name:kTiWatchKitExtensionRequest - object:nil]; - } - if ((count == 1) && [type isEqual:@"continueactivity"]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveContinueActivityNotification:) name:kTiContinueActivity object:nil]; - } + if ((count == 1) && [type isEqual:@"usernotificationsettings"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector + (didRegisterUserNotificationSettingsNotification:) + name:kTiUserNotificationSettingsNotification + object:nil]; + } + if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveWatchExtensionRequestNotification:) + name:kTiWatchKitExtensionRequest + object:nil]; + } + if ((count == 1) && [type isEqual:@"continueactivity"]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveContinueActivityNotification:) name:kTiContinueActivity object:nil]; } - if ([TiUtils isIOS9OrGreater]) { if ((count == 1) && [type isEqual:@"shortcutitemclick"]) { [[NSNotificationCenter defaultCenter] addObserver:self @@ -172,17 +169,14 @@ - (void)_listenerRemoved:(NSString *)type count:(int)count if ((count == 1) && [type isEqual:@"uploadprogress"]) { [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLUploadProgress object:nil]; } - - if ([TiUtils isIOS8OrGreater]) { - if ((count == 1) && [type isEqual:@"usernotificationsetting"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiUserNotificationSettingsNotification object:nil]; - } - if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiWatchKitExtensionRequest object:nil]; - } - if ((count == 1) && [type isEqual:@"continueactivity"]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiContinueActivity object:nil]; - } + if ((count == 1) && [type isEqual:@"usernotificationsetting"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiUserNotificationSettingsNotification object:nil]; + } + if ((count == 1) && [type isEqual:@"watchkitextensionrequest"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiWatchKitExtensionRequest object:nil]; + } + if ((count == 1) && [type isEqual:@"continueactivity"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kTiContinueActivity object:nil]; } if ([TiUtils isIOS9OrGreater]) { @@ -392,9 +386,6 @@ - (id)registerBackgroundService:(id)args - (void)registerUserNotificationSettings:(id)args { - if (![TiUtils isIOS8OrGreater]) - return; - ENSURE_SINGLE_ARG(args, NSDictionary); NSArray *categories; @@ -509,10 +500,6 @@ - (id)createUserNotificationCategory:(id)args - (NSArray *)supportedUserActivityTypes { - if (![TiUtils isIOS8OrGreater]) { - return nil; - } - NSArray *supportedActivityTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSUserActivityTypes"]; @@ -521,11 +508,7 @@ - (NSArray *)supportedUserActivityTypes - (NSDictionary *)currentUserNotificationSettings { - if (![TiUtils isIOS8OrGreater]) { - return nil; - } - - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"6.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"7.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 @@ -812,13 +795,11 @@ - (id)scheduleLocalNotification:(id)args content.userInfo = userInfo; } - if ([TiUtils isIOS8OrGreater]) { - id category = [args objectForKey:@"category"]; - if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { - content.category = [(TiAppiOSUserNotificationCategoryProxy *)category identifier]; - } else if (category != nil && [category isKindOfClass:[NSString class]]) { - content.category = category; - } + id category = [args objectForKey:@"category"]; + if (category != nil && [category isKindOfClass:[TiAppiOSUserNotificationCategoryProxy class]]) { + content.category = [(TiAppiOSUserNotificationCategoryProxy *)category identifier]; + } else if (category != nil && [category isKindOfClass:[NSString class]]) { + content.category = category; } TiThreadPerformOnMainThread(^{ @@ -968,10 +949,6 @@ - (void)sendWatchExtensionReply:(id)args if ([TiUtils isIOS9OrGreater]) { DebugLog(@"[WARN] Deprecated. Please use Ti.App.iOS.WatchConnectivity instead"); } - if (![TiUtils isIOS8OrGreater]) { - return; - } - enum Args { kArgKey = 0, kArgCount, @@ -1024,10 +1001,9 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_NONE #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionNone); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeNone); } - return NUMINT(0); + + return NUMINT(UIUserNotificationTypeNone); } - (NSNumber *)USER_NOTIFICATION_TYPE_BADGE @@ -1036,10 +1012,9 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_BADGE #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionBadge); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeBadge); } - return NUMINT(0); + + return NUMINT(UIUserNotificationTypeBadge); } - (NSNumber *)USER_NOTIFICATION_TYPE_SOUND @@ -1048,10 +1023,9 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_SOUND #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionSound); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeSound); } - return NUMINT(0); + + return NUMINT(UIUserNotificationTypeSound); } - (NSNumber *)USER_NOTIFICATION_TYPE_ALERT @@ -1060,10 +1034,9 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_ALERT #if IS_XCODE_8 return NUMINT(UNAuthorizationOptionAlert); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationTypeAlert); } - return NUMINT(0); + + return NUMINT(UIUserNotificationTypeAlert); } - (NSNumber *)USER_NOTIFICATION_TYPE_CAR_PLAY @@ -1082,10 +1055,9 @@ - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND #if IS_XCODE_8 return NUMINT(UNNotificationActionOptionNone); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationActivationModeBackground); } - return NUMINT(0); + + return NUMINT(UIUserNotificationActivationModeBackground); } - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND @@ -1094,10 +1066,9 @@ - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND #if IS_XCODE_8 return NUMINT(UNNotificationActionOptionForeground); #endif - } else if ([TiUtils isIOS8OrGreater]) { - return NUMINT(UIUserNotificationActivationModeForeground); } - return NUMINT(0); + + return NUMINT(UIUserNotificationActivationModeForeground); } - (NSNumber *)USER_NOTIFICATION_BEHAVIOR_DEFAULT @@ -1334,10 +1305,7 @@ - (CFStringRef)UTTYPE_APPLE_PROTECTED_MPEG4_AUDIO - (NSString *)applicationOpenSettingsURL { - if ([TiUtils isIOS8OrGreater]) { - return UIApplicationOpenSettingsURLString; - } - return nil; + return UIApplicationOpenSettingsURLString; } MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_LAYOUT_CHANGED, @"accessibilitylayoutchanged"); From 82045264df17078f5569616827062d4a9a8fee01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 10:42:58 +0100 Subject: [PATCH 29/44] Migrate more classes --- iphone/Classes/TiApp.m | 2 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 11 ++++- iphone/Classes/TiAppiOSProxy.m | 40 ++++++++----------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 76df32df9e8..d1bce4c3982 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -77,7 +77,7 @@ - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withConte - (void)serviceExtensionTimeWillExpire { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:@{} userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:self userInfo:nil]; } @end diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 5401e97d06a..3015c6dad14 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -30,8 +30,15 @@ - (void)cancel:(id)unused if ([TiUtils isIOS10OrGreater]) { #if IS_XCODE_8 - NSString *identifier = [(UNMutableNotificationContent *)self.notification categoryIdentifier] ?: @"notification"; - [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifier]]; + NSString *identifier = @"notification"; + NSDictionary *userInfo = [(UNMutableNotificationContent *)self.notification userInfo]; + + if (userInfo != nil) { + if ([userInfo objectForKey:@"id"] != nil) { + identifier = [TiUtils stringValue:[userInfo objectForKey:@"id"]]; + } + } + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[ [TiUtils stringValue:identifier] ]]; #endif } else { UILocalNotification *cancelledNotification = [self.notification retain]; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index f8c557a11a5..2429d74e9ed 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -676,7 +676,7 @@ - (id)scheduleLocalNotification:(id)args options:_options error:&error]; if (error != nil) { - NSLog(@"[ERROR] The attachment \"%@\" is invalid: %@", _identifier, [error localizedDescription]); + NSLog(@"[ERROR] Attachment with the identifier = \"%@\" is invalid: %@", _identifier, [error localizedDescription]); } else { [_attachments addObject:_attachment]; } @@ -825,30 +825,27 @@ - (void)cancelAllLocalNotifications:(id)unused DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removeAllPendingNotifications in iOS 10 and later."); -#endif + [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; } else { [[UIApplication sharedApplication] cancelAllLocalNotifications]; } } -- (void)cancelLocalNotification:(id)args +- (void)cancelLocalNotification:(id)value { - ENSURE_SINGLE_ARG(args, NSObject); - ENSURE_UI_THREAD(cancelLocalNotification, args); + ENSURE_SINGLE_ARG(value, NSObject); + ENSURE_UI_THREAD(cancelLocalNotification, value); DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 - DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers in iOS 10 and later."); -#endif + NSString *identifier = [TiUtils stringValue:value] ?: @"notification"; + [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[ identifier ]]; } else { NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; if (notifications != nil) { for (UILocalNotification *notification in notifications) { - if ([[[notification userInfo] objectForKey:@"id"] isEqual:args]) { + if ([[[notification userInfo] objectForKey:@"id"] isEqual:[TiUtils stringValue:value]]) { [[UIApplication sharedApplication] cancelLocalNotification:notification]; return; } @@ -857,34 +854,29 @@ - (void)cancelLocalNotification:(id)args } } -- (void)didReceiveContinueActivityNotification:(NSNotification *)notif +- (void)didReceiveContinueActivityNotification:(NSNotification *)note { - NSDictionary *notification = [notif userInfo]; - [self fireEvent:@"continueactivity" withObject:notification]; + [self fireEvent:@"continueactivity" withObject:[note userInfo]]; } - (void)didReceiveLocalNotification:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"notification" withObject:notification]; + [self fireEvent:@"notification" withObject:[note userInfo]]; } - (void)didReceiveLocalNotificationAction:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"localnotificationaction" withObject:notification]; + [self fireEvent:@"localnotificationaction" withObject:[note userInfo]]; } - (void)didReceiveRemoteNotificationAction:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"remotenotificationaction" withObject:notification]; + [self fireEvent:@"remotenotificationaction" withObject:[note userInfo]]; } - (void)remoteExtensionWillExpire:(NSNotification *)note { - NSDictionary *notification = [note object]; - [self fireEvent:@"remoteextentionwillexpire" withObject:notification]; + [self fireEvent:@"remoteextentionwillexpire" withObject:[note userInfo]]; } - (void)didReceiveBackgroundFetchNotification:(NSNotification *)note @@ -926,10 +918,10 @@ - (void)didReceiveUploadProgressNotification:(NSNotification *)note [self fireEvent:@"uploadprogress" withObject:[note userInfo]]; } -- (void)didRegisterUserNotificationSettingsNotification:(NSNotification *)notificationSettings +- (void)didRegisterUserNotificationSettingsNotification:(NSNotification *)note { [self fireEvent:@"usernotificationsettings" - withObject:[self formatUserNotificationSettings:(UIUserNotificationSettings *)[notificationSettings object]]]; + withObject:[self formatUserNotificationSettings:(UIUserNotificationSettings *)[[note userInfo] valueForKey:@"userNotificationSettings"]]]; } #pragma mark Apple Watchkit notifications From 01e2acb63a9c894cdc4392c914ed366658ab38b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 10:48:54 +0100 Subject: [PATCH 30/44] Fix typos, use DebugLog --- iphone/Classes/TiAppiOSProxy.m | 6 +++--- iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m | 6 +++--- iphone/Classes/TiAppiOSUserNotificationCenterProxy.m | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 2429d74e9ed..9ae6f5e1c6c 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -607,7 +607,7 @@ - (id)scheduleLocalNotification:(id)args } else if ([repeat isEqual:@"monthly"]) { components = NSCalendarUnitMonth; } else { - NSLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); + DebugLog(@"[ERROR] Unknown `repeat` value specified. Disabling repeat-behavior."); } } @@ -676,7 +676,7 @@ - (id)scheduleLocalNotification:(id)args options:_options error:&error]; if (error != nil) { - NSLog(@"[ERROR] Attachment with the identifier = \"%@\" is invalid: %@", _identifier, [error localizedDescription]); + DebugLog(@"[ERROR] Attachment with the identifier = \"%@\" is invalid: %@", _identifier, [error localizedDescription]); } else { [_attachments addObject:_attachment]; } @@ -769,7 +769,7 @@ - (id)scheduleLocalNotification:(id)args CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); if (!CLLocationCoordinate2DIsValid(center)) { - NSLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); + DebugLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); RELEASE_TO_NIL(content); return; } diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 8e252474540..0f622ae2ad3 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -45,9 +45,9 @@ - (void)_initWithProperties:(NSDictionary *)properties } if (intentIdentifiers) { - for (id itentIdentifier in intentIdentifiers) { - if (![itentIdentifier isKindOfClass:[NSString class]]) { - NSLog(@"[ERROR] All elements in itentIdentifiers must be a String, \"%@\" is not!", itentIdentifier); + for (id intentIdentifier in intentIdentifiers) { + if (![intentIdentifier isKindOfClass:[NSString class]]) { + DebugLog(@"[ERROR] All elements in \"intentIdentifiers\" must be a String, \"%@\" is not!", intentIdentifier); } } } diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 797d1fbcc63..f8917b38709 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -86,7 +86,7 @@ - (void)getDeliveredNotifications:(id)args NO); #endif } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); + DebugLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); } } @@ -108,7 +108,7 @@ - (void)removePendingNotifications:(id)args // Loop through current notification requests for (UNNotificationRequest *request in requests) { - // Loop throigh provided notifications + // Loop through provided notifications for (id notification in args) { ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); @@ -156,7 +156,7 @@ - (void)removeDeliveredNotifications:(id)args // Loop through current notification requests for (UNNotificationRequest *request in requests) { - // Loop throigh provided notifications + // Loop through provided notifications for (id notification in args) { ENSURE_TYPE(notification, TiAppiOSLocalNotificationProxy); @@ -170,7 +170,7 @@ - (void)removeDeliveredNotifications:(id)args NO); #endif } else { - NSLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only avaible in iOS 10 and later."); + DebugLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only available in iOS 10 and later."); } } From 7b553066364b9f65d0b7a2c22608f13db2e21d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 10:58:23 +0100 Subject: [PATCH 31/44] More small fixes --- iphone/Classes/TiAppiOSProxy.m | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 9ae6f5e1c6c..a2fa9aa85bc 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -656,7 +656,13 @@ - (id)scheduleLocalNotification:(id)args } if (userInfo) { - [content setUserInfo:userInfo]; + if (identifier != nil && ![userInfo objectForKey:@"id"]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:userInfo]; + [dict setObject:identifier forKey:@"id"]; + [content setUserInfo:dict]; + } else { + [content setUserInfo:userInfo]; + } } if (attachments) { @@ -761,26 +767,20 @@ - (id)scheduleLocalNotification:(id)args if (region != nil) { ENSURE_TYPE(region, NSDictionary); + CLLocationDegrees latitude = [TiUtils doubleValue:@"latitude" properties:region def:0]; + CLLocationDegrees longitude = [TiUtils doubleValue:@"longitude" properties:region def:0]; + CLLocationDistance radius = [TiUtils doubleValue:@"radius" properties:region def:kCLDistanceFilterNone]; + NSString *regionIdentifier = [TiUtils stringValue:@"identifier" properties:region def:@"notification"]; BOOL regionTriggersOnce = [TiUtils boolValue:[region valueForKey:@"triggersOnce"] def:YES]; - double latitude = [TiUtils doubleValue:[region valueForKey:@"latitude"] def:0]; - double longitude = [TiUtils doubleValue:[region valueForKey:@"longitude"] def:0]; - double radius = [TiUtils doubleValue:[region valueForKey:@"radius"] def:kCLDistanceFilterNone]; CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude); if (!CLLocationCoordinate2DIsValid(center)) { DebugLog(@"[WARN] The provided region is invalid, please check your `latitude` and `longitude`!"); - RELEASE_TO_NIL(content); - return; + } else { + content.region = [[[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:regionIdentifier] autorelease]; + content.regionTriggersOnce = regionTriggersOnce; } - - content.region = [[[CLCircularRegion alloc] initWithCenter:center - radius:radius - identifier:[TiUtils stringValue:@"identifier" - properties:args - def:@"notification"]] autorelease]; - - content.regionTriggersOnce = regionTriggersOnce; } if (sound) { From ac664174d5c30dcf6270eea40997b0cbd511e402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 11:04:17 +0100 Subject: [PATCH 32/44] Fix old docs --- iphone/Classes/TiAppiOSProxy.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index a2fa9aa85bc..9135ada92ca 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -822,7 +822,7 @@ - (void)cancelAllLocalNotifications:(id)unused { ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); - DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"6.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); + DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"7.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); if ([TiUtils isIOS10OrGreater]) { [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; @@ -836,7 +836,7 @@ - (void)cancelLocalNotification:(id)value ENSURE_SINGLE_ARG(value, NSObject); ENSURE_UI_THREAD(cancelLocalNotification, value); - DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"6.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"7.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { NSString *identifier = [TiUtils stringValue:value] ?: @"notification"; From b2a7e433046525864570d0a0e7fbd67a12d5f921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 11:14:41 +0100 Subject: [PATCH 33/44] Fix docs errors --- .../Titanium/App/iOS/NotificationCenter.yml | 30 ++++++++++++------- apidoc/Titanium/App/iOS/iOS.yml | 7 +++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index 360acd29cfb..c3f3f892e7b 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -48,7 +48,10 @@ methods: summary: | Notification types and user notification categories the application is registered to use (available on iOS 8 and later). - type: UserNotificationSettings + parameters: + - name: callback + summary: The callback invoked when requesting user notification settings. + type: Callback since: "7.1.0" --- @@ -86,6 +89,7 @@ properties: summary: | Alert button text ('View', by default) or slider text ('slide to unlock...', by default). type: String + type: String - name: alertBody summary: Alert message. @@ -121,9 +125,13 @@ properties: osver: {ios: {min: "8.0"}} - name: identifier - summary: Request identifier of the notification. + summary: The notification identifier. + description: | + This property is required in iOS 10 and later and will fallback + to "notification" if not set. + optional: false + since: "7.1.0" type: String - osver: {ios: {min: "10.0"}} - name: region summary: Region of the notification. @@ -162,47 +170,47 @@ properties: - name: authorizationStatus summary: The current authorization status for using notifications. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_AUTHORIZATION_STATUS_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_AUTHORIZATION_STATUS_*] osver: {ios: {min: "10.0"}} - name: soundSetting summary: The current sound settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: badgeSetting summary: The current badge settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: alertSetting summary: The current alert settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: notificationCenterSetting summary: The current notication-center settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: lockScreenSetting summary: The current lock-screen settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: carPlaySetting summary: The current CarPlay settings. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_SETTING_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_SETTING_*] osver: {ios: {min: "10.0"}} - name: alertStyle summary: The current alert style used to display notifications. type: Number - constants: [Ti.App.iOS.USER_NOTIFICATION_ALERT_STYLE_*] + constants: [Titanium.App.iOS.USER_NOTIFICATION_ALERT_STYLE_*] osver: {ios: {min: "10.0"}} diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index 134cc30f508..cecd0c7e3c2 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -1250,13 +1250,16 @@ platforms: [iphone, ipad] properties: - name: identifier summary: The notification identifier. - description: This property is required in iOS 10 and later. + description: | + This property is required in iOS 10 and later and will fallback + to "notification" if not set. optional: false since: "7.1.0" + type: String - name: alertAction summary: | - Alert button text ('Open', by default) or slider text ('slide to unlock...', by default) + Alert button text ('Open', by default) or home text ('Press Home to Unlock', by default) to display. type: String optional: true From 900329019ff38cd9434c750618e7a1d9987bdd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Mon, 20 Nov 2017 11:31:37 +0100 Subject: [PATCH 34/44] Fix docs --- apidoc/Titanium/App/iOS/NotificationCenter.yml | 2 +- apidoc/Titanium/App/iOS/iOS.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index c3f3f892e7b..2c448f0c9aa 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -87,7 +87,7 @@ properties: - name: alertAction summary: | - Alert button text ('View', by default) or slider text ('slide to unlock...', by default). + Alert button text ('Open', by default) or home text ('Press Home to unlock', by default) type: String type: String diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index cecd0c7e3c2..a7a2ccc9d63 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -1259,7 +1259,7 @@ properties: - name: alertAction summary: | - Alert button text ('Open', by default) or home text ('Press Home to Unlock', by default) + Alert button text ('Open', by default) or home text ('Press Home to unlock', by default) to display. type: String optional: true From f0f3fd828858f80ee5c9d1b0476e09006c880435 Mon Sep 17 00:00:00 2001 From: hansemannn Date: Sun, 21 Jan 2018 20:23:25 +0100 Subject: [PATCH 35/44] Remove IS_XCODE_8 macro as min-xcode is 8.3 these days --- iphone/Classes/MediaModule.m | 5 --- iphone/Classes/SCListener.m | 4 -- iphone/Classes/TiApp.h | 5 --- iphone/Classes/TiApp.m | 6 --- .../Classes/TiAppiOSLocalNotificationProxy.h | 3 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 2 - iphone/Classes/TiAppiOSProxy.m | 41 ++----------------- iphone/Classes/TiAppiOSSearchQueryProxy.h | 4 +- iphone/Classes/TiAppiOSSearchQueryProxy.m | 5 ++- .../TiAppiOSSearchableItemAttributeSetProxy.m | 4 -- .../TiAppiOSUserNotificationActionProxy.h | 2 - .../TiAppiOSUserNotificationActionProxy.m | 29 +++++++++---- .../TiAppiOSUserNotificationCategoryProxy.h | 2 - .../TiAppiOSUserNotificationCategoryProxy.m | 2 - .../TiAppiOSUserNotificationCenterProxy.h | 3 +- .../TiAppiOSUserNotificationCenterProxy.m | 12 ------ iphone/Classes/TiMediaAudioSession.m | 4 -- iphone/Classes/TiMediaSoundProxy.h | 4 -- iphone/Classes/TiMediaSoundProxy.m | 5 --- iphone/Classes/TiUIClipboardProxy.m | 12 ------ iphone/Classes/TiUIListView.h | 5 --- iphone/Classes/TiUIListView.m | 8 ---- iphone/Classes/TiUIScrollView.h | 4 -- iphone/Classes/TiUIScrollView.m | 6 --- iphone/Classes/TiUITabGroup.m | 2 - iphone/Classes/TiUITabProxy.m | 6 --- .../Classes/TiUIiOSFeedbackGeneratorProxy.h | 3 +- .../Classes/TiUIiOSFeedbackGeneratorProxy.m | 3 +- iphone/Classes/TiUIiOSProxy.h | 2 - iphone/Classes/TiUIiOSProxy.m | 8 ---- iphone/Classes/TiUtils.m | 8 ---- iphone/Classes/UIModule.m | 4 -- iphone/Classes/WatchSessionModule.m | 6 --- iphone/iphone/Titanium_Prefix.pch | 6 --- 34 files changed, 33 insertions(+), 192 deletions(-) diff --git a/iphone/Classes/MediaModule.m b/iphone/Classes/MediaModule.m index 36ee9d205be..e8b0a6ac597 100644 --- a/iphone/Classes/MediaModule.m +++ b/iphone/Classes/MediaModule.m @@ -20,12 +20,7 @@ #import "TiViewProxy.h" #import -#if IS_XCODE_8 #import -#else -#import -#import -#endif #import #import #import diff --git a/iphone/Classes/SCListener.m b/iphone/Classes/SCListener.m index a509666455c..074a393fb9a 100644 --- a/iphone/Classes/SCListener.m +++ b/iphone/Classes/SCListener.m @@ -9,11 +9,7 @@ #if defined(USE_TI_MEDIASTARTMICROPHONEMONITOR) || defined(USE_TI_MEDIASTOPMICROPHONEMONITOR) || defined(USE_TI_MEDIAPEAKMICROPHONEPOWER) || defined(USE_TI_MEDIAGETPEAKMICROPHONEPOWER) || defined(USE_TI_MEDIAAVERAGEMICROPHONEPOWER) || defined(USE_TI_MEDIAGETAVERAGEMICROPHONEPOWER) #import "SCListener.h" -#if IS_XCODE_8 #import -#else -#import -#endif @interface SCListener (Private) diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index b1959180163..4783e3c61da 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -6,10 +6,7 @@ */ #import - -#if IS_XCODE_8 #import -#endif #import "KrollBridge.h" #import "TiHost.h" @@ -213,12 +210,10 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on */ - (NSString *)systemUserAgent; -#if IS_XCODE_8 /** Returns a dictionary containing the native notification information (iOS 10 and later). */ + (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier:(NSString *)identifier; -#endif /** Returns a dictionary containing the native notification information. diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 1408a789690..b7a22e33324 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -56,7 +56,6 @@ - (void)checkBackgroundServices; - (void)appBoot; @end -#if IS_XCODE_8 @interface TiUserNotificationExtention : UNNotificationServiceExtension @end @@ -81,7 +80,6 @@ - (void)serviceExtensionTimeWillExpire } @end -#endif @implementation TiApp @@ -518,7 +516,6 @@ - (void)application:(UIApplication *)application didRegisterUserNotificationSett userInfo:@{ @"userNotificationSettings" : notificationSettings }]; } -#if IS_XCODE_8 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { // TODO: Get desired options from notification @@ -562,7 +559,6 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNoti completionHandler(); } -#endif - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { @@ -1404,7 +1400,6 @@ - (void)stopBackgroundService:(TiProxy *)proxy #define NOTNIL(v) ((v == nil) ? (id)[NSNull null] : v) -#if IS_XCODE_8 + (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification withIdentifier:(NSString *)identifier { if (notification == nil) { @@ -1426,7 +1421,6 @@ + (NSDictionary *)dictionaryWithUserNotification:(UNNotification *)notification return event; } -#endif + (NSDictionary *)dictionaryWithLocalNotification:(UILocalNotification *)notification withIdentifier:(NSString *)identifier { diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index b3351fb2ff3..deaaae67114 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -7,9 +7,8 @@ #ifdef USE_TI_APPIOS #import "TiProxy.h" -#if IS_XCODE_8 + #import -#endif @interface TiAppiOSLocalNotificationProxy : TiProxy { @private diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index 3015c6dad14..d84d56e73e8 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -29,7 +29,6 @@ - (void)cancel:(id)unused DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"7.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 NSString *identifier = @"notification"; NSDictionary *userInfo = [(UNMutableNotificationContent *)self.notification userInfo]; @@ -39,7 +38,6 @@ - (void)cancel:(id)unused } } [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[ [TiUtils stringValue:identifier] ]]; -#endif } else { UILocalNotification *cancelledNotification = [self.notification retain]; TiThreadPerformOnMainThread(^{ diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 9135ada92ca..0b13e8a41fc 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -24,18 +24,13 @@ #import "TiAppiOSUserNotificationCenterProxy.h" #endif -#if IS_XCODE_8 -#import -#endif - -#if IS_XCODE_8 #ifdef USE_TI_APPIOSSEARCHQUERY #import "TiAppiOSSearchQueryProxy.h" #endif -#endif #import #import +#import @implementation TiAppiOSProxy @@ -298,7 +293,6 @@ - (id)createSearchableItemAttributeSet:(id)args } #endif -#if IS_XCODE_8 #ifdef USE_TI_APPIOSSEARCHQUERY - (id)createSearchQuery:(id)args { @@ -320,7 +314,6 @@ - (id)createSearchQuery:(id)args return [[[TiAppiOSSearchQueryProxy alloc] _initWithPageContext:[self pageContext] andArguments:args] autorelease]; } #endif -#endif #ifdef USE_TI_APPIOSUSERACTIVITY - (id)createUserActivity:(id)args @@ -403,16 +396,13 @@ - (void)registerUserNotificationSettings:(id)args NSUInteger types = UIUserNotificationTypeNone; -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { types = UNAuthorizationOptionNone; } -#endif if (typesRequested != nil) { for (id thisTypeRequested in typesRequested) { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 switch ([TiUtils intValue:thisTypeRequested]) { case UNAuthorizationOptionBadge: // USER_NOTIFICATION_TYPE_BADGE { @@ -435,7 +425,6 @@ - (void)registerUserNotificationSettings:(id)args break; } } -#endif } else { switch ([TiUtils intValue:thisTypeRequested]) { case UIUserNotificationTypeBadge: // USER_NOTIFICATION_TYPE_BADGE @@ -459,7 +448,6 @@ - (void)registerUserNotificationSettings:(id)args } if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types completionHandler:^(BOOL granted, NSError *error) { if (granted == YES) { @@ -477,7 +465,6 @@ - (void)registerUserNotificationSettings:(id)args [self fireEvent:@"usernotificationsettings" withObject:event]; } }]; -#endif } else { UIUserNotificationSettings *notif = [UIUserNotificationSettings settingsForTypes:types categories:[NSSet setWithArray:nativeCategories]]; @@ -511,10 +498,8 @@ - (NSDictionary *)currentUserNotificationSettings DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"7.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); return; -#endif } else { __block NSDictionary *returnVal = nil; TiThreadPerformOnMainThread(^{ @@ -583,7 +568,6 @@ - (id)scheduleLocalNotification:(id)args TiAppiOSLocalNotificationProxy *lp = [[[TiAppiOSLocalNotificationProxy alloc] _initWithPageContext:[self executionContext]] autorelease]; if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 id identifier = [args objectForKey:@"identifier"]; id alertSubtitle = [args objectForKey:@"alertSubtitle"]; id category = [args objectForKey:@"category"]; @@ -722,7 +706,6 @@ - (id)scheduleLocalNotification:(id)args [content release]; return lp; -#endif } else { UILocalNotification *content = [UILocalNotification new]; id alertAction = [args objectForKey:@"alertAction"]; @@ -990,9 +973,7 @@ - (NSNumber *)BACKGROUNDFETCHINTERVAL_NEVER - (NSNumber *)USER_NOTIFICATION_TYPE_NONE { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionNone); -#endif } return NUMINT(UIUserNotificationTypeNone); @@ -1001,9 +982,7 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_NONE - (NSNumber *)USER_NOTIFICATION_TYPE_BADGE { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionBadge); -#endif } return NUMINT(UIUserNotificationTypeBadge); @@ -1012,9 +991,7 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_BADGE - (NSNumber *)USER_NOTIFICATION_TYPE_SOUND { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionSound); -#endif } return NUMINT(UIUserNotificationTypeSound); @@ -1023,9 +1000,7 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_SOUND - (NSNumber *)USER_NOTIFICATION_TYPE_ALERT { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionAlert); -#endif } return NUMINT(UIUserNotificationTypeAlert); @@ -1034,9 +1009,7 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_ALERT - (NSNumber *)USER_NOTIFICATION_TYPE_CAR_PLAY { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNAuthorizationOptionCarPlay); -#endif } return NUMINT(0); } @@ -1044,9 +1017,7 @@ - (NSNumber *)USER_NOTIFICATION_TYPE_CAR_PLAY - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNNotificationActionOptionNone); -#endif } return NUMINT(UIUserNotificationActivationModeBackground); @@ -1055,9 +1026,7 @@ - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND - (NSNumber *)USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return NUMINT(UNNotificationActionOptionForeground); -#endif } return NUMINT(UIUserNotificationActivationModeForeground); @@ -1303,11 +1272,10 @@ - (NSString *)applicationOpenSettingsURL MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_LAYOUT_CHANGED, @"accessibilitylayoutchanged"); MAKE_SYSTEM_STR(EVENT_ACCESSIBILITY_SCREEN_CHANGED, @"accessibilityscreenchanged"); -MAKE_SYSTEM_PROP(FETCH_NEWDATA, 0); //UIBackgroundFetchResultNewData -MAKE_SYSTEM_PROP(FETCH_NODATA, 1); //UIBackgroundFetchResultNoData -MAKE_SYSTEM_PROP(FETCH_FAILED, 2); //UIBackgroundFetchResultFailed +MAKE_SYSTEM_PROP(FETCH_NEWDATA, 0); // UIBackgroundFetchResultNewData +MAKE_SYSTEM_PROP(FETCH_NODATA, 1); // UIBackgroundFetchResultNoData +MAKE_SYSTEM_PROP(FETCH_FAILED, 2); // UIBackgroundFetchResultFailed -#if IS_XCODE_8 MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED, UNAuthorizationStatusDenied); MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED, UNAuthorizationStatusAuthorized); MAKE_SYSTEM_PROP(USER_NOTIFICATION_AUTHORIZATION_STATUS_NOT_DETERMINED, UNAuthorizationStatusNotDetermined); @@ -1319,7 +1287,6 @@ - (NSString *)applicationOpenSettingsURL MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_NONE, UNAlertStyleNone); MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_ALERT, UNAlertStyleAlert); MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_BANNER, UNAlertStyleBanner); -#endif @end diff --git a/iphone/Classes/TiAppiOSSearchQueryProxy.h b/iphone/Classes/TiAppiOSSearchQueryProxy.h index 598f349f5c4..628c4edde8a 100644 --- a/iphone/Classes/TiAppiOSSearchQueryProxy.h +++ b/iphone/Classes/TiAppiOSSearchQueryProxy.h @@ -4,7 +4,7 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ -#if IS_XCODE_8 + #ifdef USE_TI_APPIOSSEARCHQUERY #import "TiProxy.h" #import @@ -27,4 +27,4 @@ @end #endif -#endif + diff --git a/iphone/Classes/TiAppiOSSearchQueryProxy.m b/iphone/Classes/TiAppiOSSearchQueryProxy.m index 9959c9abf9e..48a931304e8 100644 --- a/iphone/Classes/TiAppiOSSearchQueryProxy.m +++ b/iphone/Classes/TiAppiOSSearchQueryProxy.m @@ -4,7 +4,7 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ -#if IS_XCODE_8 + #ifdef USE_TI_APPIOSSEARCHQUERY #import "TiAppiOSSearchQueryProxy.h" #import "TiAppiOSSearchableItemProxy.h" @@ -101,5 +101,6 @@ - (NSNumber *)isCancelled:(id)unused } @end + #endif -#endif + diff --git a/iphone/Classes/TiAppiOSSearchableItemAttributeSetProxy.m b/iphone/Classes/TiAppiOSSearchableItemAttributeSetProxy.m index d22c31343b8..e7ec1b7086f 100644 --- a/iphone/Classes/TiAppiOSSearchableItemAttributeSetProxy.m +++ b/iphone/Classes/TiAppiOSSearchableItemAttributeSetProxy.m @@ -1322,8 +1322,6 @@ - (void)setUrl:(id)value ; } -#if IS_XCODE_8 - // The fully formatted address of the item (obtained from MapKit) - (NSString *)fullyFormattedAddress { @@ -1377,7 +1375,5 @@ - (void)setThoroughfare:(id)value [_attributes setThoroughfare:[TiUtils stringValue:value]]; } -#endif - @end #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h index f47ba7640fd..52383509901 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h @@ -8,9 +8,7 @@ #import "TiProxy.h" #ifdef USE_TI_APPIOS -#if IS_XCODE_8 #import -#endif @interface TiAppiOSUserNotificationActionProxy : TiProxy diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 326d71a5a36..3d0c80834f3 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -26,9 +26,7 @@ - (NSString *)apiName - (void)_initWithProperties:(NSDictionary *)properties { if (_notificationAction == nil) { - if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 id identifier = [properties valueForKey:@"identifier"]; id title = [properties valueForKey:@"title"]; id activationMode = [properties valueForKey:@"activationMode"]; @@ -62,7 +60,6 @@ - (void)_initWithProperties:(NSDictionary *)properties title:title options:[TiUtils intValue:activationMode]] retain]; } -#endif } else { _notificationAction = [[UIMutableUserNotificationAction new] retain]; } @@ -78,7 +75,6 @@ - (id)notificationAction #pragma mark Public API's -#if !defined(IS_XCODE_8) - (void)setIdentifier:(id)value { [[self notificationAction] setIdentifier:value]; @@ -91,24 +87,39 @@ - (void)setTitle:(id)value - (void)setActivationMode:(id)value { - [[self notificationAction] setActivationMode:[TiUtils intValue:value]]; + if (![TiUtils isIOS10OrGreater]) { + return; // Not available on iOS 10+ + } + + [(UIMutableUserNotificationAction *)[self notificationAction] setActivationMode:[TiUtils intValue:value]]; } - (void)setBehavior:(id)value { - [[self notificationAction] setBehavior:[TiUtils intValue:value]]; + if (![TiUtils isIOS10OrGreater]) { + return; // Not available on iOS 10+ + } + + [(UIMutableUserNotificationAction *)[self notificationAction] setBehavior:[TiUtils intValue:value]]; } - (void)setDestructive:(id)value { - [[self notificationAction] setDestructive:[TiUtils boolValue:value]]; + if (![TiUtils isIOS10OrGreater]) { + return; // Not available on iOS 10+ + } + + [(UIMutableUserNotificationAction *)[self notificationAction] setDestructive:[TiUtils boolValue:value]]; } - (void)setAuthenticationRequired:(id)value { - [[self notificationAction] setAuthenticationRequired:[TiUtils boolValue:value]]; + if (![TiUtils isIOS10OrGreater]) { + return; // Not available on iOS 10+ + } + + [(UIMutableUserNotificationAction *)[self notificationAction] setAuthenticationRequired:[TiUtils boolValue:value]]; } -#endif @end diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index b97c35a190a..16f9fa7e737 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -7,9 +7,7 @@ #import "TiProxy.h" #ifdef USE_TI_APPIOS -#if IS_XCODE_8 #import -#endif @interface TiAppiOSUserNotificationCategoryProxy : TiProxy diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 0f622ae2ad3..3b12710a1e2 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -53,12 +53,10 @@ - (void)_initWithProperties:(NSDictionary *)properties } if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier actions:defaultActions intentIdentifiers:intentIdentifiers ?: @[] options:UNNotificationCategoryOptionCustomDismissAction] retain]; -#endif } else { _notificationCategory = [UIMutableUserNotificationCategory new]; diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index 254648f47d0..31c4e76587d 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -8,9 +8,8 @@ #import "TiApp.h" #import "TiProxy.h" -#if IS_XCODE_8 + #import -#endif @interface TiAppiOSUserNotificationCenterProxy : TiProxy diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index f8917b38709..691fe46dab8 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -21,7 +21,6 @@ - (void)getPendingNotifications:(id)args ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 TiThreadPerformOnMainThread(^{ [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { NSMutableArray *result = [NSMutableArray arrayWithCapacity:[requests count]]; @@ -40,7 +39,6 @@ - (void)getPendingNotifications:(id)args }]; }, NO); -#endif } else { NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; NSMutableArray *result = [NSMutableArray arrayWithCapacity:[notifications count]]; @@ -62,7 +60,6 @@ - (void)getPendingNotifications:(id)args - (void)getDeliveredNotifications:(id)args { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 KrollCallback *callback = nil; ENSURE_ARG_AT_INDEX(callback, args, 0, KrollCallback); @@ -84,7 +81,6 @@ - (void)getDeliveredNotifications:(id)args }]; }, NO); -#endif } else { DebugLog(@"[WARN] Ti.App.iOS.NotificationCenter.getDeliveredNotifications is not available in iOS < 10."); } @@ -95,7 +91,6 @@ - (void)removePendingNotifications:(id)args ENSURE_TYPE(args, NSArray); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; TiThreadPerformOnMainThread(^{ if ([args count] == 0) { @@ -120,7 +115,6 @@ - (void)removePendingNotifications:(id)args }]; }, NO); -#endif } else { TiThreadPerformOnMainThread(^{ if ([args count] == 0) { @@ -142,7 +136,6 @@ - (void)removeDeliveredNotifications:(id)args ENSURE_TYPE(args, NSArray); if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 TiThreadPerformOnMainThread(^{ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; @@ -168,7 +161,6 @@ - (void)removeDeliveredNotifications:(id)args }]; }, NO); -#endif } else { DebugLog(@"[WARN] Ti.App.iOS.NotificationCenter.removeDeliveredNotifications is only available in iOS 10 and later."); } @@ -182,7 +174,6 @@ - (void)requestUserNotificationSettings:(id)args KrollCallback *callback = [args objectAtIndex:0]; if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 TiThreadPerformOnMainThread(^{ [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { NSDictionary *propertiesDict = @{ @@ -202,7 +193,6 @@ - (void)requestUserNotificationSettings:(id)args }]; }, NO); -#endif } else { TiThreadPerformOnMainThread(^{ UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; @@ -219,7 +209,6 @@ - (void)requestUserNotificationSettings:(id)args #pragma mark Utilities -#if IS_XCODE_8 - (NSDictionary *)dictionaryWithUserNotificationRequest:(UNNotificationRequest *)request { NSMutableDictionary *event = [NSMutableDictionary dictionary]; @@ -251,7 +240,6 @@ - (NSDictionary *)dictionaryWithUserNotificationRequest:(UNNotificationRequest * return event; } -#endif - (NSDictionary *)formatUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { diff --git a/iphone/Classes/TiMediaAudioSession.m b/iphone/Classes/TiMediaAudioSession.m index 887406120ae..1d020446ea0 100644 --- a/iphone/Classes/TiMediaAudioSession.m +++ b/iphone/Classes/TiMediaAudioSession.m @@ -9,11 +9,7 @@ #import "TiMediaAudioSession.h" #import "TiUtils.h" -#if IS_XCODE_8 #import -#else -#import -#endif NSString *const kTiMediaAudioSessionInterruptionBegin = @"TiMediaAudioSessionInterruptionBegin"; NSString *const kTiMediaAudioSessionInterruptionEnd = @"TiMediaAudioSessionInterruptionEnd"; diff --git a/iphone/Classes/TiMediaSoundProxy.h b/iphone/Classes/TiMediaSoundProxy.h index 2a1abb5689d..cbf071f3fcd 100644 --- a/iphone/Classes/TiMediaSoundProxy.h +++ b/iphone/Classes/TiMediaSoundProxy.h @@ -8,11 +8,7 @@ #import "TiFile.h" #import "TiProxy.h" -#if IS_XCODE_8 #import -#else -#import -#endif @interface TiMediaSoundProxy : TiProxy { @private diff --git a/iphone/Classes/TiMediaSoundProxy.m b/iphone/Classes/TiMediaSoundProxy.m index 2e5f365b8f2..bb782efe6a9 100644 --- a/iphone/Classes/TiMediaSoundProxy.m +++ b/iphone/Classes/TiMediaSoundProxy.m @@ -7,12 +7,7 @@ #ifdef USE_TI_MEDIASOUND #import -#if IS_XCODE_8 #import -#else -#import -#import -#endif #import "TiBlob.h" #import "TiFile.h" diff --git a/iphone/Classes/TiUIClipboardProxy.m b/iphone/Classes/TiUIClipboardProxy.m index 6d9680619c1..2711e8c70a7 100644 --- a/iphone/Classes/TiUIClipboardProxy.m +++ b/iphone/Classes/TiUIClipboardProxy.m @@ -269,22 +269,18 @@ - (id)hasData:(id)args - (id)hasText:(id)unused { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMBOOL([[self pasteboard] hasStrings]); } -#endif return [self hasData:@"text/plain"]; } - (id)hasColors:(id)unused { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMBOOL([[self pasteboard] hasColors]); } -#endif NSLog(@"[WARN] Ti.UI.Clipboard.hasColors() is only available on iOS 10 and later."); return NUMBOOL(NO); @@ -292,11 +288,9 @@ - (id)hasColors:(id)unused - (id)hasImages:(id)unused { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMBOOL([[self pasteboard] hasImages]); } -#endif NSLog(@"[WARN] Ti.UI.Clipboard.hasImages() is only available on iOS 10 and later."); return NUMBOOL(NO); @@ -304,11 +298,9 @@ - (id)hasImages:(id)unused - (id)hasURLs:(id)unused { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMBOOL([[self pasteboard] hasURLs]); } -#endif NSLog(@"[WARN] Ti.UI.Clipboard.hasURLs() is only available on iOS 10 and later."); return NUMBOOL(NO); @@ -316,7 +308,6 @@ - (id)hasURLs:(id)unused - (void)setItems:(id)args { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { NSArray *items = [args objectForKey:@"items"]; NSDictionary *options = [args objectForKey:@"options"]; @@ -346,12 +337,10 @@ - (void)setItems:(id)args }, YES); } -#endif } - (id)getItems:(id)unused { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { __block id items; @@ -378,7 +367,6 @@ - (id)getItems:(id)unused return [items autorelease]; } -#endif return @[]; } diff --git a/iphone/Classes/TiUIListView.h b/iphone/Classes/TiUIListView.h index 034967e3b97..4d1c8ee5640 100644 --- a/iphone/Classes/TiUIListView.h +++ b/iphone/Classes/TiUIListView.h @@ -9,12 +9,7 @@ #import "TiUIListViewProxy.h" #import "TiUIView.h" -#if IS_XCODE_8 -// Add support for iOS 10 table-view prefetching @interface TiUIListView : TiUIView -#else -@interface TiUIListView : TiUIView -#endif #pragma mark - Private APIs diff --git a/iphone/Classes/TiUIListView.m b/iphone/Classes/TiUIListView.m index 64ead973f16..cfc289d4693 100644 --- a/iphone/Classes/TiUIListView.m +++ b/iphone/Classes/TiUIListView.m @@ -115,11 +115,9 @@ - (void)dealloc _searchTableView.dataSource = nil; RELEASE_TO_NIL(_searchTableView) -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { _tableView.prefetchDataSource = nil; } -#endif [_tableView release]; [_templates release]; @@ -216,11 +214,9 @@ - (UITableView *)searchTableView } #endif -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { _searchTableView.prefetchDataSource = self; } -#endif if (TiDimensionIsDip(_rowHeight)) { [_searchTableView setRowHeight:_rowHeight.value]; @@ -269,11 +265,9 @@ - (UITableView *)tableView } #endif -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { _tableView.prefetchDataSource = self; } -#endif if (TiDimensionIsDip(_rowHeight)) { [_tableView setRowHeight:_rowHeight.value]; @@ -1634,7 +1628,6 @@ - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInte #pragma mark - UITableViewDataSourcePrefetching -#if IS_XCODE_8 - (void)tableView:(UITableView *)tableView prefetchRowsAtIndexPaths:(NSArray *)indexPaths { NSString *eventName = @"prefetch"; @@ -1668,7 +1661,6 @@ - (void)tableView:(UITableView *)tableView cancelPrefetchingForRowsAtIndexPaths: [self.proxy fireEvent:eventName withObject:@{ @"prefetchedItems" : cells }]; RELEASE_TO_NIL(cells); } -#endif - (NSDictionary *)listItemFromIndexPath:(NSIndexPath *)indexPath { diff --git a/iphone/Classes/TiUIScrollView.h b/iphone/Classes/TiUIScrollView.h index f56f14c6f0c..1303a9e6185 100644 --- a/iphone/Classes/TiUIScrollView.h +++ b/iphone/Classes/TiUIScrollView.h @@ -6,11 +6,9 @@ */ #ifdef USE_TI_UISCROLLVIEW -#if IS_XCODE_8 #ifdef USE_TI_UIREFRESHCONTROL #import "TiUIRefreshControlProxy.h" #endif -#endif #import "TiUIView.h" @@ -35,10 +33,8 @@ #endif CGFloat minimumContentHeight; -#if IS_XCODE_8 #ifdef USE_TI_UIREFRESHCONTROL TiUIRefreshControlProxy *refreshControl; -#endif #endif BOOL needsHandleContentSize; diff --git a/iphone/Classes/TiUIScrollView.m b/iphone/Classes/TiUIScrollView.m index b3c03045610..9d3a08857d8 100644 --- a/iphone/Classes/TiUIScrollView.m +++ b/iphone/Classes/TiUIScrollView.m @@ -85,10 +85,8 @@ - (void)dealloc #ifndef TI_USE_AUTOLAYOUT RELEASE_TO_NIL(wrapperView); #endif -#if IS_XCODE_8 #ifdef USE_TI_UIREFRESHCONTROL RELEASE_TO_NIL(refreshControl); -#endif #endif RELEASE_TO_NIL(scrollView); [super dealloc]; @@ -342,7 +340,6 @@ - (void)setContentHeight_:(id)value - (void)setRefreshControl_:(id)args { -#if IS_XCODE_8 #ifdef USE_TI_UIREFRESHCONTROL if (![TiUtils isIOS10OrGreater]) { NSLog(@"[WARN] Ti.UI.RefreshControl inside Ti.UI.ScrollView is only available in iOS 10 and later."); @@ -357,9 +354,6 @@ - (void)setRefreshControl_:(id)args [[self scrollView] setRefreshControl:[refreshControl control]]; } #endif -#else - NSLog(@"[WARN] Ti.UI.RefreshControl inside Ti.UI.ScrollView is only available in iOS 10 and later."); -#endif } - (void)setShowHorizontalScrollIndicator_:(id)value diff --git a/iphone/Classes/TiUITabGroup.m b/iphone/Classes/TiUITabGroup.m index ec1798ee18f..b6707ea5261 100644 --- a/iphone/Classes/TiUITabGroup.m +++ b/iphone/Classes/TiUITabGroup.m @@ -383,13 +383,11 @@ - (void)setTabsTintColor_:(id)value [[controller tabBar] setTintColor:[[TiUtils colorValue:value] color]]; } -#if IS_XCODE_8 - (void)setUnselectedItemTintColor_:(id)value { ENSURE_TYPE_OR_NIL(value, NSString); [[controller tabBar] setUnselectedItemTintColor:[[TiUtils colorValue:value] color]]; } -#endif - (void)setTabsTranslucent_:(id)value { diff --git a/iphone/Classes/TiUITabProxy.m b/iphone/Classes/TiUITabProxy.m index 9539814890f..194ed5f6c65 100644 --- a/iphone/Classes/TiUITabProxy.m +++ b/iphone/Classes/TiUITabProxy.m @@ -499,9 +499,7 @@ - (void)updateTabBarItem UIViewController *rootController = [rootWindow hostingController]; id badgeValue = [TiUtils stringValue:[self valueForKey:@"badge"]]; -#if IS_XCODE_8 id badgeColor = [self valueForKey:@"badgeColor"]; -#endif id iconInsets = [self valueForKey:@"iconInsets"]; id icon = [self valueForKey:@"icon"]; @@ -511,11 +509,9 @@ - (void)updateTabBarItem UITabBarItem *newItem = [[UITabBarItem alloc] initWithTabBarSystemItem:value tag:value]; [newItem setBadgeValue:badgeValue]; -#if IS_XCODE_8 if (badgeColor != nil && [TiUtils isIOS10OrGreater]) { [newItem setBadgeColor:[[TiUtils colorValue:badgeColor] color]]; } -#endif [rootController setTabBarItem:newItem]; [newItem release]; @@ -581,11 +577,9 @@ - (void)updateTabBarItem } } -#if IS_XCODE_8 if (badgeColor != nil && [TiUtils isIOS10OrGreater]) { [ourItem setBadgeColor:[[TiUtils colorValue:badgeColor] color]]; } -#endif [ourItem setBadgeValue:badgeValue]; [rootController setTabBarItem:ourItem]; diff --git a/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.h b/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.h index b03faae123a..462697e256b 100644 --- a/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.h +++ b/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.h @@ -4,7 +4,7 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ -#if IS_XCODE_8 + #ifdef USE_TI_UIIOSFEEDBACKGENERATOR #import "TiProxy.h" @@ -56,4 +56,3 @@ typedef NS_ENUM(NSInteger, TiUIiOSFeedbackGeneratorType) { @end #endif -#endif diff --git a/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.m b/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.m index 3c8ded017cf..4d764932c5a 100644 --- a/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.m +++ b/iphone/Classes/TiUIiOSFeedbackGeneratorProxy.m @@ -4,7 +4,7 @@ * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ -#if IS_XCODE_8 + #ifdef USE_TI_UIIOSFEEDBACKGENERATOR #import "TiUIiOSFeedbackGeneratorProxy.h" @@ -109,4 +109,3 @@ - (void)notificationOccurred:(id)value @end #endif -#endif diff --git a/iphone/Classes/TiUIiOSProxy.h b/iphone/Classes/TiUIiOSProxy.h index 6e6b2056211..d76b7f759e4 100644 --- a/iphone/Classes/TiUIiOSProxy.h +++ b/iphone/Classes/TiUIiOSProxy.h @@ -230,10 +230,8 @@ #ifdef USE_TI_UIIOSAPPLICATIONSHORTCUTS - (id)createApplicationShortcuts:(id)args; #endif -#if IS_XCODE_8 #ifdef USE_TI_UIIOSFEEDBACKGENERATOR - (id)createFeedbackGenerator:(id)args; #endif -#endif @end diff --git a/iphone/Classes/TiUIiOSProxy.m b/iphone/Classes/TiUIiOSProxy.m index 4572d32084e..aa28f2e19cc 100644 --- a/iphone/Classes/TiUIiOSProxy.m +++ b/iphone/Classes/TiUIiOSProxy.m @@ -93,11 +93,9 @@ #import "TiUIiOSStepperProxy.h" #endif -#if IS_XCODE_8 #ifdef USE_TI_UIIOSFEEDBACKGENERATOR #import "TiUIiOSFeedbackGeneratorProxy.h" #endif -#endif @implementation TiUIiOSProxy @@ -430,21 +428,17 @@ - (id)BLUR_EFFECT_STYLE_DARK - (id)BLUR_EFFECT_STYLE_REGULAR { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMINTEGER(UIBlurEffectStyleRegular); } -#endif return [NSNull null]; } - (id)BLUR_EFFECT_STYLE_PROMINENT { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { return NUMINTEGER(UIBlurEffectStyleProminent); } -#endif return [NSNull null]; } #endif @@ -779,7 +773,6 @@ - (id)createApplicationShortcuts:(id)args MAKE_SYSTEM_PROP(MODAL_PRESENTATION_FORMSHEET, UIModalPresentationFormSheet); MAKE_SYSTEM_PROP(MODAL_PRESENTATION_CURRENT_CONTEXT, UIModalPresentationCurrentContext); -#if IS_XCODE_8 #ifdef USE_TI_UIIOSFEEDBACKGENERATOR - (id)createFeedbackGenerator:(id)args @@ -799,7 +792,6 @@ - (id)createFeedbackGenerator:(id)args MAKE_SYSTEM_PROP(FEEDBACK_GENERATOR_IMPACT_STYLE_MEDIUM, UIImpactFeedbackStyleMedium); MAKE_SYSTEM_PROP(FEEDBACK_GENERATOR_IMPACT_STYLE_HEAVY, UIImpactFeedbackStyleHeavy); #endif -#endif #if IS_XCODE_9 MAKE_SYSTEM_PROP(LARGE_TITLE_DISPLAY_MODE_AUTOMATIC, UINavigationItemLargeTitleDisplayModeAutomatic); diff --git a/iphone/Classes/TiUtils.m b/iphone/Classes/TiUtils.m index 2f101215727..e806c96aaa8 100644 --- a/iphone/Classes/TiUtils.m +++ b/iphone/Classes/TiUtils.m @@ -185,20 +185,12 @@ + (BOOL)isIOS9_3OrGreater + (BOOL)isIOS10OrGreater { -#if IS_XCODE_8 return [TiUtils isIOSVersionOrGreater:@"10.0"]; -#else - return NO; -#endif } + (BOOL)isIOS11OrGreater { -#if IS_XCODE_9 return [TiUtils isIOSVersionOrGreater:@"11.0"]; -#else - return NO; -#endif } + (BOOL)isIOSVersionOrGreater:(NSString *)version diff --git a/iphone/Classes/UIModule.m b/iphone/Classes/UIModule.m index f8a99ac24ae..dd488b95026 100644 --- a/iphone/Classes/UIModule.m +++ b/iphone/Classes/UIModule.m @@ -631,9 +631,7 @@ - (NSNumber *)ATTRIBUTE_LINE_BREAK_BY_TRUNCATING_MIDDLE - (NSString *)CLIPBOARD_OPTION_LOCAL_ONLY { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return UIPasteboardOptionLocalOnly; -#endif } else { return @""; } @@ -641,9 +639,7 @@ - (NSString *)CLIPBOARD_OPTION_LOCAL_ONLY - (NSString *)CLIPBOARD_OPTION_EXPIRATION_DATE { if ([TiUtils isIOS10OrGreater]) { -#if IS_XCODE_8 return UIPasteboardOptionExpirationDate; -#endif } else { return @""; } diff --git a/iphone/Classes/WatchSessionModule.m b/iphone/Classes/WatchSessionModule.m index 6474dd382a1..af004787427 100644 --- a/iphone/Classes/WatchSessionModule.m +++ b/iphone/Classes/WatchSessionModule.m @@ -137,22 +137,18 @@ - (NSNumber *)isActivated - (NSNumber *)hasContentPending { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater] && [WCSession isSupported]) { return NUMBOOL([[self watchSession] hasContentPending]); } -#endif return NUMBOOL(NO); } - (NSNumber *)remainingComplicationUserInfoTransfers { -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater] && [WCSession isSupported]) { return NUMUINTEGER([[self watchSession] remainingComplicationUserInfoTransfers]); } -#endif return NUMBOOL(0); } @@ -489,12 +485,10 @@ - (NSDictionary *)dictionaryFromWatchSession:(WCSession *)session [dict setObject:[self activationState] forKey:@"activationState"]; } -#if IS_XCODE_8 if ([TiUtils isIOS10OrGreater]) { [dict setObject:[self hasContentPending] forKey:@"hasContentPending"]; [dict setObject:[self remainingComplicationUserInfoTransfers] forKey:@"remainingComplicationUserInfoTransfers"]; } -#endif return dict; } diff --git a/iphone/iphone/Titanium_Prefix.pch b/iphone/iphone/Titanium_Prefix.pch index ab06c2ac358..6412f63ab97 100644 --- a/iphone/iphone/Titanium_Prefix.pch +++ b/iphone/iphone/Titanium_Prefix.pch @@ -11,12 +11,6 @@ #include "ThirdpartyNS.h" #import -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 -#define IS_XCODE_8 true -#else -#define IS_XCODE_8 false -#endif - #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 #define IS_XCODE_9 true #else From 1895b9b2f8108f75f0c49e3e1ca1c642f64b4011 Mon Sep 17 00:00:00 2001 From: hansemannn Date: Sun, 21 Jan 2018 20:41:59 +0100 Subject: [PATCH 36/44] Fix some TODOs --- iphone/Classes/TiApp.m | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index b7a22e33324..c1870141163 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -476,7 +476,7 @@ - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceAppl } #pragma mark -#pragma mark Background Fetch iOS 7 +#pragma mark Background Fetch #ifdef USE_TI_FETCH @@ -507,7 +507,7 @@ - (void)application:(UIApplication *)application performFetchWithCompletionHandl #endif -#pragma mark Remote and Local Notifications iOS 8 +#pragma mark Remote and Local Notifications - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { @@ -518,46 +518,26 @@ - (void)application:(UIApplication *)application didRegisterUserNotificationSett - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { - // TODO: Get desired options from notification - // For example, pass none for silent pushes + // TODO: Get desired options from notification? completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { - /*RELEASE_TO_NIL(remoteNotification); - [self generateNotification:userInfo]; - NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; - event[@"data"] = remoteNotification; - if (identifier != nil) { - event[@"identifier"] = identifier; - } - NSString *category = remoteNotification[@"category"]; - if (category != nil) { - event[@"category"] = category; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:event userInfo:nil]; - [event autorelease]; - completionHandler();*/ - - // TODO: Find out where the payload is stored to handle the above - if ([[[[[response notification] request] content] userInfo] valueForKey:@"isRemoteNotification"] != nil) { RELEASE_TO_NIL(remoteNotification); remoteNotification = [[[self class] dictionaryWithUserNotification:response.notification withIdentifier:response.actionIdentifier] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteNotificationAction object:remoteNotification userInfo:nil]; + [self tryToPostNotification:remoteNotification withNotificationName:kTiRemoteNotificationAction completionHandler:completionHandler]; } else { RELEASE_TO_NIL(localNotification); localNotification = [[[self class] dictionaryWithUserNotification:response.notification withIdentifier:response.actionIdentifier] retain]; - [[NSNotificationCenter defaultCenter] postNotificationName:kTiLocalNotificationAction object:localNotification userInfo:nil]; + [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotificationAction completionHandler:completionHandler]; } - - completionHandler(); } - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler @@ -724,7 +704,7 @@ - (void)completionHandlerForBackgroundTransfer:(id)key } #pragma mark -#pragma mark Remote Notifications iOS 7 +#pragma mark Remote Notifications #ifdef USE_TI_SILENTPUSH // Delegate callback for Silent Remote Notification. @@ -761,11 +741,10 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N [[NSRunLoop mainRunLoop] addTimer:flushTimer forMode:NSDefaultRunLoopMode]; } } - #endif #pragma mark -#pragma mark Background Transfer Service iOS 7 +#pragma mark Background Transfer Service //Delegate callback for Background Transfer completes. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler @@ -1253,7 +1232,7 @@ - (KrollBridge *)krollBridge return kjsBridge; } -#pragma mark Backgrounding +#pragma mark Background Tasks - (void)beginBackgrounding { From 0214eb9920dc24ea7fbd936d5830975fab42a448 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Thu, 22 Mar 2018 18:26:23 +0100 Subject: [PATCH 37/44] Use NSOrderedSet and NSInvocation for proper invocations --- iphone/Classes/TiApp.h | 2 +- iphone/Classes/TiApp.m | 65 ++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/iphone/Classes/TiApp.h b/iphone/Classes/TiApp.h index d91ed3019f7..7d4a731105a 100644 --- a/iphone/Classes/TiApp.h +++ b/iphone/Classes/TiApp.h @@ -56,7 +56,7 @@ TI_INLINE void waitForMemoryPanicCleared() //WARNING: This must never be run on NSMutableDictionary *pendingReplyHandlers; NSMutableDictionary *backgroundTransferCompletionHandlers; NSMutableDictionary *queuedBootEvents; - NSMutableDictionary *> *_queuedApplicationSelectors; + NSMutableDictionary *> *_queuedApplicationSelectors; NSMutableSet *_applicationDelegates; BOOL appBooted; diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 1ffa1e43f6c..8094f22912f 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -137,7 +137,7 @@ - (NSMutableDictionary *)queuedBootEvents return queuedBootEvents; } -- (NSMutableDictionary *> *)queuedApplicationSelectors +- (NSMutableDictionary *> *)queuedApplicationSelectors { if (_queuedApplicationSelectors == nil) { _queuedApplicationSelectors = [[[NSMutableDictionary alloc] init] retain]; @@ -428,7 +428,7 @@ - (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdenti BOOL allowsCustomKeyboard = [TiUtils boolValue:[[TiApp tiAppProperties] objectForKey:@"allow-custom-keyboards"] def:YES]; [self tryToInvokeSelector:@selector(application:shouldAllowExtensionPointIdentifier:) - withArguments:[NSSet setWithObjects:application, extensionPointIdentifier, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, extensionPointIdentifier, nil]]; if ([extensionPointIdentifier isEqualToString:UIApplicationKeyboardExtensionPointIdentifier] && !allowsCustomKeyboard) { return NO; @@ -490,7 +490,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( } [self tryToInvokeSelector:@selector(application:didFinishLaunchingWithOptions:) - withArguments:[NSSet setWithObjects:application, launchOptions_, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, launchOptions_, nil]]; [self launchToUrl]; [self boot]; @@ -502,7 +502,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { [self tryToInvokeSelector:@selector(application:openURL:options:) - withArguments:[NSSet setWithObjects:app, url, options, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:app, url, options, nil]]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; [launchOptions setObject:[url absoluteString] forKey:@"url"]; @@ -519,7 +519,7 @@ - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDiction - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { [self tryToInvokeSelector:@selector(application:sourceApplication:annotation:) - withArguments:[NSSet setWithObjects:application, sourceApplication, annotation, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, sourceApplication, annotation, nil]]; [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; [launchOptions setObject:[url absoluteString] forKey:@"url"]; @@ -539,7 +539,7 @@ - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceAppl - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [self tryToInvokeSelector:@selector(application:performFetchWithCompletionHandler:) - withArguments:[NSSet setWithObjects:application, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, completionHandler, nil]]; //Only for simulator builds NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; @@ -571,7 +571,7 @@ - (void)application:(UIApplication *)application performFetchWithCompletionHandl - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { [self tryToInvokeSelector:@selector(application:didRegisterUserNotificationSettings:) - withArguments:[NSSet setWithObjects:application, notificationSettings, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, notificationSettings, nil]]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiUserNotificationSettingsNotification object:self @@ -612,7 +612,7 @@ - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSS } [self tryToInvokeSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:) - withArguments:[NSSet setWithObjects:application, identifier, notification, responseInfo, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, identifier, notification, responseInfo, completionHandler, nil]]; [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotificationAction completionHandler:completionHandler]; } @@ -621,7 +621,7 @@ - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSS - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler { [self tryToInvokeSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:) - withArguments:[NSSet setWithObjects:application, identifier, userInfo, responseInfo, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, identifier, userInfo, responseInfo, completionHandler, nil]]; [self handleRemoteNotificationWithIdentifier:identifier andUserInfo:userInfo @@ -633,7 +633,7 @@ - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSS - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { [self tryToInvokeSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:completionHandler:) - withArguments:[NSSet setWithObjects:application, identifier, userInfo, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, identifier, userInfo, completionHandler, nil]]; [self handleRemoteNotificationWithIdentifier:identifier andUserInfo:userInfo @@ -664,7 +664,7 @@ - (void)application:(UIApplication *)application } [self tryToInvokeSelector:@selector(application:handleWatchKitExtensionRequest:reply:) - withArguments:[NSSet setWithObjects:application, userInfo, reply, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, userInfo, reply, nil]]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiWatchKitExtensionRequest object:self userInfo:dic]; } @@ -690,21 +690,24 @@ - (void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary *)use #pragma mark Helper Methods -- (void)invokeSelector:(SEL)selector withArguments:(NSSet *)arguments onDelegate:(id)delegate +- (void)invokeSelector:(SEL)selector withArguments:(NSOrderedSet *)arguments onDelegate:(id)delegate { NSArray *keys = [NSStringFromSelector(selector) componentsSeparatedByString:@":"]; NSMutableDictionary *output = [NSMutableDictionary dictionaryWithCapacity:[arguments count]]; - NSInteger i = 0; + NSInteger index = 2; // Index 0 and 1 are reserved for the invocation internals ("self" and "_cmd") + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:selector]]; + [inv setSelector:selector]; + [inv setTarget:delegate]; + for (id obj in arguments) { - [output setObject:obj forKey:[keys objectAtIndex:i]]; - i++; + [inv setArgument:&(obj)atIndex:index++]; } - [delegate performSelector:selector withObject:output]; + [inv invoke]; } -- (void)tryToInvokeSelector:(SEL)selector withArguments:(NSSet *)arguments +- (void)tryToInvokeSelector:(SEL)selector withArguments:(NSOrderedSet *)arguments { NSString *selectorString = NSStringFromSelector(selector); @@ -820,7 +823,7 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N } [self tryToInvokeSelector:@selector(application:didReceiveRemoteNotification:) - withArguments:[NSSet setWithObjects:application, userInfo, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, userInfo, completionHandler, nil]]; //This only here for Simulator builds. @@ -866,7 +869,7 @@ - (void)application:(UIApplication *)application handleEventsForBackgroundURLSes [backgroundTransferCompletionHandlers setObject:[[completionHandler copy] autorelease] forKey:key]; [self tryToInvokeSelector:@selector(application:handleEventsForBackgroundURLSession:completionHandler:) - withArguments:[NSSet setWithObjects:application, identifier, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, identifier, completionHandler, nil]]; NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:identifier, @"sessionId", key, @"handlerId", nil]; @@ -1007,7 +1010,7 @@ - (void)waitForKrollProcessing - (void)applicationWillTerminate:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationWillTerminate:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; NSNotificationCenter *theNotificationCenter = [NSNotificationCenter defaultCenter]; _willTerminate = YES; @@ -1057,7 +1060,7 @@ - (void)applicationWillTerminate:(UIApplication *)application - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationDidReceiveMemoryWarning:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; applicationInMemoryPanic = YES; [Webcolor flushCache]; @@ -1073,7 +1076,7 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application - (void)applicationWillResignActive:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationWillResignActive:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; if ([self forceSplashAsSnapshot]) { #ifdef LAUNCHSCREEN_STORYBOARD @@ -1101,7 +1104,7 @@ - (void)applicationWillResignActive:(UIApplication *)application - (void)applicationDidBecomeActive:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationDidBecomeActive:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; // We should think about placing this inside "applicationWillBecomeActive" instead to make // the UI re-useable again more quickly @@ -1128,7 +1131,7 @@ - (void)applicationDidBecomeActive:(UIApplication *)application - (void)applicationDidEnterBackground:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationDidEnterBackground:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; @@ -1162,7 +1165,7 @@ - (void)applicationDidEnterBackground:(UIApplication *)application - (void)applicationWillEnterForeground:(UIApplication *)application { [self tryToInvokeSelector:@selector(applicationWillEnterForeground:) - withArguments:[NSSet setWithObject:application]]; + withArguments:[NSOrderedSet orderedSetWithObject:application]]; [self flushCompletionHandlerQueue]; [sessionId release]; @@ -1214,7 +1217,7 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct [launchOptions setObject:userActivityDict forKey:UIApplicationLaunchOptionsUserActivityDictionaryKey]; [self tryToInvokeSelector:@selector(application:continueUserActivity:restorationHandler:) - withArguments:[NSSet setWithObjects:application, userActivity, restorationHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, userActivity, restorationHandler, nil]]; if (appBooted) { [[NSNotificationCenter defaultCenter] postNotificationName:kTiContinueActivity object:self userInfo:dict]; @@ -1239,7 +1242,7 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N [self generateNotification:userInfo]; [self tryToInvokeSelector:@selector(application:didReceiveRemoteNotification:) - withArguments:[NSSet setWithObjects:application, userInfo, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, userInfo, nil]]; } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken @@ -1264,13 +1267,13 @@ - (void)application:(UIApplication *)application didRegisterForRemoteNotificatio } [self tryToInvokeSelector:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:) - withArguments:[NSSet setWithObjects:application, deviceToken, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, deviceToken, nil]]; } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { [self tryToInvokeSelector:@selector(application:didFailToRegisterForRemoteNotificationsWithError:) - withArguments:[NSSet setWithObjects:application, error, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, error, nil]]; } #endif @@ -1395,7 +1398,7 @@ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UI localNotification = [[[self class] dictionaryWithLocalNotification:notification] retain]; [self tryToInvokeSelector:@selector(application:didReceiveLocalNotification:) - withArguments:[NSSet setWithObjects:application, notification, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, notification, nil]]; [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotification completionHandler:nil]; } @@ -1468,7 +1471,7 @@ - (void)application:(UIApplication *)application completionHandler:(void (^)(BOOL succeeded))completionHandler { [self tryToInvokeSelector:@selector(application:performActionForShortcutItem:completionHandler:) - withArguments:[NSSet setWithObjects:application, shortcutItem, completionHandler, nil]]; + withArguments:[NSOrderedSet orderedSetWithObjects:application, shortcutItem, completionHandler, nil]]; BOOL handledShortCutItem = [self handleShortcutItem:shortcutItem queueToBootIfNotLaunched:NO]; completionHandler(handledShortCutItem); From 7518f8a0fd47f1b61e315bb4046c1e5324b37a72 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Thu, 22 Mar 2018 18:26:42 +0100 Subject: [PATCH 38/44] Remove references to old methods --- .../TiAppiOSUserNotificationActionProxy.m | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 3d0c80834f3..079ae34204b 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -46,7 +46,9 @@ - (void)_initWithProperties:(NSDictionary *)properties options |= UNNotificationActionOptionAuthenticationRequired; } - if (behavior && [TiUtils intValue:behavior def:0] == UIUserNotificationActionBehaviorTextInput) { + // Important: The UNNoticationAction class is creation-only, so the manual setters are only + // for the iOS < 10 UIUserNotificationAction + if (behavior && [TiUtils intValue:behavior def:UIUserNotificationActionBehaviorDefault] == UIUserNotificationActionBehaviorTextInput) { _notificationAction = [[UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:options @@ -75,19 +77,9 @@ - (id)notificationAction #pragma mark Public API's -- (void)setIdentifier:(id)value -{ - [[self notificationAction] setIdentifier:value]; -} - -- (void)setTitle:(id)value -{ - [[self notificationAction] setTitle:value]; -} - - (void)setActivationMode:(id)value { - if (![TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { return; // Not available on iOS 10+ } @@ -96,7 +88,7 @@ - (void)setActivationMode:(id)value - (void)setBehavior:(id)value { - if (![TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { return; // Not available on iOS 10+ } @@ -105,7 +97,7 @@ - (void)setBehavior:(id)value - (void)setDestructive:(id)value { - if (![TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { return; // Not available on iOS 10+ } @@ -114,7 +106,7 @@ - (void)setDestructive:(id)value - (void)setAuthenticationRequired:(id)value { - if (![TiUtils isIOS10OrGreater]) { + if ([TiUtils isIOS10OrGreater]) { return; // Not available on iOS 10+ } From 5119683cd1e63db264bc1b6b86d40f369c9832ec Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Thu, 22 Mar 2018 18:49:39 +0100 Subject: [PATCH 39/44] =?UTF-8?q?Change=20=E2=80=9Esince=E2=80=9C=20versio?= =?UTF-8?q?ns=20to=207.2.0,=20fix=20a=20minor=20doc=20issue=20and=20lint?= =?UTF-8?q?=20sources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Titanium/App/iOS/NotificationCenter.yml | 46 +++++----- apidoc/Titanium/App/iOS/iOS.yml | 88 +++++++++---------- .../Classes/TiAppiOSLocalNotificationProxy.m | 2 +- iphone/Classes/TiAppiOSProxy.m | 6 +- .../TiAppiOSUserNotificationActionProxy.m | 2 +- .../TiAppiOSUserNotificationCenterProxy.m | 2 - 6 files changed, 72 insertions(+), 74 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index 2c448f0c9aa..22bed31be55 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -7,42 +7,42 @@ summary: | extends: Titanium.Module platforms: [iphone, ipad] osver: {ios: {min: "8.0"}} -since: "7.1.0" +since: "7.2.0" methods: - name: getPendingNotifications summary: Fetches the pending notifications asynchronously. parameters: - name: callback - summary: | - The function that is being called after the notifications + summary: | + The function that is being called after the notifications have been fetched. type: Callback - since: "7.1.0" + since: "7.2.0" - name: getDeliveredNotifications summary: Fetches the delivered notifications asynchronously. parameters: - name: callback - summary: | - The function that is being called after the notifications + summary: | + The function that is being called after the notifications have been fetched. type: Callback osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: removePendingNotifications - summary: | + summary: | Removes the specified pending notifications to prevent them from being triggered. If no notifications are specified, all pending notifications will be removed. - since: "7.1.0" + since: "7.2.0" - name: removeDeliveredNotifications - summary: | + summary: | Removes the specified delivered notifications from the notification-center. If no notifications are specified, all delivered notifications will be removed. osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: requestUserNotificationSettings summary: | @@ -51,8 +51,8 @@ methods: parameters: - name: callback summary: The callback invoked when requesting user notification settings. - type: Callback - since: "7.1.0" + type: Callback + since: "7.2.0" --- name: UserNotificationCallbackResponse @@ -60,7 +60,7 @@ summary: | Response when receiving pending or local notifications in and . -since: "7.1.0" +since: "7.2.0" properties: - name: notifications type: Array @@ -69,11 +69,11 @@ properties: --- name: UserNotificationDictionary summary: | - Dictionary of notification data used in the array of `notifications` - when receiving pending or local notifications in + Dictionary of notification data used in the array of `notifications` + when receiving pending or local notifications in and . -since: "7.1.0" +since: "7.2.0" properties: - name: alertTitle summary: Title of the notification. @@ -127,10 +127,10 @@ properties: - name: identifier summary: The notification identifier. description: | - This property is required in iOS 10 and later and will fallback + This property is required in iOS 10 and later and will fallback to "notification" if not set. optional: false - since: "7.1.0" + since: "7.2.0" type: String - name: region @@ -145,7 +145,7 @@ properties: osver: {ios: {min: "10.0"}} --- -name: UserNotificationSettings +name: GetUserNotificationSettings summary: | Dictionary object of parameters used to register the application with local notifications using the method. @@ -154,7 +154,7 @@ platforms: [iphone, ipad] properties: - name: types summary: Notification types to use. - description: | + description: | Only available in iOS < 10. iOS 10 and later returns notification settings more detailed, check the other attributes for more information. type: Array @@ -163,12 +163,12 @@ properties: - name: categories summary: Set of categories of user notification actions required by the applicaiton to use. type: Array - description: | + description: | Only available in iOS < 10. iOS 10 and later returns notification settings more detailed, check the other attributes for more information. - name: authorizationStatus - summary: The current authorization status for using notifications. + summary: The current authorization status for using notifications. type: Number constants: [Titanium.App.iOS.USER_NOTIFICATION_AUTHORIZATION_STATUS_*] osver: {ios: {min: "10.0"}} diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index a7a2ccc9d63..c6e396cec59 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -311,7 +311,7 @@ properties: - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_NOT_DETERMINED summary: | - The user has not yet made a choice regarding whether the application may post + The user has not yet made a choice regarding whether the application may post user notifications. description: | Use to check the `authorizationStatus` attribute received in @@ -319,7 +319,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED summary: The application is authorized to post user notifications. @@ -329,7 +329,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED summary: The application is not authorized to post user notifications. @@ -339,7 +339,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_SETTING_NOT_SUPPORTED summary: The application does not support this notification type. @@ -349,7 +349,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_SETTING_ENABLED summary: The notification setting is turned on. @@ -359,7 +359,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_SETTING_DISABLED summary: The notification setting is turned off. @@ -369,7 +369,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_ALERT_STYLE_NONE summary: No banner or alert dialog is presented when the notification is received. @@ -379,7 +379,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_ALERT_STYLE_ALERT summary: A alert dialog is presented when the notification is received. @@ -389,7 +389,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: USER_NOTIFICATION_ALERT_STYLE_BANNER summary: A banner is presented when the notification is received. @@ -399,7 +399,7 @@ properties: type: Number permission: read-only osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: UTTYPE_TEXT summary: | @@ -669,7 +669,7 @@ properties: type: UserNotificationSettings permission: read-only deprecated: - since: "7.1.0" + since: "7.2.0" notes: Use instead. osver: {ios: {min: "8.0"}} since: "3.4.0" @@ -755,7 +755,7 @@ events: type: Dictionary - name: inBackground - summary: Boolean indicating if notification was received while app was in background (since Titanium SDK 6.2.0). + summary: Boolean indicating if notification was received while app was in background (since Titanium SDK 6.2.0). type: Boolean - name: localnotificationaction @@ -807,7 +807,7 @@ events: type: Dictionary - name: inBackground - summary: Boolean indicating if notification was received while app was in background (since Titanium SDK 6.2.0). + summary: Boolean indicating if notification was received while app was in background (since Titanium SDK 6.2.0). type: Boolean - name: remotenotificationaction @@ -889,9 +889,9 @@ events: The event returns the dictionary containing the `handlerID` property, which is a unique handler ID for the current event. This identifier should be passed as the argument to the [endBackgroundHandler](Titanium.App.iOS.endBackgroundHandler) method. - + You can send extra information with a silent push using extra: - + { aps: { 'content-available': 1 @@ -900,9 +900,9 @@ events: foo: 'bar' } } - + In the event handler for silentpush, your code may look something like this: - + { "handlerId": "SilentPush-1415976886.375816", "aps": { @@ -979,7 +979,7 @@ events: type: Number - name: sessionIdentifier - summary: | + summary: | The `urlSession` session identifier. If it does not exist, this property is not provided. This property is available since Titanium Mobile 5.4.0.GA. type: String @@ -1012,7 +1012,7 @@ events: type: Number - name: sessionIdentifier - summary: | + summary: | The `urlSession` session identifier. If it does not exist, this property is not provided. This property is available since Titanium Mobile 5.4.0.GA. type: String @@ -1045,7 +1045,7 @@ events: type: Number - name: sessionIdentifier - summary: | + summary: | The `urlSession` session identifier. If it does not exist, this property is not provided. This property is available since Titanium Mobile 5.4.0.GA. type: String @@ -1072,7 +1072,7 @@ events: type: Number - name: sessionIdentifier - summary: | + summary: | The `urlSession` session identifier. If it does not exist, this property is not provided. This property is available since Titanium Mobile 5.4.0.GA. type: String @@ -1112,7 +1112,7 @@ events: this method. properties: - name: sessionIdentifier - summary: | + summary: | The `urlSession` session identifier. If it does not exist, this property is not provided. This property is available since Titanium Mobile 5.4.0.GA. type: String @@ -1171,9 +1171,9 @@ events: - name: continueactivity summary: Fired when iOS continueactivity calls `continueUserActivity`. description: | - Add this event if your Titanium application if you are responding to an iOS Handoff or Core Spotlight `continueUserActivity` request. This event will - fire when a user taps on the handoff icon or the Core Spotlight search item. Your Titanium application will be opened in the background and provides - your Titanium app the information from the NSUserActivity. When this event is fired you should implement logic within your application to allow the + Add this event if your Titanium application if you are responding to an iOS Handoff or Core Spotlight `continueUserActivity` request. This event will + fire when a user taps on the handoff icon or the Core Spotlight search item. Your Titanium application will be opened in the background and provides + your Titanium app the information from the NSUserActivity. When this event is fired you should implement logic within your application to allow the user to pick-up from where they left off on their other device. Ti.App.iOS.addEventListener("continueactivity", function(e) { @@ -1187,7 +1187,7 @@ events: - name: searchableItemActivityIdentifier summary: | With field will contain the searchable Unique Identifier if the continueactivity is fired from a Core Spotlight searh result. - type: String + type: String - name: title summary: | The optional title provided to the user activity or search item. @@ -1198,7 +1198,7 @@ events: type: String - name: userInfo summary: | - The optional userInfo provided to the user activity. The userInfo is a custom dictionary and can contain any information needed + The optional userInfo provided to the user activity. The userInfo is a custom dictionary and can contain any information needed to create your handoff or Core Spotlight session. type: Dictionary platforms: [iphone, ipad] @@ -1222,7 +1222,7 @@ events: - name: userInfo summary: The payload passed by the application shortcut. - type: Dictionary + type: Dictionary platforms: [iphone] osver: {ios: {min: "9.0"}} since: '5.1.0' @@ -1251,10 +1251,10 @@ properties: - name: identifier summary: The notification identifier. description: | - This property is required in iOS 10 and later and will fallback + This property is required in iOS 10 and later and will fallback to "notification" if not set. optional: false - since: "7.1.0" + since: "7.2.0" type: String - name: alertAction @@ -1274,14 +1274,14 @@ properties: type: String optional: true osver: {ios: {min: "8.2"}} - since: "7.1.0" + since: "7.2.0" - name: alertSubtitle summary: Alert subtitle to display. type: String optional: true osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: alertLaunchImage summary: Image to display instead of `Default.png` when launching the application. @@ -1293,7 +1293,7 @@ properties: type: Array optional: true osver: {ios: {min: "10.0"}} - since: "7.1.0" + since: "7.2.0" - name: badge summary: Application badge value. @@ -1334,25 +1334,25 @@ properties: optional: true - name: region - summary: | + summary: | Region the notification will be triggered in. Allowed parameter are: - + - `latitude`: Latitude of the location center, in decimal degrees (required). - `longitude`: Longitude of the location center, in decimal degrees (required). - `triggersOnce`: Whether or not the notification will only fire once (optional, default: true). type: Dictionary optional: true osver: {ios: {min: "8.0"}} - since: "7.1.0" - + since: "7.2.0" + --- name: UserNotificationAttachment summary: | - Provide at least the property `identifier` and `url` property to identify a local + Provide at least the property `identifier` and `url` property to identify a local image, sound or video. If your media is invalid, the API will throw an error log and skip the invalid attachment. -since: "7.1.0" -platforms: [iphone, ipad] +since: "7.2.0" +platforms: [iphone, ipad] osver: {ios: {min: "10.0"}} properties: @@ -1364,7 +1364,7 @@ properties: - name: url type: String summary: | - The URL to the attachment's data. If you have obtained this attachment from + The URL to the attachment's data. If you have obtained this attachment from the notification-center then the URL will be security-scoped. optional: false - name: options @@ -1377,9 +1377,9 @@ properties: --- name: LaunchOptionsType summary: | - Dictionary object of parameters used to identify an incoming URL that is handled + Dictionary object of parameters used to identify an incoming URL that is handled by the application. -since: "6.0.0" +since: "6.0.0" platforms: [iphone, ipad] properties: - name: source @@ -1388,7 +1388,7 @@ properties: - name: url summary: The url that was triggered by the application or service. type: String - + --- name: UserNotificationSettings summary: | diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index d84d56e73e8..e5b81a03347 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -26,7 +26,7 @@ - (NSString *)apiName - (void)cancel:(id)unused { - DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"7.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.LocalNotification.cancel", @"7.2.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { NSString *identifier = @"notification"; diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 0b13e8a41fc..641d8646d66 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -495,7 +495,7 @@ - (NSArray *)supportedUserActivityTypes - (NSDictionary *)currentUserNotificationSettings { - DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"7.1.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); + DEPRECATED_REPLACED(@"App.iOS.currentUserNotificationSettings", @"7.2.0", @"App.iOS.NotificationCenter.requestUserNotificationSettings"); if ([TiUtils isIOS10OrGreater]) { DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); @@ -805,7 +805,7 @@ - (void)cancelAllLocalNotifications:(id)unused { ENSURE_UI_THREAD(cancelAllLocalNotifications, unused); - DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"7.1.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); + DEPRECATED_REPLACED(@"App.iOS.cancelAllLocalNotifications", @"7.2.0", @"App.iOS.NotificationCenter.removeAllPendingNotifications"); if ([TiUtils isIOS10OrGreater]) { [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; @@ -819,7 +819,7 @@ - (void)cancelLocalNotification:(id)value ENSURE_SINGLE_ARG(value, NSObject); ENSURE_UI_THREAD(cancelLocalNotification, value); - DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"7.1.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); + DEPRECATED_REPLACED(@"App.iOS.cancelLocalNotification", @"7.2.0", @"App.iOS.NotificationCenter.removePendingNotificationsWithIdentifiers"); if ([TiUtils isIOS10OrGreater]) { NSString *identifier = [TiUtils stringValue:value] ?: @"notification"; diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index 079ae34204b..c809457a228 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -82,7 +82,7 @@ - (void)setActivationMode:(id)value if ([TiUtils isIOS10OrGreater]) { return; // Not available on iOS 10+ } - + [(UIMutableUserNotificationAction *)[self notificationAction] setActivationMode:[TiUtils intValue:value]]; } diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 691fe46dab8..78ea9594955 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -99,7 +99,6 @@ - (void)removePendingNotifications:(id)args } [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - // Loop through current notification requests for (UNNotificationRequest *request in requests) { @@ -145,7 +144,6 @@ - (void)removeDeliveredNotifications:(id)args } [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray *requests) { - // Loop through current notification requests for (UNNotificationRequest *request in requests) { From 7784f471419df458852b9632c53d64be5a560c76 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Thu, 22 Mar 2018 21:33:16 +0100 Subject: [PATCH 40/44] More improvements and docs --- apidoc/Titanium/App/iOS/iOS.yml | 8 +++++--- iphone/Classes/TiApp.m | 25 ------------------------- iphone/Classes/TiAppiOSProxy.m | 31 ++++++++++++++++++++++++++++++- iphone/Classes/UtilsModule.m | 4 ++-- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index c6e396cec59..a6b875989c6 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -1354,9 +1354,7 @@ summary: | since: "7.2.0" platforms: [iphone, ipad] osver: {ios: {min: "10.0"}} - properties: - - name: identifier type: String summary: The identifier of this attachment. @@ -1371,7 +1369,11 @@ properties: type: Dictionary summary: An additional dictionary of options to provide. description: | - Allowed options can be found in the [Apple docs](https://developer.apple.com/reference/usernotifications/1974189-usernotifications_constants). + Allowed options are: + * `typeHint` - File type hint (String) + * `clipping` - Clipping enabled or not (Boolean) + * `thumbnailHidden` - Thumbnail hidden or not (Boolean) + * `thumbnailTime` - Video frame in milliseconds (Number) optional: true --- diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index 8094f22912f..c3e0b70b6ec 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -56,31 +56,6 @@ - (void)checkBackgroundServices; - (void)appBoot; @end -@interface TiUserNotificationExtention : UNNotificationServiceExtension - -@end - -@implementation TiUserNotificationExtention - -- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler -{ - NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[[request content] userInfo]]; - UNMutableNotificationContent *content = [(UNMutableNotificationContent *)[request content] copy]; - - [userInfo setObject:@YES forKey:@"isRemoteNotification"]; - [content setUserInfo:userInfo]; - - contentHandler(content); - RELEASE_TO_NIL(content); -} - -- (void)serviceExtensionTimeWillExpire -{ - [[NSNotificationCenter defaultCenter] postNotificationName:kTiRemoteExtentionWillExpire object:self userInfo:nil]; -} - -@end - @implementation TiApp - (void)clearMemoryPanic diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 641d8646d66..f679c02461f 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -512,6 +512,35 @@ - (NSDictionary *)currentUserNotificationSettings } } +- (NSDictionary *)formatNotificationAttachmentOptions:(NSDictionary *)options +{ + if (!options) { + return nil; + } + + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + + // We could use the raw string values here, but want to be future proof in case Apple + // renames them. Also, some require customc casting, like NSDictionary -> CGRect + for (NSString *key in options) { + if ([key isEqualToString:@"typeHint"]) { + result[UNNotificationAttachmentOptionsTypeHintKey] = options[key]; + } else if ([key isEqualToString:@"clipping"]) { + ENSURE_TYPE(options[key], NSDictionary); + CGRect rect = [TiUtils rectValue:options[key]]; + result[UNNotificationAttachmentOptionsThumbnailClippingRectKey] = CFBridgingRelease(CGRectCreateDictionaryRepresentation(rect)); + } else if ([key isEqualToString:@"thumbnailHidden"]) { + result[UNNotificationAttachmentOptionsThumbnailHiddenKey] = NUMBOOL(options[key]); + } else if ([key isEqualToString:@"thumbnailTime"]) { + result[UNNotificationAttachmentOptionsThumbnailTimeKey] = @([TiUtils doubleValue:options[key]] / 1000); // Convert milli-seconds to seconds + } else { + DebugLog(@"[ERROR] Unknown key \"%@\" provided for attachment options! Skipping ..."); + } + } + + return result; +} + - (NSDictionary *)formatUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { if (![NSThread isMainThread]) { @@ -663,7 +692,7 @@ - (id)scheduleLocalNotification:(id)args UNNotificationAttachment *_attachment = [UNNotificationAttachment attachmentWithIdentifier:_identifier URL:[TiUtils toURL:_url proxy:self] - options:_options + options:[[self formatNotificationAttachmentOptions:_options] retain] error:&error]; if (error != nil) { DebugLog(@"[ERROR] Attachment with the identifier = \"%@\" is invalid: %@", _identifier, [error localizedDescription]); diff --git a/iphone/Classes/UtilsModule.m b/iphone/Classes/UtilsModule.m index 810f5740e94..6c091e38622 100644 --- a/iphone/Classes/UtilsModule.m +++ b/iphone/Classes/UtilsModule.m @@ -90,7 +90,7 @@ - (id)sha1:(id)args NSData *data = [self convertToData:args]; unsigned char result[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1([data bytes], [data length], result); + CC_SHA1([data bytes], (int)[data length], result); return [TiUtils convertToHex:(unsigned char *)&result length:CC_SHA1_DIGEST_LENGTH]; } @@ -101,7 +101,7 @@ - (id)sha256:(id)args NSData *data = [self convertToData:args]; unsigned char result[CC_SHA256_DIGEST_LENGTH]; - CC_SHA256([data bytes], [data length], result); + CC_SHA256([data bytes], (int)[data length], result); return [TiUtils convertToHex:(unsigned char *)&result length:CC_SHA256_DIGEST_LENGTH]; } From f54fa40257885036d8bd38576161ef8b8d5fa516 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Fri, 23 Mar 2018 04:25:14 +0100 Subject: [PATCH 41/44] Fix missing argument in silent push-selector --- iphone/Classes/TiApp.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iphone/Classes/TiApp.m b/iphone/Classes/TiApp.m index c3e0b70b6ec..533f8ab574e 100644 --- a/iphone/Classes/TiApp.m +++ b/iphone/Classes/TiApp.m @@ -676,7 +676,7 @@ - (void)invokeSelector:(SEL)selector withArguments:(NSOrderedSet *)arguments [inv setTarget:delegate]; for (id obj in arguments) { - [inv setArgument:&(obj)atIndex:index++]; + [inv setArgument:&(obj) atIndex:index++]; } [inv invoke]; @@ -797,7 +797,7 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N [self application:application didReceiveRemoteNotification:userInfo]; } - [self tryToInvokeSelector:@selector(application:didReceiveRemoteNotification:) + [self tryToInvokeSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:) withArguments:[NSOrderedSet orderedSetWithObjects:application, userInfo, completionHandler, nil]]; //This only here for Simulator builds. From 2f3999dc6da413cd61c2435af8f892886a6e43c0 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Fri, 23 Mar 2018 04:25:47 +0100 Subject: [PATCH 42/44] Handle time-intervals in push notifications, always enable silent pish for dev builds --- iphone/Classes/TiAppiOSProxy.m | 4 ++++ iphone/Classes/defines.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index f679c02461f..4e06ffb061e 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -605,6 +605,10 @@ - (id)scheduleLocalNotification:(id)args UNNotificationTrigger *trigger; if (date) { + // Handle time intervals as well (backwards compatibility) + if ([date isKindOfClass:[NSNumber class]]) { + date = [NSDate dateWithTimeIntervalSince1970:[TiUtils doubleValue:date] / 1000]; + } NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; // Per default, use all components and don't repeat diff --git a/iphone/Classes/defines.h b/iphone/Classes/defines.h index a838156cab4..e1fb64f27a1 100644 --- a/iphone/Classes/defines.h +++ b/iphone/Classes/defines.h @@ -138,6 +138,7 @@ #define USE_TI_UIIOSAPPLICATIONSHORTCUTS #define USE_TI_UIIOSBLURVIEW #define USE_TI_NETWORKREGISTERFORPUSHNOTIFICATIONS +#define USE_TI_SILENTPUSH #define USE_TI_MEDIASHOWCAMERA #define USE_TI_MEDIAHIDECAMERA @@ -204,4 +205,4 @@ #define USE_TI_MEDIAPEAKMICROPHONEPOWER #define USE_TI_MEDIAGETPEAKMICROPHONEPOWER #define USE_TI_MEDIAAVERAGEMICROPHONEPOWER -#define USE_TI_MEDIAGETAVERAGEMICROPHONEPOWER \ No newline at end of file +#define USE_TI_MEDIAGETAVERAGEMICROPHONEPOWER From cc3fd5fdb7e94201f69ec3a35c606c147114deb3 Mon Sep 17 00:00:00 2001 From: hansemannnn Date: Sat, 24 Mar 2018 19:01:20 +0100 Subject: [PATCH 43/44] =?UTF-8?q?[TIMOB-23527]=20Expose=20missing=20API?= =?UTF-8?q?=E2=80=99s,=20update=20a=20few=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App/iOS/UserNotificationCategory.yml | 28 +++++++- apidoc/Titanium/App/iOS/iOS.yml | 65 ++++++++++++++++--- .../Classes/TiAppiOSLocalNotificationProxy.h | 2 +- .../Classes/TiAppiOSLocalNotificationProxy.m | 2 +- iphone/Classes/TiAppiOSProxy.m | 45 +++++++++++++ .../TiAppiOSUserNotificationActionProxy.h | 2 +- .../TiAppiOSUserNotificationActionProxy.m | 2 +- .../TiAppiOSUserNotificationCategoryProxy.h | 2 +- .../TiAppiOSUserNotificationCategoryProxy.m | 45 ++++++++++--- .../TiAppiOSUserNotificationCenterProxy.h | 2 +- .../TiAppiOSUserNotificationCenterProxy.m | 27 ++++---- iphone/Classes/defines.h | 1 + 12 files changed, 186 insertions(+), 37 deletions(-) diff --git a/apidoc/Titanium/App/iOS/UserNotificationCategory.yml b/apidoc/Titanium/App/iOS/UserNotificationCategory.yml index 1e8837d9361..4a2a9d0502e 100644 --- a/apidoc/Titanium/App/iOS/UserNotificationCategory.yml +++ b/apidoc/Titanium/App/iOS/UserNotificationCategory.yml @@ -36,7 +36,7 @@ properties: summary: Array of notification actions to display for non-dialog-style notification. description: | If not specified, the first two actions from `actionsForDefaultContent` are displayed. - Note: This property has been removed in iOS 10 and iOS will handle the actions internally. + Note: This property has been removed in iOS 10. iOS 10+ will handle the actions internally. type: Array accessors: false osver: {ios: {max: 9.3}} @@ -50,3 +50,29 @@ properties: accessors: false availability: creation + - name: intentIdentifiers + summary: The intents related to notifications of this category. + description: | + When a notification is delivered, the presence of an intent identifier + lets the system know that the notification is potentially related to the + handling of a request made through Siri. + type: Array + accessors: false + osver: {ios: {min: 10.0}} + availability: creation + + - name: hiddenPreviewsBodyPlaceholder + summary: The placeholder text to display when notification previews are disabled for the app. + type: String + accessors: false + osver: {ios: {min: 11.0}} + availability: creation + + - name: options + summary: Options for how to handle notifications of this type. + description: If not specified, defaults to . + type: Array + accessors: false + constants: [Titanium.App.iOS.USER_NOTIFICATION_CATEGORY_OPTION_*] + osver: {ios: {min: 10.0}} + availability: creation diff --git a/apidoc/Titanium/App/iOS/iOS.yml b/apidoc/Titanium/App/iOS/iOS.yml index a6b875989c6..06b14b100bb 100644 --- a/apidoc/Titanium/App/iOS/iOS.yml +++ b/apidoc/Titanium/App/iOS/iOS.yml @@ -314,7 +314,7 @@ properties: The user has not yet made a choice regarding whether the application may post user notifications. description: | - Use to check the `authorizationStatus` attribute received in + Used to check the `authorizationStatus` attribute received in . type: Number permission: read-only @@ -324,7 +324,7 @@ properties: - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_AUTHORIZED summary: The application is authorized to post user notifications. description: | - Use to check the `authorizationStatus` attribute received in + Used to check the `authorizationStatus` attribute received in . type: Number permission: read-only @@ -334,7 +334,7 @@ properties: - name: USER_NOTIFICATION_AUTHORIZATION_STATUS_DENIED summary: The application is not authorized to post user notifications. description: | - Use to check the `authorizationStatus` attribute received in + Used to check the `authorizationStatus` attribute received in . type: Number permission: read-only @@ -344,7 +344,7 @@ properties: - name: USER_NOTIFICATION_SETTING_NOT_SUPPORTED summary: The application does not support this notification type. description: | - Use to check application-wide enabled notification settings received in + Used to check application-wide enabled notification settings received in . type: Number permission: read-only @@ -354,7 +354,7 @@ properties: - name: USER_NOTIFICATION_SETTING_ENABLED summary: The notification setting is turned on. description: | - Use to check application-wide enabled notification settings received in + Used to check application-wide enabled notification settings received in . type: Number permission: read-only @@ -364,7 +364,7 @@ properties: - name: USER_NOTIFICATION_SETTING_DISABLED summary: The notification setting is turned off. description: | - Use to check application-wide enabled notification settings received in + Used to check application-wide enabled notification settings received in . type: Number permission: read-only @@ -374,7 +374,7 @@ properties: - name: USER_NOTIFICATION_ALERT_STYLE_NONE summary: No banner or alert dialog is presented when the notification is received. description: | - Use to check the `alertStyle` attribute received in + Used to check the `alertStyle` attribute received in . type: Number permission: read-only @@ -384,7 +384,7 @@ properties: - name: USER_NOTIFICATION_ALERT_STYLE_ALERT summary: A alert dialog is presented when the notification is received. description: | - Use to check the `alertStyle` attribute received in + Used to check the `alertStyle` attribute received in . type: Number permission: read-only @@ -394,13 +394,58 @@ properties: - name: USER_NOTIFICATION_ALERT_STYLE_BANNER summary: A banner is presented when the notification is received. description: | - Use to check the `alertStyle` attribute received in + Used to check the `alertStyle` attribute received in . type: Number permission: read-only osver: {ios: {min: "10.0"}} since: "7.2.0" + - name: USER_NOTIFICATION_CATEGORY_OPTION_NONE + summary: No options. + description: | + Used in the `options` attribute when creating a . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "7.2.0" + + - name: USER_NOTIFICATION_CATEGORY_OPTION_CUSTOM_DISMISS_ACTION + summary: Send dismiss actions to the UNUserNotificationCenter object's delegate for handling. + description: | + Used in the `options` attribute when creating a . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "7.2.0" + + - name: USER_NOTIFICATION_CATEGORY_OPTION_ALLOW_IN_CARPLAY + summary: Allow CarPlay to display notifications of this type. + description: | + Used in the `options` attribute when creating a . + type: Number + permission: read-only + osver: {ios: {min: "10.0"}} + since: "7.2.0" + + - name: USER_NOTIFICATION_CATEGORY_OPTION_HIDEEN_PREVIEWS_SHOW_TITLE + summary: Show the notification's title, even if the user has disabled notification previews for the app. + description: | + Used in the `options` attribute when creating a . + type: Number + permission: read-only + osver: {ios: {min: "11.0"}} + since: "7.2.0" + + - name: USER_NOTIFICATION_CATEGORY_OPTION_HIDEEN_PREVIEWS_SHOW_SUBTITLE + summary: Show the notification's subtitle, even if the user has disabled notification previews for the app. + description: | + Used in the `options` attribute when creating a . + type: Number + permission: read-only + osver: {ios: {min: "11.0"}} + since: "7.2.0" + - name: UTTYPE_TEXT summary: | Uniform type identifier for all text types. @@ -743,7 +788,7 @@ events: type: Date - name: sound - summary: Path to the sound file configured to play when the notification was fired. + summary: Name of the sound file configured to play when the notification was fired. type: String - name: timezone diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index deaaae67114..add35f51db7 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.m b/iphone/Classes/TiAppiOSLocalNotificationProxy.m index e5b81a03347..a0ee272d55a 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.m +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.m @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 4e06ffb061e..2a130fee9f7 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -1083,6 +1083,51 @@ - (NSNumber *)USER_NOTIFICATION_BEHAVIOR_TEXTINPUT return NUMINT(0); } +- (NSNumber *)USER_NOTIFICATION_CATEGORY_OPTION_NONE +{ + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNNotificationCategoryOptionNone); + } + + return NUMINT(0); +} + +- (NSNumber *)USER_NOTIFICATION_CATEGORY_OPTION_CUSTOM_DISMISS_ACTION +{ + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNNotificationCategoryOptionCustomDismissAction); + } + + return NUMINT(0); +} + +- (NSNumber *)USER_NOTIFICATION_CATEGORY_OPTION_ALLOW_IN_CARPLAY +{ + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNNotificationCategoryOptionAllowInCarPlay); + } + + return NUMINT(0); +} + +- (NSNumber *)USER_NOTIFICATION_CATEGORY_OPTION_HIDEEN_PREVIEWS_SHOW_TITLE +{ + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNNotificationCategoryOptionHiddenPreviewsShowTitle); + } + + return NUMINT(0); +} + +- (NSNumber *)USER_NOTIFICATION_CATEGORY_OPTION_HIDEEN_PREVIEWS_SHOW_SUBTITLE +{ + if ([TiUtils isIOS10OrGreater]) { + return NUMINT(UNNotificationCategoryOptionHiddenPreviewsShowSubtitle); + } + + return NUMINT(0); +} + #pragma mark UTI Text Type Constants - (CFStringRef)UTTYPE_TEXT { diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h index 52383509901..377ff514850 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.h @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m index c809457a228..9148542aaca 100644 --- a/iphone/Classes/TiAppiOSUserNotificationActionProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationActionProxy.m @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h index 16f9fa7e737..4014f75c7b8 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.h @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m index 3b12710a1e2..cc4f0fbfada 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCategoryProxy.m @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ @@ -28,10 +28,12 @@ - (void)_initWithProperties:(NSDictionary *)properties { if (_notificationCategory == nil) { - id identifier = [properties valueForKey:@"identifier"]; - id actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; - id actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; - id intentIdentifiers = [properties valueForKey:@"intentIdentifiers"]; + NSString *identifier = [properties valueForKey:@"identifier"]; + NSArray *actionsForDefaultContext = [properties valueForKey:@"actionsForDefaultContext"]; + NSArray *actionsForMinimalContext = [properties valueForKey:@"actionsForMinimalContext"]; + NSArray *intentIdentifiers = [properties valueForKey:@"intentIdentifiers"] ?: @[]; + NSString *hiddenPreviewsBodyPlaceholder = [properties valueForKey:@"hiddenPreviewsBodyPlaceholder"]; + UNNotificationCategoryOptions options = [self categoryOptionsFromArray:[properties valueForKey:@"options"] ?: @[]]; NSMutableArray *defaultActions = [NSMutableArray new]; NSMutableArray *minimalActions = [NSMutableArray new]; @@ -52,12 +54,24 @@ - (void)_initWithProperties:(NSDictionary *)properties } } + // For iOS 10+, use the UserNotifications framerwork if ([TiUtils isIOS10OrGreater]) { - _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier - actions:defaultActions - intentIdentifiers:intentIdentifiers ?: @[] - options:UNNotificationCategoryOptionCustomDismissAction] retain]; + // For iOS 11+, use the "hiddenPreviewsBodyPlaceholder" constructor + if (hiddenPreviewsBodyPlaceholder != nil && [TiUtils isIOSVersionOrGreater:@"11.0"]) { + _notificationCategory = [UNNotificationCategory categoryWithIdentifier:identifier + actions:defaultActions + intentIdentifiers:intentIdentifiers + hiddenPreviewsBodyPlaceholder:hiddenPreviewsBodyPlaceholder + options:options]; + } else { + // For iOS < 11, use the default constructor + _notificationCategory = [[UNNotificationCategory categoryWithIdentifier:identifier + actions:defaultActions + intentIdentifiers:intentIdentifiers + options:options] retain]; + } } else { + // For iOS < 10, use the old constructor _notificationCategory = [UIMutableUserNotificationCategory new]; [_notificationCategory setIdentifier:identifier]; @@ -82,6 +96,19 @@ - (NSString *)identifier return [[self notificationCategory] identifier]; } +#pragma mark Helper + +- (UNNotificationCategoryOptions)categoryOptionsFromArray:(NSArray *)array +{ + UNNotificationCategoryOptions options = UNNotificationCategoryOptionNone; + + for (id option in array) { + options |= [TiUtils intValue:option]; + } + + return options; +} + @end #endif diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h index 31c4e76587d..bfdba76e2be 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.h @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ diff --git a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m index 78ea9594955..fa7dae69341 100644 --- a/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m +++ b/iphone/Classes/TiAppiOSUserNotificationCenterProxy.m @@ -1,6 +1,6 @@ /** * Appcelerator Titanium Mobile - * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved. + * Copyright (c) 2009-2018 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Apache Public License * Please see the LICENSE included with this distribution for details. */ @@ -174,16 +174,21 @@ - (void)requestUserNotificationSettings:(id)args if ([TiUtils isIOS10OrGreater]) { TiThreadPerformOnMainThread(^{ [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { - NSDictionary *propertiesDict = @{ - @"authorizationStatus" : NUMINTEGER([settings authorizationStatus]), - @"soundSetting" : NUMINTEGER([settings soundSetting]), - @"badgeSetting" : NUMINTEGER([settings badgeSetting]), - @"alertSetting" : NUMINTEGER([settings alertSetting]), - @"notificationCenterSetting" : NUMINTEGER([settings notificationCenterSetting]), - @"lockScreenSetting" : NUMINTEGER([settings lockScreenSetting]), - @"carPlaySetting" : NUMINTEGER([settings carPlaySetting]), - @"alertStyle" : NUMINTEGER([settings alertStyle]) - }; + NSMutableDictionary *propertiesDict = [@{ + @"authorizationStatus" : @([settings authorizationStatus]), + @"soundSetting" : @([settings soundSetting]), + @"badgeSetting" : @([settings badgeSetting]), + @"alertSetting" : @([settings alertSetting]), + @"notificationCenterSetting" : @([settings notificationCenterSetting]), + @"lockScreenSetting" : @([settings lockScreenSetting]), + @"carPlaySetting" : @([settings carPlaySetting]), + @"alertStyle" : @([settings alertStyle]) + } mutableCopy]; +#if IS_XCODE_9 + if ([TiUtils isIOSVersionOrGreater:@"11.0"]) { + propertiesDict[@"showPreviewsSetting"] = @([settings showPreviewsSetting]); + } +#endif NSArray *invocationArray = [[NSArray alloc] initWithObjects:&propertiesDict count:1]; [callback call:invocationArray thisObject:self]; diff --git a/iphone/Classes/defines.h b/iphone/Classes/defines.h index e1fb64f27a1..9c88b280ee6 100644 --- a/iphone/Classes/defines.h +++ b/iphone/Classes/defines.h @@ -139,6 +139,7 @@ #define USE_TI_UIIOSBLURVIEW #define USE_TI_NETWORKREGISTERFORPUSHNOTIFICATIONS #define USE_TI_SILENTPUSH +#define USE_TI_FETCH #define USE_TI_MEDIASHOWCAMERA #define USE_TI_MEDIAHIDECAMERA From add93ffcfc40743ac9e9ff56324b3f313388cb3d Mon Sep 17 00:00:00 2001 From: hansemannn Date: Fri, 18 May 2018 11:05:27 +0200 Subject: [PATCH 44/44] Fix review comments --- .../Titanium/App/iOS/NotificationCenter.yml | 18 +++++++++--------- iphone/Classes/MediaModule.m | 4 ++-- .../Classes/TiAppiOSLocalNotificationProxy.h | 2 +- iphone/Classes/TiAppiOSProxy.m | 19 +++++++++---------- iphone/Classes/TiAppiOSSearchQueryProxy.h | 1 - iphone/Classes/TiAppiOSSearchQueryProxy.m | 1 - iphone/Classes/TiMediaSoundProxy.m | 2 +- 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/apidoc/Titanium/App/iOS/NotificationCenter.yml b/apidoc/Titanium/App/iOS/NotificationCenter.yml index 22bed31be55..d0118642600 100644 --- a/apidoc/Titanium/App/iOS/NotificationCenter.yml +++ b/apidoc/Titanium/App/iOS/NotificationCenter.yml @@ -7,7 +7,7 @@ summary: | extends: Titanium.Module platforms: [iphone, ipad] osver: {ios: {min: "8.0"}} -since: "7.2.0" +since: "7.3.0" methods: - name: getPendingNotifications @@ -18,7 +18,7 @@ methods: The function that is being called after the notifications have been fetched. type: Callback - since: "7.2.0" + since: "7.3.0" - name: getDeliveredNotifications summary: Fetches the delivered notifications asynchronously. @@ -29,20 +29,20 @@ methods: have been fetched. type: Callback osver: {ios: {min: "10.0"}} - since: "7.2.0" + since: "7.3.0" - name: removePendingNotifications summary: | Removes the specified pending notifications to prevent them from being triggered. If no notifications are specified, all pending notifications will be removed. - since: "7.2.0" + since: "7.3.0" - name: removeDeliveredNotifications summary: | Removes the specified delivered notifications from the notification-center. If no notifications are specified, all delivered notifications will be removed. osver: {ios: {min: "10.0"}} - since: "7.2.0" + since: "7.3.0" - name: requestUserNotificationSettings summary: | @@ -52,7 +52,7 @@ methods: - name: callback summary: The callback invoked when requesting user notification settings. type: Callback - since: "7.2.0" + since: "7.3.0" --- name: UserNotificationCallbackResponse @@ -60,7 +60,7 @@ summary: | Response when receiving pending or local notifications in and . -since: "7.2.0" +since: "7.3.0" properties: - name: notifications type: Array @@ -73,7 +73,7 @@ summary: | when receiving pending or local notifications in and . -since: "7.2.0" +since: "7.3.0" properties: - name: alertTitle summary: Title of the notification. @@ -130,7 +130,7 @@ properties: This property is required in iOS 10 and later and will fallback to "notification" if not set. optional: false - since: "7.2.0" + since: "7.3.0" type: String - name: region diff --git a/iphone/Classes/MediaModule.m b/iphone/Classes/MediaModule.m index 549c1ef7474..1239b03538c 100644 --- a/iphone/Classes/MediaModule.m +++ b/iphone/Classes/MediaModule.m @@ -20,12 +20,12 @@ #import "TiUtils.h" #import "TiViewProxy.h" -#import -#import #import #import +#import #import #import +#import #import #import #import diff --git a/iphone/Classes/TiAppiOSLocalNotificationProxy.h b/iphone/Classes/TiAppiOSLocalNotificationProxy.h index add35f51db7..348e80a70de 100644 --- a/iphone/Classes/TiAppiOSLocalNotificationProxy.h +++ b/iphone/Classes/TiAppiOSLocalNotificationProxy.h @@ -17,7 +17,7 @@ @property (nonatomic, retain) id notification; -- (void)cancel:(id)used; +- (void)cancel:(id)unused; @end diff --git a/iphone/Classes/TiAppiOSProxy.m b/iphone/Classes/TiAppiOSProxy.m index 2a130fee9f7..d191aeb3e7e 100644 --- a/iphone/Classes/TiAppiOSProxy.m +++ b/iphone/Classes/TiAppiOSProxy.m @@ -499,17 +499,16 @@ - (NSDictionary *)currentUserNotificationSettings if ([TiUtils isIOS10OrGreater]) { DebugLog(@"[ERROR] Please use Ti.App.iOS.NotificationCenter.requestUserNotificationSettings in iOS 10 and later to request user notification settings asynchronously."); - return; - } else { - __block NSDictionary *returnVal = nil; - TiThreadPerformOnMainThread(^{ - UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; - }, - YES); - - return [returnVal autorelease]; } + + __block NSDictionary *returnVal = nil; + TiThreadPerformOnMainThread(^{ + UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + returnVal = [[self formatUserNotificationSettings:notificationSettings] retain]; + }, + YES); + + return [returnVal autorelease]; } - (NSDictionary *)formatNotificationAttachmentOptions:(NSDictionary *)options diff --git a/iphone/Classes/TiAppiOSSearchQueryProxy.h b/iphone/Classes/TiAppiOSSearchQueryProxy.h index 628c4edde8a..c8352dd66f7 100644 --- a/iphone/Classes/TiAppiOSSearchQueryProxy.h +++ b/iphone/Classes/TiAppiOSSearchQueryProxy.h @@ -27,4 +27,3 @@ @end #endif - diff --git a/iphone/Classes/TiAppiOSSearchQueryProxy.m b/iphone/Classes/TiAppiOSSearchQueryProxy.m index 48a931304e8..c05b415e215 100644 --- a/iphone/Classes/TiAppiOSSearchQueryProxy.m +++ b/iphone/Classes/TiAppiOSSearchQueryProxy.m @@ -103,4 +103,3 @@ - (NSNumber *)isCancelled:(id)unused @end #endif - diff --git a/iphone/Classes/TiMediaSoundProxy.m b/iphone/Classes/TiMediaSoundProxy.m index bb782efe6a9..a1e6f9d788c 100644 --- a/iphone/Classes/TiMediaSoundProxy.m +++ b/iphone/Classes/TiMediaSoundProxy.m @@ -6,8 +6,8 @@ */ #ifdef USE_TI_MEDIASOUND -#import #import +#import #import "TiBlob.h" #import "TiFile.h"