Skip to content

Commit 4c43395

Browse files
authored
Feat: Add option to disable swizzling (#1650)
* feat: enhance manual integration support and swizzling control - Added APIs for manual notification handling and lifecycle observation when swizzling is disabled. - Introduced a new constant for controlling swizzling via Info.plist. * dev app: setup to test swizzle disabled * return early from manual APIs if swizzling is enabled * address PR feedback * thread safety * rename a method for clarity * remove ios 9 and 10 checks minimum is ios 12
1 parent 336fc6e commit 4c43395

12 files changed

Lines changed: 259 additions & 93 deletions

File tree

iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929
// This project exisits to make testing OneSignal SDK changes.
3030

3131
#import <UIKit/UIKit.h>
32+
#import <UserNotifications/UserNotifications.h>
3233
#import <OneSignalFramework/OneSignalFramework.h>
3334

34-
@interface AppDelegate : UIResponder <UIApplicationDelegate, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSPushSubscriptionObserver, OSNotificationLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener, OSUserStateObserver, OSLogListener>
35+
@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSPushSubscriptionObserver, OSNotificationLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener, OSUserStateObserver, OSLogListener>
3536

3637
@property (strong, nonatomic) UIWindow *window;
3738

iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDiction
5959
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
6060

6161
// [FIRApp configure];
62+
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
6263

6364
NSLog(@"Bundle URL: %@", [[NSBundle mainBundle] bundleURL]);
6465
// Uncomment to test LogListener
@@ -197,17 +198,66 @@ - (void)applicationDidBecomeActive:(UIApplication *)application {
197198
- (void)applicationWillTerminate:(UIApplication *)application {
198199
}
199200

200-
// Remote
201+
- (void)onLogEvent:(OneSignalLogEvent * _Nonnull)event {
202+
NSLog(@"Dev App onLogEvent: %@", event.entry);
203+
}
204+
205+
#pragma mark - Manual Integration APIs (for use when swizzling is disabled)
206+
207+
// Forward the APNs device token to OneSignal so it can register the device for push
201208
- (void)application:(UIApplication *)application
202-
didReceiveRemoteNotification:(NSDictionary *)userInfo
203-
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
204-
205-
NSLog(@"application:didReceiveRemoteNotification:fetchCompletionHandler: %@", userInfo);
206-
completionHandler(UIBackgroundFetchResultNoData);
209+
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
210+
NSLog(@"Dev App application:didRegisterForRemoteNotificationsWithDeviceToken %@", deviceToken);
211+
[OneSignal.Notifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
207212
}
208213

209-
- (void)onLogEvent:(OneSignalLogEvent * _Nonnull)event {
210-
NSLog(@"Dev App onLogEvent: %@", event.entry);
214+
// Forward APNs registration failures so OneSignal can log and retry appropriately
215+
- (void)application:(UIApplication *)application
216+
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
217+
NSLog(@"Dev App application:didFailToRegisterForRemoteNotificationsWithError %@", error);
218+
[OneSignal.Notifications didFailToRegisterForRemoteNotificationsWithError:error];
219+
}
220+
221+
// Forward background / silent notifications for content-available processing
222+
- (void)application:(UIApplication *)application
223+
didReceiveRemoteNotification:(NSDictionary *)userInfo
224+
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
225+
NSLog(@"Dev App application:didReceiveRemoteNotification %@", userInfo);
226+
[OneSignal.Notifications didReceiveRemoteNotification:userInfo
227+
completionHandler:completionHandler];
228+
}
229+
230+
// Forward foreground notifications so the SDK can invoke onWillDisplayNotification listeners
231+
// and determine whether to show a banner. Completion returns nil for IAM previews.
232+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
233+
willPresentNotification:(UNNotification *)notification
234+
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
235+
NSLog(@"Dev App userNotificationCenter:willPresentNotification %@", notification);
236+
[OneSignal.Notifications
237+
willPresentNotificationWithPayload:notification.request.content.userInfo
238+
completion:^(OSNotification *notif) {
239+
if (notif) {
240+
if (@available(iOS 14.0, *)) {
241+
completionHandler(UNNotificationPresentationOptionBanner |
242+
UNNotificationPresentationOptionList |
243+
UNNotificationPresentationOptionSound);
244+
} else {
245+
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
246+
}
247+
} else {
248+
completionHandler(UNNotificationPresentationOptionNone);
249+
}
250+
}];
251+
}
252+
253+
// Forward notification tap / action so the SDK can fire onClickNotification listeners
254+
// and handle deep links and action buttons
255+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
256+
didReceiveNotificationResponse:(UNNotificationResponse *)response
257+
withCompletionHandler:(void (^)(void))completionHandler {
258+
NSLog(@"Dev App userNotificationCenter:didReceiveNotificationResponse %@", response);
259+
[OneSignal.Notifications didReceiveNotificationResponse:response];
260+
completionHandler();
211261
}
212262

