Skip to content

Commit 298ef31

Browse files
authored
Merge pull request #1094 from OneSignal/fix/swizzle_forwarding_deprecated_didReceiveRemoteNotification
[Fix] swizzle of deprecated didReceiveRemoteNotification
2 parents 2879e22 + 9f09fa5 commit 298ef31

File tree

2 files changed

+68
-18
lines changed

2 files changed

+68
-18
lines changed

iOS_SDK/OneSignalSDK/Source/UIApplicationDelegate+OneSignal.m

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,6 @@ + (void)sizzlePreiOS10MethodsPhase2 {
129129
if ([OneSignalHelper isIOSVersionGreaterThanOrEqual:@"10.0"])
130130
return;
131131

132-
injectToProperClass(@selector(oneSignalReceivedRemoteNotification:userInfo:),
133-
@selector(application:didReceiveRemoteNotification:), delegateSubclasses, [OneSignalAppDelegate class], delegateClass);
134-
135132
injectToProperClass(@selector(oneSignalLocalNotificationOpened:notification:),
136133
@selector(application:didReceiveLocalNotification:), delegateSubclasses, [OneSignalAppDelegate class], delegateClass);
137134
}
@@ -184,17 +181,6 @@ - (void)oneSignalDidRegisterUserNotifications:(UIApplication*)application settin
184181
[self oneSignalDidRegisterUserNotifications:application settings:notificationSettings];
185182
}
186183
#pragma clang diagnostic pop
187-
// Fallback method - Normally this would not fire as oneSignalReceiveRemoteNotification below will fire instead. Was needed for iOS 6 support in the past.
188-
- (void)oneSignalReceivedRemoteNotification:(UIApplication*)application userInfo:(NSDictionary*)userInfo {
189-
[OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"oneSignalReceivedRemoteNotification:userInfo:"];
190-
191-
if ([OneSignal appId]) {
192-
[OneSignal notificationReceived:userInfo wasOpened:YES];
193-
}
194-
195-
if ([self respondsToSelector:@selector(oneSignalReceivedRemoteNotification:userInfo:)])
196-
[self oneSignalReceivedRemoteNotification:application userInfo:userInfo];
197-
}
198184

199185
// Fires when a notication is opened or recieved while the app is in focus.
200186
// - Also fires when the app is in the background and a notificaiton with content-available=1 is received.
@@ -238,15 +224,35 @@ - (void) oneSignalReceiveRemoteNotification:(UIApplication*)application UserInfo
238224
return;
239225
}
240226

241-
// Make sure not a cold start from tap on notification (OS doesn't call didReceiveRemoteNotification)
242-
if ([self respondsToSelector:@selector(oneSignalReceivedRemoteNotification:userInfo:)]
243-
&& ![[OneSignal valueForKey:@"coldStartFromTapOnNotification"] boolValue])
244-
[self oneSignalReceivedRemoteNotification:application userInfo:userInfo];
227+
[OneSignalAppDelegate
228+
forwardToDepercatedApplication:application
229+
didReceiveRemoteNotification:userInfo];
245230

246231
if (!startedBackgroundJob)
247232
completionHandler(UIBackgroundFetchResultNewData);
248233
}
249234

235+
// Forwards to application:didReceiveRemoteNotification: in the rare case
236+
// that the app happens to use this BUT doesn't use
237+
// UNUserNotificationCenterDelegate OR
238+
// application:didReceiveRemoteNotification:fetchCompletionHandler:
239+
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623117-application?language=objc
240+
+(void)forwardToDepercatedApplication:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
241+
id<UIApplicationDelegate> originalDelegate = UIApplication.sharedApplication.delegate;
242+
if (![originalDelegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)])
243+
return;
244+
245+
// Make sure we don't forward to this depreated selector on cold start
246+
// from a notification open, since iOS itself doesn't call this either
247+
if ([[OneSignal valueForKey:@"coldStartFromTapOnNotification"] boolValue])
248+
return;
249+
250+
#pragma clang diagnostic push
251+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
252+
[originalDelegate application:application didReceiveRemoteNotification:userInfo];
253+
#pragma clang diagnostic pop
254+
}
255+
250256
#pragma clang diagnostic push
251257
#pragma clang diagnostic ignored "-Wdeprecated"
252258
- (void) oneSignalLocalNotificationOpened:(UIApplication*)application handleActionWithIdentifier:(NSString*)identifier forLocalNotification:(UILocalNotification*)notification completionHandler:(void(^)()) completionHandler {

iOS_SDK/OneSignalSDK/UnitTests/UIApplicationDelegateSwizzlingTests.m

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ - (void)applicationWillTerminate:(UIApplication *)application
136136
}
137137
@end
138138

139+
@interface AppDelegateForDepercatedDidReceiveRemoteNotificationTest : UIResponder<UIApplicationDelegate> {
140+
@public BOOL selectorCalled;
141+
}
142+
@end
143+
144+
@implementation AppDelegateForDepercatedDidReceiveRemoteNotificationTest
145+
- (instancetype)init {
146+
self = [super init];
147+
selectorCalled = false;
148+
return self;
149+
}
150+
-(void)application:(UIApplication *)application
151+
didReceiveRemoteNotification:(NSDictionary *)userInfo
152+
{
153+
selectorCalled = true;
154+
}
155+
@end
156+
139157
static id<UIApplicationDelegate> orignalDelegate;
140158

141159
@interface UIApplicationDelegateSwizzlingTest : XCTestCase
@@ -280,4 +298,30 @@ - (void)testSwizzleExistingSelectors {
280298
)
281299
]);
282300
}
301+
302+
// OneSignal adds application:didReceiveRemoteNotification:fetchCompletionHandler: however
303+
// this causes iOS to no longer call application:didReceiveRemoteNotification: since it sees
304+
// the delegate is using the newer method. To prevent OneSignal from creating side effects we
305+
// need to forward this event to the deprecated application:didReceiveRemoteNotification:.
306+
/** From Apple's documenation:
307+
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler:
308+
method instead of this one whenever possible. If your delegate implements both
309+
methods, the app object calls the
310+
application:didReceiveRemoteNotification:fetchCompletionHandler: method.
311+
*/
312+
- (void)testCallsDepercatedDidReceiveRemoteNotification {
313+
AppDelegateForDepercatedDidReceiveRemoteNotificationTest* myAppDelegate =
314+
[AppDelegateForDepercatedDidReceiveRemoteNotificationTest new];
315+
UIApplication.sharedApplication.delegate = myAppDelegate;
316+
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
317+
318+
// Apple will call this AppDelegate method
319+
[appDelegate
320+
application:UIApplication.sharedApplication
321+
didReceiveRemoteNotification:@{}
322+
fetchCompletionHandler:^(UIBackgroundFetchResult result){}];
323+
// Ensures the OneSignal swizzling code forwarded it to
324+
// application:didReceiveRemoteNotification:
325+
XCTAssertTrue(myAppDelegate->selectorCalled);
326+
}
283327
@end

0 commit comments

Comments
 (0)