Skip to content

Commit

Permalink
Merge pull request #1094 from OneSignal/fix/swizzle_forwarding_deprec…
Browse files Browse the repository at this point in the history
…ated_didReceiveRemoteNotification

[Fix] swizzle of deprecated didReceiveRemoteNotification
  • Loading branch information
jkasten2 committed May 26, 2022
2 parents 2879e22 + 9f09fa5 commit 298ef31
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 18 deletions.
42 changes: 24 additions & 18 deletions iOS_SDK/OneSignalSDK/Source/UIApplicationDelegate+OneSignal.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,6 @@ + (void)sizzlePreiOS10MethodsPhase2 {
if ([OneSignalHelper isIOSVersionGreaterThanOrEqual:@"10.0"])
return;

injectToProperClass(@selector(oneSignalReceivedRemoteNotification:userInfo:),
@selector(application:didReceiveRemoteNotification:), delegateSubclasses, [OneSignalAppDelegate class], delegateClass);

injectToProperClass(@selector(oneSignalLocalNotificationOpened:notification:),
@selector(application:didReceiveLocalNotification:), delegateSubclasses, [OneSignalAppDelegate class], delegateClass);
}
Expand Down Expand Up @@ -184,17 +181,6 @@ - (void)oneSignalDidRegisterUserNotifications:(UIApplication*)application settin
[self oneSignalDidRegisterUserNotifications:application settings:notificationSettings];
}
#pragma clang diagnostic pop
// Fallback method - Normally this would not fire as oneSignalReceiveRemoteNotification below will fire instead. Was needed for iOS 6 support in the past.
- (void)oneSignalReceivedRemoteNotification:(UIApplication*)application userInfo:(NSDictionary*)userInfo {
[OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"oneSignalReceivedRemoteNotification:userInfo:"];

if ([OneSignal appId]) {
[OneSignal notificationReceived:userInfo wasOpened:YES];
}

if ([self respondsToSelector:@selector(oneSignalReceivedRemoteNotification:userInfo:)])
[self oneSignalReceivedRemoteNotification:application userInfo:userInfo];
}

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

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

if (!startedBackgroundJob)
completionHandler(UIBackgroundFetchResultNewData);
}

// Forwards to application:didReceiveRemoteNotification: in the rare case
// that the app happens to use this BUT doesn't use
// UNUserNotificationCenterDelegate OR
// application:didReceiveRemoteNotification:fetchCompletionHandler:
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623117-application?language=objc
+(void)forwardToDepercatedApplication:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
id<UIApplicationDelegate> originalDelegate = UIApplication.sharedApplication.delegate;
if (![originalDelegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)])
return;

// Make sure we don't forward to this depreated selector on cold start
// from a notification open, since iOS itself doesn't call this either
if ([[OneSignal valueForKey:@"coldStartFromTapOnNotification"] boolValue])
return;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[originalDelegate application:application didReceiveRemoteNotification:userInfo];
#pragma clang diagnostic pop
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void) oneSignalLocalNotificationOpened:(UIApplication*)application handleActionWithIdentifier:(NSString*)identifier forLocalNotification:(UILocalNotification*)notification completionHandler:(void(^)()) completionHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ - (void)applicationWillTerminate:(UIApplication *)application
}
@end

@interface AppDelegateForDepercatedDidReceiveRemoteNotificationTest : UIResponder<UIApplicationDelegate> {
@public BOOL selectorCalled;
}
@end

@implementation AppDelegateForDepercatedDidReceiveRemoteNotificationTest
- (instancetype)init {
self = [super init];
selectorCalled = false;
return self;
}
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
{
selectorCalled = true;
}
@end

static id<UIApplicationDelegate> orignalDelegate;

@interface UIApplicationDelegateSwizzlingTest : XCTestCase
Expand Down Expand Up @@ -280,4 +298,30 @@ - (void)testSwizzleExistingSelectors {
)
]);
}

// OneSignal adds application:didReceiveRemoteNotification:fetchCompletionHandler: however
// this causes iOS to no longer call application:didReceiveRemoteNotification: since it sees
// the delegate is using the newer method. To prevent OneSignal from creating side effects we
// need to forward this event to the deprecated application:didReceiveRemoteNotification:.
/** From Apple's documenation:
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler:
method instead of this one whenever possible. If your delegate implements both
methods, the app object calls the
application:didReceiveRemoteNotification:fetchCompletionHandler: method.
*/
- (void)testCallsDepercatedDidReceiveRemoteNotification {
AppDelegateForDepercatedDidReceiveRemoteNotificationTest* myAppDelegate =
[AppDelegateForDepercatedDidReceiveRemoteNotificationTest new];
UIApplication.sharedApplication.delegate = myAppDelegate;
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;

// Apple will call this AppDelegate method
[appDelegate
application:UIApplication.sharedApplication
didReceiveRemoteNotification:@{}
fetchCompletionHandler:^(UIBackgroundFetchResult result){}];
// Ensures the OneSignal swizzling code forwarded it to
// application:didReceiveRemoteNotification:
XCTAssertTrue(myAppDelegate->selectorCalled);
}
@end

0 comments on commit 298ef31

Please sign in to comment.