213263
@end

iOS_SDK/OneSignalDevApp/OneSignalDevApp/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@
8282
<string>UIInterfaceOrientationLandscapeLeft</string>
8383
<string>UIInterfaceOrientationLandscapeRight</string>
8484
</array>
85+
<key>OneSignal_disable_swizzling</key>
86+
<true/>
8587
</dict>
8688
</plist>

iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCommonDefines.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@
155155
#define GDPR_CONSENT_GRANTED @"GDPR_CONSENT_GRANTED"
156156
#define ONESIGNAL_REQUIRE_PRIVACY_CONSENT @"OneSignal_require_privacy_consent"
157157

158+
// Swizzling
159+
#define ONESIGNAL_DISABLE_SWIZZLING @"OneSignal_disable_swizzling"
160+
158161
// Badge handling
159162
#define ONESIGNAL_DISABLE_BADGE_CLEARING @"OneSignal_disable_badge_clearing"
160163
#define ONESIGNAL_APP_GROUP_NAME_KEY @"OneSignal_app_groups_key"

iOS_SDK/OneSignalSDK/OneSignalNotifications/Categories/UIApplicationDelegate+OneSignalNotifications.m

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ + (BOOL)swizzledClassInHeirarchy:(Class)delegateClass {
111111
return false;
112112
}
113113

114-
- (void)oneSignalDidRegisterForRemoteNotifications:(UIApplication*)app deviceToken:(NSData*)inDeviceToken {
114+
- (void)oneSignalDidRegisterForRemoteNotifications:(UIApplication*)app deviceToken:(NSData*)deviceToken {
115115
[OneSignalNotificationsAppDelegate traceCall:@"oneSignalDidRegisterForRemoteNotifications:deviceToken:"];
116116

117-
[OSNotificationsManager didRegisterForRemoteNotifications:app deviceToken:inDeviceToken];
117+
[OSNotificationsManager processRegisteredDeviceToken:deviceToken];
118118

119119
SwizzlingForwarder *forwarder = [[SwizzlingForwarder alloc]
120120
initWithTarget:self
@@ -125,14 +125,14 @@ - (void)oneSignalDidRegisterForRemoteNotifications:(UIApplication*)app deviceTok
125125
application:didRegisterForRemoteNotificationsWithDeviceToken:
126126
)
127127
];
128-
[forwarder invokeWithArgs:@[app, inDeviceToken]];
128+
[forwarder invokeWithArgs:@[app, deviceToken]];
129129
}
130130

