Skip to content

Commit cc7ae43

Browse files
committed
Fixed iOS 10 crash with action buttons
* Crash would only happen if application:didReceiveRemoteNotification:fetchCompletionHandler: was not present in the app when the app is resumed after a notification with action buttons is received. - This was due to multiple calls to the completionHandler.
1 parent e55e390 commit cc7ae43

File tree

4 files changed

+25
-15
lines changed

4 files changed

+25
-15
lines changed

iOS_SDK/OneSignal/OneSignal.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,9 @@ + (void)didRegisterForRemoteNotifications:(UIApplication*)app deviceToken:(NSDat
10711071
}];
10721072
}
10731073

1074-
+ (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictionary*)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
1074+
+ (BOOL) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictionary*)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
1075+
BOOL startedBackgroundJob = false;
1076+
10751077
// If 'm' present then the notification has action buttons attached to it.
10761078
NSDictionary* data = nil;
10771079

@@ -1082,6 +1084,7 @@ + (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictio
10821084
// Genergate local notification for action button and/or attachments.
10831085
if (data) {
10841086
if (NSClassFromString(@"UNUserNotificationCenter")) {
1087+
startedBackgroundJob = true;
10851088
#if XC8_AVAILABLE
10861089
[OneSignalHelper addnotificationRequest:data userInfo:userInfo completionHandler:completionHandler];
10871090
#endif
@@ -1097,7 +1100,7 @@ + (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictio
10971100
if (application.applicationState == UIApplicationStateActive)
10981101
[OneSignalHelper handleNotificationReceived:OSNotificationDisplayTypeNotification];
10991102
[OneSignal notificationOpened:userInfo isActive:NO];
1100-
return;
1103+
return startedBackgroundJob;
11011104
}
11021105
// content-available notification received in the background - Fire handleNotificationReceived block in app
11031106
else {
@@ -1107,6 +1110,8 @@ + (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictio
11071110
else
11081111
[OneSignalHelper handleNotificationReceived:OSNotificationDisplayTypeNotification];
11091112
}
1113+
1114+
return startedBackgroundJob;
11101115
}
11111116

11121117
// iOS 8-9 - Entry point when OneSignal action button notifiation is displayed or opened.

iOS_SDK/OneSignal/OneSignalHelper.m

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -684,14 +684,12 @@ + (id)prepareUNNotificationRequest:(NSDictionary *)data :(NSDictionary *)userInf
684684
}
685685

686686
+ (void)addnotificationRequest:(NSDictionary *)data userInfo:(NSDictionary *)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
687-
if (!NSClassFromString(@"UNUserNotificationCenter"))
688-
return;
689-
690687
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
691688
[OneSignalHelper beginBackgroundMediaTask];
692689
id notificationRequest = [OneSignalHelper prepareUNNotificationRequest:data :userInfo];
693690
[[NSClassFromString(@"UNUserNotificationCenter") currentNotificationCenter] addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {}];
694-
completionHandler(UIBackgroundFetchResultNewData);
691+
if (completionHandler)
692+
completionHandler(UIBackgroundFetchResultNewData);
695693
[OneSignalHelper endBackgroundMediaTask];
696694
});
697695

iOS_SDK/OneSignal/UIApplicationDelegate+OneSignal.m

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ + (void) handleDidFailRegisterForRemoteNotification:(NSError*)error;
4040
+ (void) updateNotificationTypes:(int)notificationTypes;
4141
+ (NSString*) app_id;
4242
+ (void) notificationOpened:(NSDictionary*)messageDict isActive:(BOOL)isActive;
43-
+ (void) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictionary*)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
43+
+ (BOOL) remoteSilentNotification:(UIApplication*)application UserInfo:(NSDictionary*)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
4444
+ (void) processLocalActionBasedNotification:(UILocalNotification*) notification identifier:(NSString*)identifier;
4545
+ (void) onesignal_Log:(ONE_S_LOG_LEVEL)logLevel message:(NSString*) message;
4646
@end
@@ -180,29 +180,36 @@ - (void)oneSignalReceivedRemoteNotification:(UIApplication*)application userInfo
180180
[self oneSignalReceivedRemoteNotification:application userInfo:userInfo];
181181
}
182182

