diff --git a/OneSignal.podspec b/OneSignal.podspec index 56d51daf1..17dfb25e3 100644 --- a/OneSignal.podspec +++ b/OneSignal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "OneSignal" - s.version = "2.1.0" + s.version = "2.1.1" s.summary = "OneSignal push notification library for mobile apps." s.homepage = "https://onesignal.com" s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/OneSignalExample/push-notifications/AppDelegate.m b/OneSignalExample/push-notifications/AppDelegate.m index 8e77e1a2b..1eeac3cd9 100755 --- a/OneSignalExample/push-notifications/AppDelegate.m +++ b/OneSignalExample/push-notifications/AppDelegate.m @@ -37,7 +37,7 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N [OneSignal initWithLaunchOptions:launchOptions appId:@"b2f7f966-d8cc-11e4-bed1-df8f05be55ba" handleNotificationReceived:^(OSNotification *notification) { NSLog(@"Received Notification - %@", notification.payload.notificationID); - } handleNotificationAction:^(OSNotificationResult *result) { + } handleNotificationAction:^(OSNotificationOpenedResult *result) { // This block gets called when the user reacts to a notification received OSNotificationPayload* payload = result.notification.payload; @@ -50,8 +50,6 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N if(payload.title) messageTitle = payload.title; - NSDictionary* additionalData = payload.additionalData; - if (result.action.actionID) fullMessage = [fullMessage stringByAppendingString:[NSString stringWithFormat:@"\nPressed ButtonId:%@", result.action.actionID]]; } diff --git a/OneSignalSwiftExample/OneSignalSwiftExample.xcodeproj/project.pbxproj b/OneSignalSwiftExample/OneSignalSwiftExample.xcodeproj/project.pbxproj index 7c7a04ec2..58bb5d4b5 100644 --- a/OneSignalSwiftExample/OneSignalSwiftExample.xcodeproj/project.pbxproj +++ b/OneSignalSwiftExample/OneSignalSwiftExample.xcodeproj/project.pbxproj @@ -106,6 +106,7 @@ TargetAttributes = { 91E4D50C1C7521DE00025BA8 = { CreatedOnToolsVersion = 7.2; + DevelopmentTeam = 99SW8E36CT; SystemCapabilities = { com.apple.BackgroundModes = { enabled = 1; @@ -264,12 +265,14 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 99SW8E36CT; FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../iOS_SDK/Framework\""; INFOPLIST_FILE = OneSignalSwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.onesignal.example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "OneSignalSwiftExample/OneSignalSwiftExample-Bridging-Header.h"; + SWIFT_VERSION = ""; }; name = Debug; }; @@ -277,12 +280,14 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 99SW8E36CT; FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../iOS_SDK/Framework\""; INFOPLIST_FILE = OneSignalSwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.onesignal.example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "OneSignalSwiftExample/OneSignalSwiftExample-Bridging-Header.h"; + SWIFT_VERSION = ""; }; name = Release; }; diff --git a/iOS_SDK/Framework/OneSignal.framework/Versions/A/Headers/OneSignal.h b/iOS_SDK/Framework/OneSignal.framework/Versions/A/Headers/OneSignal.h index c9b2dc4df..a84877e06 100755 --- a/iOS_SDK/Framework/OneSignal.framework/Versions/A/Headers/OneSignal.h +++ b/iOS_SDK/Framework/OneSignal.framework/Versions/A/Headers/OneSignal.h @@ -144,6 +144,12 @@ typedef enum : NSUInteger { requires remote-notification within UIBackgroundModes array of the Info.plist */ @property(readonly, getter=isSilentNotification)BOOL silentNotification; +/* iOS 10+: Indicates wether or not the received notification has mutableContent : 1 assigned to its payload + Used for UNNotificationServiceExtension to launch extension. +*/ +#if XC8_AVAILABLE +@property(readonly, getter=hasMutableContent)BOOL mutableContent; +#endif /* Convert object into an NSString that can be convertible into a custom Dictionary / JSON Object */ - (NSString*)stringify; @@ -241,7 +247,6 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { + (void)IdsAvailable:(OSIdsAvailableBlock)idsAvailableBlock; // - Alerting -// + (void)enableInAppAlertNotification:(BOOL)enable; + (void)setSubscription:(BOOL)enable; // - Posting Notification diff --git a/iOS_SDK/Framework/OneSignal.framework/Versions/A/OneSignal b/iOS_SDK/Framework/OneSignal.framework/Versions/A/OneSignal index c89bb245e..ac7a9c47f 100644 Binary files a/iOS_SDK/Framework/OneSignal.framework/Versions/A/OneSignal and b/iOS_SDK/Framework/OneSignal.framework/Versions/A/OneSignal differ diff --git a/iOS_SDK/Framework/OneSignal.framework/Versions/B/Headers/OneSignal.h b/iOS_SDK/Framework/OneSignal.framework/Versions/B/Headers/OneSignal.h index c9b2dc4df..a84877e06 100755 --- a/iOS_SDK/Framework/OneSignal.framework/Versions/B/Headers/OneSignal.h +++ b/iOS_SDK/Framework/OneSignal.framework/Versions/B/Headers/OneSignal.h @@ -144,6 +144,12 @@ typedef enum : NSUInteger { requires remote-notification within UIBackgroundModes array of the Info.plist */ @property(readonly, getter=isSilentNotification)BOOL silentNotification; +/* iOS 10+: Indicates wether or not the received notification has mutableContent : 1 assigned to its payload + Used for UNNotificationServiceExtension to launch extension. +*/ +#if XC8_AVAILABLE +@property(readonly, getter=hasMutableContent)BOOL mutableContent; +#endif /* Convert object into an NSString that can be convertible into a custom Dictionary / JSON Object */ - (NSString*)stringify; @@ -241,7 +247,6 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { + (void)IdsAvailable:(OSIdsAvailableBlock)idsAvailableBlock; // - Alerting -// + (void)enableInAppAlertNotification:(BOOL)enable; + (void)setSubscription:(BOOL)enable; // - Posting Notification diff --git a/iOS_SDK/Framework/OneSignal.framework/Versions/B/OneSignal b/iOS_SDK/Framework/OneSignal.framework/Versions/B/OneSignal index cd945d9b5..36d376534 100644 Binary files a/iOS_SDK/Framework/OneSignal.framework/Versions/B/OneSignal and b/iOS_SDK/Framework/OneSignal.framework/Versions/B/OneSignal differ diff --git a/iOS_SDK/OneSignal/OneSignal.h b/iOS_SDK/OneSignal/OneSignal.h index c9b2dc4df..a84877e06 100755 --- a/iOS_SDK/OneSignal/OneSignal.h +++ b/iOS_SDK/OneSignal/OneSignal.h @@ -144,6 +144,12 @@ typedef enum : NSUInteger { requires remote-notification within UIBackgroundModes array of the Info.plist */ @property(readonly, getter=isSilentNotification)BOOL silentNotification; +/* iOS 10+: Indicates wether or not the received notification has mutableContent : 1 assigned to its payload + Used for UNNotificationServiceExtension to launch extension. +*/ +#if XC8_AVAILABLE +@property(readonly, getter=hasMutableContent)BOOL mutableContent; +#endif /* Convert object into an NSString that can be convertible into a custom Dictionary / JSON Object */ - (NSString*)stringify; @@ -241,7 +247,6 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { + (void)IdsAvailable:(OSIdsAvailableBlock)idsAvailableBlock; // - Alerting -// + (void)enableInAppAlertNotification:(BOOL)enable; + (void)setSubscription:(BOOL)enable; // - Posting Notification diff --git a/iOS_SDK/OneSignal/OneSignal.m b/iOS_SDK/OneSignal/OneSignal.m index ad0023606..5275ad870 100755 --- a/iOS_SDK/OneSignal/OneSignal.m +++ b/iOS_SDK/OneSignal/OneSignal.m @@ -71,7 +71,7 @@ @implementation OneSignal -NSString* const ONESIGNAL_VERSION = @"020100"; +NSString* const ONESIGNAL_VERSION = @"020101"; static NSString* mSDKType = @"native"; static BOOL coldStartFromTapOnNotification = NO; static BOOL registeredWithApple = NO; //Has attempted to register for push notifications with Apple. @@ -205,8 +205,10 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId trackIAPPurchase = [[OneSignalTrackIAP alloc] init]; if (NSClassFromString(@"UNUserNotificationCenter")) { + #if XC8_AVAILABLE [OneSignalHelper registerAsUNNotificationCenterDelegate]; [OneSignalHelper clearCachedMedia]; + #endif } return self; @@ -263,8 +265,10 @@ void onesignal_Log(ONE_S_LOG_LEVEL logLevel, NSString* message) { // "registerForRemoteNotifications*" calls didRegisterForRemoteNotificationsWithDeviceToken // in the implementation UIApplication(OneSignalPush) below after contacting Apple's server. + (void)registerForPushNotifications { - + + #if XC8_AVAILABLE [OneSignalHelper requestAuthorization]; + #endif // For iOS 8 devices if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) { @@ -761,7 +765,8 @@ + (void)notificationOpened:(NSDictionary*)messageDict isActive:(BOOL)isActive { [OneSignalHelper lastMessageReceived:messageDict]; - if (inAppAlert) { + //Make sure it is not a silent one do display, if inAppAlerts are enabled + if (inAppAlert && ![OneSignalHelper isRemoteSilentNotification:messageDict]) { NSArray* titleAndBody = [OneSignalHelper getPushTitleBody:messageDict]; id oneSignalAlertViewDelegate = [[OneSignalAlertViewDelegate alloc] initWithMessageDict:messageDict]; @@ -950,13 +955,8 @@ + (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictio // If 'm' present then the notification has action buttons attached to it. NSDictionary* data = nil; - if (userInfo[@"os_data"]) - data = userInfo[@"os_data"][@"buttons"]; - else if (userInfo[@"m"]) - data = userInfo; - - // - TEMP until server sends special field for attachments - else if (userInfo[@"custom"][@"at"]) + // Check for buttons or attachments + if (userInfo[@"os_data"][@"buttons"] || userInfo[@"at"] || userInfo[@"o"]) data = userInfo; //If buttons -> Data is buttons diff --git a/iOS_SDK/OneSignal/OneSignalHelper.h b/iOS_SDK/OneSignal/OneSignalHelper.h index 075bdf902..aaabdeff6 100644 --- a/iOS_SDK/OneSignal/OneSignalHelper.h +++ b/iOS_SDK/OneSignal/OneSignalHelper.h @@ -26,6 +26,7 @@ */ #import "OneSignal.h" +#import "OneSignalWebView.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -33,6 +34,7 @@ @interface OneSignalHelper : NSObject // - Web ++ (OneSignalWebView*)webVC; + (void) displayWebView:(NSURL*)url; // - Notification Opened @@ -44,15 +46,18 @@ + (void)handleNotificationAction:(OSNotificationActionType)actionType actionID:(NSString*)actionID displayType:(OSNotificationDisplayType)displayType; // - iOS 10 ++ (BOOL)isiOS10Plus; +#if XC8_AVAILABLE ++ (void)registerAsUNNotificationCenterDelegate; + (void) requestAuthorization; + (void)conformsToUNProtocol; -+ (void)registerAsUNNotificationCenterDelegate; + (void)clearCachedMedia; ++ (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInfo; +#endif // - Notifications + (BOOL) isCapableOfGettingNotificationTypes; + (UILocalNotification*)prepareUILocalNotification:(NSDictionary*)data :(NSDictionary*)userInfo; -+ (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInfo; + (BOOL)verifyURL:(NSString *)urlString; + (BOOL) isRemoteSilentNotification:(NSDictionary*)msg; diff --git a/iOS_SDK/OneSignal/OneSignalHelper.m b/iOS_SDK/OneSignal/OneSignalHelper.m index ddf99e36f..eb5bb7d2d 100644 --- a/iOS_SDK/OneSignal/OneSignalHelper.m +++ b/iOS_SDK/OneSignal/OneSignalHelper.m @@ -28,7 +28,6 @@ #import "OneSignalReachability.h" #import "OneSignalHelper.h" #import "NSObject+Extras.h" -#import "OneSignalWebView.h" #import @@ -90,10 +89,10 @@ - (id)initWithRawMessage:(NSDictionary*)message { NSDictionary * custom = _rawPayload[@"custom"]; if(custom[@"a"]) _additionalData = [custom[@"a"] copy]; - if(custom[@"at"]) - _attachments = [custom[@"at"] copy]; _notificationID = custom[@"i"]; _launchURL = custom[@"u"]; + + _attachments = [_rawPayload[@"at"] copy]; } else if(_rawPayload[@"os_data"]) { NSDictionary * os_data = _rawPayload[@"os_data"]; @@ -106,15 +105,19 @@ - (id)initWithRawMessage:(NSDictionary*)message { _notificationID = os_data[@"i"]; _launchURL = os_data[@"u"]; - if(os_data[@"at"]) - _attachments = [os_data[@"at"] copy]; + if(os_data[@"buttons"][@"at"]) + _attachments = [os_data[@"buttons"][@"at"] copy]; } if(_rawPayload[@"m"]) { - NSDictionary * m = _rawPayload[@"m"]; - _body = m[@"body"]; - _title = m[@"title"]; - _subtitle = m[@"subtitle"]; + id m = _rawPayload[@"m"]; + if([m isKindOfClass:[NSDictionary class]]) { + _body = m[@"body"]; + _title = m[@"title"]; + _subtitle = m[@"subtitle"]; + } + //Content-only + else _body = m; } else if(_rawPayload[@"aps"][@"alert"]) { id a = message[@"aps"][@"alert"]; @@ -138,6 +141,11 @@ - (id)initWithRawMessage:(NSDictionary*)message { @implementation OSNotification @synthesize payload = _payload, shown = _shown, silentNotification = _silentNotification, displayType = _displayType; + +#if XC8_AVAILABLE +@synthesize mutableContent = _mutableContent; +#endif + - (id)initWithPayload:(OSNotificationPayload *)payload displayType:(OSNotificationDisplayType)displayType { self = [super init]; if (self) { @@ -147,6 +155,10 @@ - (id)initWithPayload:(OSNotificationPayload *)payload displayType:(OSNotificati _silentNotification = [OneSignalHelper isRemoteSilentNotification:payload.rawPayload]; + #if XC8_AVAILABLE + _mutableContent = payload.rawPayload[@"aps"][@"mutable-content"] && [payload.rawPayload[@"aps"][@"mutable-content"] isEqual: @YES]; + #endif + _shown = true; BOOL isActive = [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; @@ -227,11 +239,15 @@ @implementation OneSignalHelper OSHandleNotificationReceivedBlock handleNotificationReceived; OSHandleNotificationActionBlock handleNotificationAction; +//Passed to the OnFocus to make sure dismissed when coming back into app ++(OneSignalWebView*)webVC { + return webVC; +} + (BOOL) isRemoteSilentNotification:(NSDictionary*)msg { //no alert, sound, or badge payload - if(msg[@"badge"] || msg[@"aps"][@"badge"] || msg[@"m"] || msg[@"o"] || msg[@"s"] || msg[@"title"] || msg[@"sound"] || msg[@"aps"][@"sound"] || msg[@"aps"][@"alert"] || msg[@"os_data"][@"buttons"]) + if(msg[@"badge"] || msg[@"aps"][@"badge"] || msg[@"m"] || msg[@"o"] || msg[@"s"] || (msg[@"title"] && [msg[@"title"] length] > 0) || msg[@"sound"] || msg[@"aps"][@"sound"] || msg[@"aps"][@"alert"] || msg[@"os_data"][@"buttons"]) return false; return true; } @@ -395,10 +411,6 @@ + (UILocalNotification*)prepareUILocalNotification:(NSDictionary*)data :(NSDicti return notification; } -+ (id)currentNotificationCenter { - return [NSClassFromString(@"UNUserNotificationCenter") performSelector:@selector(currentNotificationCenter)]; -} - //Shared instance as OneSignal is delegate of UNUserNotificationCenterDelegate and CLLocationManagerDelegate static OneSignal* singleInstance = nil; +(OneSignal*) sharedInstance { @@ -411,24 +423,26 @@ +(OneSignal*) sharedInstance { return singleInstance; } -+ (void)registerAsUNNotificationCenterDelegate { - - if(!NSClassFromString(@"UNUserNotificationCenter")) return; - [[self currentNotificationCenter] setValue:[self sharedInstance] forKey:@"delegate"]; - ++ (BOOL)isiOS10Plus { + return [[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0 ; } -+ (void)addnotificationRequest:(NSDictionary *)data :(NSDictionary *)userInfo { - if(!NSClassFromString(@"UNUserNotificationCenter")) return; - - id notificationRequest = [OneSignalHelper prepareUNNotificationRequest:data :userInfo]; - ++(NSString*)randomStringWithLength:(int)length { - [[OneSignalHelper currentNotificationCenter] performSelector:@selector(addNotificationRequest:withCompletionHandler:) withObject:notificationRequest withObject:^(NSError * _Nullable error) {}]; + const NSString * letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + NSMutableString *randomString = [[NSMutableString alloc] initWithCapacity:length]; + for(int i = 0; i < length; i++) { + uint32_t ln = (uint32_t)[letters length]; + uint32_t rand = arc4random_uniform(ln); + [randomString appendFormat:@"%C", [letters characterAtIndex:rand]]; + } + return randomString; } +#if XC8_AVAILABLE + + (void)requestAuthorization { - [[OneSignalHelper currentNotificationCenter] performSelector:@selector(requestAuthorizationWithOptions:completionHandler:) withObject:@7 withObject:^(BOOL granted, NSError * _Nullable error) {}]; + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:7 completionHandler:^(BOOL granted, NSError * _Nullable error) {}]; } + (void)conformsToUNProtocol { @@ -437,65 +451,11 @@ + (void)conformsToUNProtocol { } } -//Synchroneously downloads a media -//On success returns bundle resource name, otherwise returns nil -+(NSString*) downloadMediaAndSaveInBundle:(NSString*) url { - - NSArray* supportedExtensions = @[@"aiff", @"wav", @"mp3", @"mp4", @"jpg", @"jpeg", @"png", @"gif", @"mpeg", @"mpg", @"avi", @"m4a", @"m4v"]; - NSArray* components = [url componentsSeparatedByString:@"."]; - - //URL is not to a file - if ([components count] < 2) return NULL; - NSString * extension = [components lastObject]; - - //Unrecognized extention - if(![supportedExtensions containsObject:extension]) return NULL; - - NSURL * URL = [NSURL URLWithString:url]; - NSData * data = [NSData dataWithContentsOfURL:URL]; - NSString *name = [[self randomStringWithLength:10] stringByAppendingString:[NSString stringWithFormat:@".%@", extension]]; - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString* filePath = [paths[0] stringByAppendingPathComponent:name]; - NSError* error; - [data writeToFile:filePath options:NSDataWritingAtomic error:&error]; - NSArray * cachedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"CACHED_MEDIA"]; - NSMutableArray* appendedCache; - if (cachedFiles) { - appendedCache = [[NSMutableArray alloc] initWithArray:cachedFiles]; - [appendedCache addObject:name]; - } - else appendedCache = [[NSMutableArray alloc] initWithObjects:name, nil]; - - [[NSUserDefaults standardUserDefaults] setObject:appendedCache forKey:@"CACHED_MEDIA"]; - [[NSUserDefaults standardUserDefaults] synchronize]; - return name; -} - -+(void)clearCachedMedia { ++ (void)registerAsUNNotificationCenterDelegate { - NSArray * cachedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"CACHED_MEDIA"]; - if(cachedFiles) { - - NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - for (NSString* file in cachedFiles) { - NSString* filePath = [paths[0] stringByAppendingPathComponent:file]; - NSError* error; - [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - } - [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"CACHED_MEDIA"]; - } -} - -+(NSString*)randomStringWithLength:(int)length { + if(!NSClassFromString(@"UNUserNotificationCenter")) return; + [UNUserNotificationCenter currentNotificationCenter].delegate = [self sharedInstance]; - const NSString * letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - NSMutableString *randomString = [[NSMutableString alloc] initWithCapacity:length]; - for(int i = 0; i < length; i++) { - uint32_t ln = (uint32_t)[letters length]; - uint32_t rand = arc4random_uniform(ln); - [randomString appendFormat:@"%C", [letters characterAtIndex:rand]]; - } - return randomString; } + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInfo { @@ -506,27 +466,42 @@ + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInf for( NSDictionary* button in data[@"o"]) { NSString* title = button[@"n"] != NULL ? button[@"n"] : @""; NSString* buttonID = button[@"i"] != NULL ? button[@"i"] : title; - id action = [NSClassFromString(@"UNNotificationAction") performSelector2:@selector(actionWithIdentifier:title:options:) withObjects:@[buttonID, title, @4]]; + UNNotificationAction* action = [UNNotificationAction actionWithIdentifier:buttonID title:title options:UNNotificationActionOptionForeground]; [actionArray addObject:action]; } if ([actionArray count] == 2) actionArray = (NSMutableArray*)[[actionArray reverseObjectEnumerator] allObjects]; - id category = [[NSClassFromString(@"UNNotificationCategory") class] performSelector2:@selector(categoryWithIdentifier:actions:intentIdentifiers:options:) withObjects:@[@"__dynamic__", actionArray, @[], @1]]; + id category = [UNNotificationCategory categoryWithIdentifier:@"__dynamic__" actions:actionArray intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction]; NSSet* set = [[NSSet alloc] initWithArray:@[category]]; - [[self currentNotificationCenter] performSelector:@selector(setNotificationCategories:) withObject:set]; + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:set]; id content = [[NSClassFromString(@"UNMutableNotificationContent") alloc] init]; [content setValue:@"__dynamic__" forKey:@"categoryIdentifier"]; - if(data[@"m"][@"title"]) - [content setValue:data[@"m"][@"title"] forKey:@"title"]; + if(data[@"m"]) { + if([data[@"m"] isKindOfClass:[NSDictionary class]]) { + if(data[@"m"][@"title"]) + [content setValue:data[@"m"][@"title"] forKey:@"title"]; + if(data[@"m"][@"body"]) + [content setValue:data[@"m"][@"body"] forKey:@"body"]; + if(data[@"m"][@"subtitle"]) + [content setValue:data[@"m"][@"subtitle"] forKey:@"subtitle"]; + } + else [content setValue:data[@"m"] forKey:@"body"]; + } - if(data[@"m"][@"body"]) - [content setValue:data[@"m"][@"body"] forKey:@"body"]; + else if(data[@"aps"][@"alert"]) { + if([data[@"aps"][@"alert"] isKindOfClass:[NSDictionary class]]) { + [content setValue:data[@"aps"][@"alert"][@"title"] forKey:@"title"]; + [content setValue:data[@"aps"][@"alert"][@"body"] forKey:@"body"]; + [content setValue:data[@"aps"][@"alert"][@"subtitle"] forKey:@"subtitle"]; + } + else [content setValue:data[@"aps"][@"alert"] forKey:@"body"]; + } [content setValue:userInfo forKey:@"userInfo"]; @@ -542,11 +517,10 @@ + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInf [content setValue:data[@"b"] forKey:@"badge"]; //Check if media attached - //!! TEMP : Until Server implements Media Dict, use additional data dict as key val media NSMutableArray *attachments = [NSMutableArray new]; - NSDictionary * att = userInfo[@"custom"][@"at"]; - if(!attachments) - attachments = userInfo[@"os_data"][@"at"]; + NSDictionary * att = userInfo[@"at"]; + if(!att && userInfo[@"os_data"][@"buttons"]) + att = userInfo[@"os_data"][@"buttons"][@"at"]; for(id key in att) { NSString * URI = [att valueForKey:key]; @@ -559,7 +533,8 @@ + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInf NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString*filePath = [paths[0] stringByAppendingPathComponent:name]; NSURL * url = [NSURL fileURLWithPath:filePath]; - id attachment = [NSClassFromString(@"UNNotificationAttachment") performSelector2:@selector(attachmentWithIdentifier:URL:options:error:) withObjects:@[key, url, @0]]; + NSError * error; + id attachment = [UNNotificationAttachment attachmentWithIdentifier:key URL:url options:0 error:&error]; if (attachment) [attachments addObject:attachment]; } @@ -574,22 +549,78 @@ + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInf NSURL * url = [[NSBundle mainBundle] URLForResource:name withExtension:extension]; if (url) { NSError *error; - - id attachment = [NSClassFromString(@"UNNotificationAttachment") performSelector2:@selector(attachmentWithIdentifier:URL:options:error:) withObjects:@[key, url, @0, error]]; + id attachment = [UNNotificationAttachment attachmentWithIdentifier:key URL:url options:0 error:&error]; if (attachment) [attachments addObject:attachment]; } } } - [content setValue:[[NSArray alloc] initWithArray:attachments] forKey:@"attachments"]; + [content setValue:attachments forKey:@"attachments"]; + + UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.25 repeats:NO]; + + return [UNNotificationRequest requestWithIdentifier:@"__dynamic__"content:content trigger:trigger]; +} + ++ (void)addnotificationRequest:(NSDictionary *)data :(NSDictionary *)userInfo { + if(!NSClassFromString(@"UNUserNotificationCenter")) return; + + id notificationRequest = [OneSignalHelper prepareUNNotificationRequest:data :userInfo]; + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {}]; +} + +//Synchroneously downloads a media +//On success returns bundle resource name, otherwise returns nil ++(NSString*) downloadMediaAndSaveInBundle:(NSString*) url { + + NSArray* supportedExtensions = @[@"aiff", @"wav", @"mp3", @"mp4", @"jpg", @"jpeg", @"png", @"gif", @"mpeg", @"mpg", @"avi", @"m4a", @"m4v"]; + NSArray* components = [url componentsSeparatedByString:@"."]; + + //URL is not to a file + if ([components count] < 2) return NULL; + NSString * extension = [components lastObject]; + + //Unrecognized extention + if(![supportedExtensions containsObject:extension]) return NULL; + NSURL * URL = [NSURL URLWithString:url]; + NSData * data = [NSData dataWithContentsOfURL:URL]; + NSString *name = [[self randomStringWithLength:10] stringByAppendingString:[NSString stringWithFormat:@".%@", extension]]; + NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString* filePath = [paths[0] stringByAppendingPathComponent:name]; + NSError* error; + [data writeToFile:filePath options:NSDataWritingAtomic error:&error]; + NSArray * cachedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"CACHED_MEDIA"]; + NSMutableArray* appendedCache; + if (cachedFiles) { + appendedCache = [[NSMutableArray alloc] initWithArray:cachedFiles]; + [appendedCache addObject:name]; + } + else appendedCache = [[NSMutableArray alloc] initWithObjects:name, nil]; - id trigger = [NSClassFromString(@"UNTimeIntervalNotificationTrigger") performSelector2:@selector(triggerWithTimeInterval:repeats:) withObjects: @[@0.25, [NSNumber numberWithBool:NO]]]; + [[NSUserDefaults standardUserDefaults] setObject:appendedCache forKey:@"CACHED_MEDIA"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + return name; +} + ++(void)clearCachedMedia { - return [NSClassFromString(@"UNNotificationRequest") performSelector2:@selector(requestWithIdentifier:content:trigger:) withObjects: @[@"__dynamic__", content, trigger]]; + NSArray * cachedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"CACHED_MEDIA"]; + if(cachedFiles) { + + NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + for (NSString* file in cachedFiles) { + NSString* filePath = [paths[0] stringByAppendingPathComponent:file]; + NSError* error; + [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; + } + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"CACHED_MEDIA"]; + } } +#endif + + (BOOL)verifyURL:(NSString *)urlString { if (urlString) { NSURL* url = [NSURL URLWithString:urlString]; @@ -597,7 +628,6 @@ + (BOOL)verifyURL:(NSString *)urlString { return YES; } - return NO; } diff --git a/iOS_SDK/OneSignal/UIApplication+Swizzling.m b/iOS_SDK/OneSignal/UIApplication+Swizzling.m index c685b4b63..23ac5cae1 100644 --- a/iOS_SDK/OneSignal/UIApplication+Swizzling.m +++ b/iOS_SDK/OneSignal/UIApplication+Swizzling.m @@ -181,7 +181,8 @@ - (void) oneSignalRemoteSilentNotification:(UIApplication*)application UserInfo: if([OneSignal app_id]) { //Call notificationAction if app is active -> not a silent notification but rather user tap on notification - if([UIApplication sharedApplication].applicationState == UIApplicationStateActive) + //Unless iOS 10+ then call remoteSilentNotification instead. + if([UIApplication sharedApplication].applicationState == UIApplicationStateActive && ![OneSignalHelper isiOS10Plus]) [OneSignal notificationOpened:userInfo isActive:YES]; else [OneSignal remoteSilentNotification:application UserInfo:userInfo]; @@ -312,8 +313,10 @@ - (void) setOneSignalDelegate:(id)delegate { /* iOS 10.0: UNUserNotificationCenterDelegate instead of UIApplicationDelegate for methods handling opening app from notification Make sure AppDelegate does not conform to this protocol */ - if([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) + #if XC8_AVAILABLE + if([OneSignalHelper isiOS10Plus]) [OneSignalHelper conformsToUNProtocol]; + #endif [self setOneSignalDelegate:delegate]; } diff --git a/iOS_SDK/OneSignalTracker.m b/iOS_SDK/OneSignalTracker.m index 822ebd813..25333c6a4 100644 --- a/iOS_SDK/OneSignalTracker.m +++ b/iOS_SDK/OneSignalTracker.m @@ -28,6 +28,7 @@ #import "OneSignalTracker.h" #import "OneSignalHelper.h" #import "OneSignalHTTPClient.h" +#import "OneSignalWebView.h" #import "OneSignal.h" @interface OneSignal () @@ -74,6 +75,11 @@ + (void)onFocus:(BOOL)toBackground { [OneSignal sendNotificationTypesUpdate:false]; wasBadgeSet = [OneSignal clearBadgeCount:false]; [OneSignal registerUser]; + + //Make sure webview dismissed if came back from deep link + OneSignalWebView *webVC = [OneSignalHelper webVC]; + if(webVC) + [webVC dismiss:self]; } else {