131131
- (void)oneSignalDidFailRegisterForRemoteNotification:(UIApplication*)app error:(NSError*)err {
132132
[OneSignalNotificationsAppDelegate traceCall:@"oneSignalDidFailRegisterForRemoteNotification:error:"];
133133

134134
if ([OneSignalConfigManager getAppId])
135-
[OSNotificationsManager handleDidFailRegisterForRemoteNotification:err];
135+
[OSNotificationsManager processFailedRemoteNotificationsRegistration:err];
136136

137137
SwizzlingForwarder *forwarder = [[SwizzlingForwarder alloc]
138138
initWithTarget:self
@@ -169,18 +169,10 @@ - (void) oneSignalReceiveRemoteNotification:(UIApplication*)application UserInfo
169169
let appState = [UIApplication sharedApplication].applicationState;
170170
let isVisibleNotification = userInfo[@"aps"][@"alert"] != nil;
171171

172-
// iOS 9 - Notification was tapped on
173-
// https://medium.com/posts-from-emmerge/ios-push-notification-background-fetch-demystified-7090358bb66e
174-
// - NOTE: We do not have the extra logic for the notifiation center or double tap home button cases
175-
// of "inactive" on notification received the link above describes.
176-
// Omiting that complex logic as iOS 9 usage stats are very low (12/11/2020) and these are rare cases.
177-
if ([OSDeviceUtils isIOSVersionLessThan:@"10.0"] && appState == UIApplicationStateInactive && isVisibleNotification) {
178-
[OSNotificationsManager notificationReceived:userInfo wasOpened:YES];
179-
}
180-
else if (appState == UIApplicationStateActive && isVisibleNotification)
172+
if (appState == UIApplicationStateActive && isVisibleNotification)
181173
[OSNotificationsManager notificationReceived:userInfo wasOpened:NO];
182174
else
183-
startedBackgroundJob = [OSNotificationsManager receiveRemoteNotification:application UserInfo:userInfo completionHandler:forwarder.hasReceiver ? nil : completionHandler];
175+
startedBackgroundJob = [OSNotificationsManager processReceivedRemoteNotification:userInfo completionHandler:forwarder.hasReceiver ? nil : completionHandler];
184176
}
185177

186178
if (forwarder.hasReceiver) {

iOS_SDK/OneSignalSDK/OneSignalNotifications/Categories/UNUserNotificationCenter+OneSignalNotifications.m

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ - (void)onesignalUserNotificationCenter:(UNUserNotificationCenter *)center
293293

294294
[OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: Fired! %@", notification.request.content.body]];
295295

296-
[OSNotificationsManager handleWillPresentNotificationInForegroundWithPayload:notification.request.content.userInfo withCompletion:^(OSNotification *responseNotif) {
296+
[OSNotificationsManager processWillPresentNotificationWithPayload:notification.request.content.userInfo completion:^(OSNotification *responseNotif) {
297297
UNNotificationPresentationOptions displayType = responseNotif != nil ? (UNNotificationPresentationOptions)7 : (UNNotificationPresentationOptions)0;
298298
finishProcessingNotification(notification, center, displayType, completionHandler, self);
299299
}];
@@ -377,19 +377,7 @@ + (BOOL)isDismissEvent:(UNNotificationResponse *)response {
377377
}
378378

379379
+ (void)processiOS10Open:(UNNotificationResponse*)response {
380-
if (![OneSignalConfigManager getAppId])
381-
return;
382-
383-
if ([OneSignalNotificationsUNUserNotificationCenter isDismissEvent:response])
384-
return;
385-
386-
if (![OneSignalCoreHelper isOneSignalPayload:response.notification.request.content.userInfo])
387-
return;
388-
389-
let userInfo = [OneSignalCoreHelper formatApsPayloadIntoStandard:response.notification.request.content.userInfo
390-
identifier:response.actionIdentifier];
391-
392-
[OSNotificationsManager notificationReceived:userInfo wasOpened:YES];
380+
[OSNotificationsManager processNotificationResponse:response];
393381
}
394382

395383
// Calls depercated pre-iOS 10 selector if one is set on the AppDelegate.

iOS_SDK/OneSignalSDK/OneSignalNotifications/OSNotificationsManager.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ NS_SWIFT_NAME(onClick(event:));
6565
+ (void)addPermissionObserver:(NSObject<OSNotificationPermissionObserver>*_Nonnull)observer NS_REFINED_FOR_SWIFT;
6666
+ (void)removePermissionObserver:(NSObject<OSNotificationPermissionObserver>*_Nonnull)observer NS_REFINED_FOR_SWIFT;
6767
+ (void)clearAll;
68+
// Manual integration APIs (for use when swizzling is disabled via Info.plist)
69+
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *_Nonnull)deviceToken
70+
NS_SWIFT_NAME(didRegisterForRemoteNotifications(deviceToken:));
71+
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *_Nonnull)error
72+
NS_SWIFT_NAME(didFailToRegisterForRemoteNotifications(error:));
73+
+ (void)didReceiveRemoteNotification:(NSDictionary *_Nonnull)userInfo completionHandler:(void (^_Nonnull)(UIBackgroundFetchResult))completionHandler
74+
NS_SWIFT_NAME(didReceiveRemoteNotification(userInfo:completionHandler:));
75+
+ (void)willPresentNotificationWithPayload:(NSDictionary *_Nonnull)payload completion:(OSNotificationDisplayResponse _Nonnull)completion
76+
NS_SWIFT_NAME(willPresentNotification(payload:completion:));
77+
+ (void)didReceiveNotificationResponse:(UNNotificationResponse *_Nonnull)response
78+
NS_SWIFT_NAME(didReceiveNotificationResponse(_:));
79+
+ (void)setBadgeCount:(NSInteger)badgeCount;
6880
@end
6981

7082

@@ -82,7 +94,7 @@ NS_SWIFT_NAME(onClick(event:));
8294
@property (class, weak, nonatomic, nullable) id<OneSignalNotificationsDelegate> delegate;
8395

8496
+ (Class<OSNotifications> _Nonnull)Notifications;
85-
+ (void)start;
97+
+ (void)startSwizzling;
8698
+ (void)setColdStartFromTapOnNotification:(BOOL)coldStartFromTapOnNotification;
8799
+ (BOOL)getColdStartFromTapOnNotification;
88100

@@ -116,10 +128,17 @@ NS_SWIFT_NAME(onClick(event:));
116128
+ (void)handleNotificationActionWithUrl:(NSString* _Nullable)url actionID:(NSString* _Nonnull)actionID;
117129
+ (void)clearBadgeCount:(BOOL)fromNotifOpened fromClearAll:(BOOL)fromClearAll;
118130

119-
+ (BOOL)receiveRemoteNotification:(UIApplication* _Nonnull)application UserInfo:(NSDictionary* _Nonnull)userInfo completionHandler:(void (^_Nonnull)(UIBackgroundFetchResult))completionHandler;
120131
+ (void)notificationReceived:(NSDictionary* _Nonnull)messageDict wasOpened:(BOOL)opened;
121-
+ (void)handleWillPresentNotificationInForegroundWithPayload:(NSDictionary * _Nonnull)payload withCompletion:(OSNotificationDisplayResponse _Nonnull)completion;
122-
+ (void)didRegisterForRemoteNotifications:(UIApplication *_Nonnull)app deviceToken:(NSData *_Nonnull)inDeviceToken;
123-
+ (void)handleDidFailRegisterForRemoteNotification:(NSError*_Nonnull)err;
124132
+ (void)checkProvisionalAuthorizationStatus;
133+
+ (void)registerLifecycleObserver;
134+
+ (BOOL)isSwizzlingDisabled;
135+
136+
// Internal entry points called by swizzled delegate paths
137+
// These bypass the swizzling-active guard so the SDK doesn't block its own calls
138+
+ (void)processRegisteredDeviceToken:(NSData *_Nonnull)deviceToken;
139+
+ (void)processFailedRemoteNotificationsRegistration:(NSError *_Nonnull)error;
140+
+ (BOOL)processReceivedRemoteNotification:(NSDictionary *_Nonnull)userInfo completionHandler:(void (^_Nonnull)(UIBackgroundFetchResult))completionHandler;
141+
+ (void)processWillPresentNotificationWithPayload:(NSDictionary *_Nonnull)payload completion:(OSNotificationDisplayResponse _Nonnull)completion;
142+
+ (void)processNotificationResponse:(UNNotificationResponse *_Nonnull)response;
143+
125144
@end

0 commit comments

Comments
 (0)