183-
// User Tap on Notification while app was in background - OR - Notification received (silent or not, foreground or background) on iOS 7+
183+
// Fires when a notication is opened or recieved while the app is in focus.
184+
// - Also fires when the app is in the background and a notificaiton with content-available=1 is received.
185+
// NOTE: completionHandler must only be called once!
186+
// iOS 10 - This crashes the app if it is called twice! Crash will happen when the app is resumed.
187+
// iOS 9 - Does not have this issue.
184188
- (void) oneSignalRemoteSilentNotification:(UIApplication*)application UserInfo:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult)) completionHandler {
185189
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"oneSignalRemoteSilentNotification:UserInfo:fetchCompletionHandler:"];
186190

191+
BOOL callExistingSelector = [self respondsToSelector:@selector(oneSignalRemoteSilentNotification:UserInfo:fetchCompletionHandler:)];
192+
BOOL startedBackgroundJob = false;
193+
187194
if ([OneSignal app_id]) {
188-
// Call notificationAction if app is active -> not a silent notification but rather user tap on notification
189-
// Unless iOS 10+ then call remoteSilentNotification instead.
190195
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive && userInfo[@"aps"][@"alert"])
191196
[OneSignal notificationOpened:userInfo isActive:YES];
192197
else
193-
[OneSignal remoteSilentNotification:application UserInfo:userInfo completionHandler:completionHandler];
198+
startedBackgroundJob = [OneSignal remoteSilentNotification:application UserInfo:userInfo completionHandler:callExistingSelector ? nil : completionHandler];
194199
}
195200

196-
if ([self respondsToSelector:@selector(oneSignalRemoteSilentNotification:UserInfo:fetchCompletionHandler:)]) {
201+
if (callExistingSelector) {
197202
[self oneSignalRemoteSilentNotification:application UserInfo:userInfo fetchCompletionHandler:completionHandler];
198203
return;
199204
}
200205

201206
// Make sure not a cold start from tap on notification (OS doesn't call didReceiveRemoteNotification)
202-
if ([self respondsToSelector:@selector(oneSignalReceivedRemoteNotification:userInfo:)] && ![[OneSignal valueForKey:@"coldStartFromTapOnNotification"] boolValue])
207+
if ([self respondsToSelector:@selector(oneSignalReceivedRemoteNotification:userInfo:)]
208+
&& ![[OneSignal valueForKey:@"coldStartFromTapOnNotification"] boolValue])
203209
[self oneSignalReceivedRemoteNotification:application userInfo:userInfo];
204210

205-
completionHandler(UIBackgroundFetchResultNewData);
211+
if (!startedBackgroundJob)
212+
completionHandler(UIBackgroundFetchResultNewData);
206213
}
207214

208215
- (void) oneSignalLocalNotificationOpened:(UIApplication*)application handleActionWithIdentifier:(NSString*)identifier forLocalNotification:(UILocalNotification*)notification completionHandler:(void(^)()) completionHandler {

iOS_SDK/OneSignal/UNUserNotificationCenter+OneSignal.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ + (void)callLegacyAppDeletegateSelector:(UNNotification *)notification
257257
completionHandler();
258258
}];
259259
// Always trigger selector for open events and for non-content-available receive events.
260-
// content-available seema to be an odd expection to iOS 10's fallback rules for legacy selectors.
260+
// content-available seems to be an odd expection to iOS 10's fallback rules for legacy selectors.
261261
else if ([sharedApp.delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)] &&
262262
(!fromPresentNotification ||
263263
![[notification.request.trigger valueForKey:@"_isContentAvailable"] boolValue])) {

0 commit comments

Comments
 (0)