Skip to content

Commit 0d4bc5c

Browse files
authored
Merge pull request #1091 from OneSignal/fix/swizzling_not_calling_forwarding_target
[Fix] swizzling not forwarding with apps that use UIApplicationDelegateAdaptor
2 parents 2ca52e7 + 9a6c8c4 commit 0d4bc5c

12 files changed

+523
-127
lines changed

iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@
4747
03389F691FB548A0006537F0 /* OneSignalTrackFirebaseAnalyticsOverrider.m in Sources */ = {isa = PBXBuildFile; fileRef = 03389F681FB548A0006537F0 /* OneSignalTrackFirebaseAnalyticsOverrider.m */; };
4848
03866CBD2378A33B0009C1D8 /* OutcomeIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03866CBC2378A33B0009C1D8 /* OutcomeIntegrationTests.m */; };
4949
03866CC12378A67B0009C1D8 /* RestClientAsserts.m in Sources */ = {isa = PBXBuildFile; fileRef = 03866CC02378A67B0009C1D8 /* RestClientAsserts.m */; };
50-
03CCCC7E2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzingTest.m */; };
50+
03CCCC7E2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzlingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzlingTest.m */; };
5151
03CCCC832835D90F004BF794 /* OneSignalUNUserNotificationCenterHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC812835D90F004BF794 /* OneSignalUNUserNotificationCenterHelper.m */; };
52+
03CCCC852835F291004BF794 /* UIApplicationDelegateSwizzlingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC842835F291004BF794 /* UIApplicationDelegateSwizzlingTests.m */; };
53+
03CCCC8D283624F3004BF794 /* SwizzlingForwarder.h in Headers */ = {isa = PBXBuildFile; fileRef = 03CCCC8B283624F3004BF794 /* SwizzlingForwarder.h */; };
54+
03CCCC8E283624F3004BF794 /* SwizzlingForwarder.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC8C283624F3004BF794 /* SwizzlingForwarder.m */; };
55+
03CCCC8F283624F3004BF794 /* SwizzlingForwarder.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CCCC8C283624F3004BF794 /* SwizzlingForwarder.m */; };
5256
16664C4C25DDB195003B8A14 /* NSTimeZoneOverrider.m in Sources */ = {isa = PBXBuildFile; fileRef = 16664C4B25DDB195003B8A14 /* NSTimeZoneOverrider.m */; };
5357
37E6B2BB19D9CAF300D0C601 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37E6B2BA19D9CAF300D0C601 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
5458
3E464ED71D88ED1F00DCF7E9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37E6B2BA19D9CAF300D0C601 /* UIKit.framework */; };
@@ -350,7 +354,6 @@
350354
CAB4112920852E48005A70D1 /* DelayedConsentInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedConsentInitializationParameters.m */; };
351355
CAB4112A20852E4C005A70D1 /* DelayedConsentInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedConsentInitializationParameters.m */; };
352356
CAB4112B20852E4C005A70D1 /* DelayedConsentInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedConsentInitializationParameters.m */; };
353-
CAB411AE208931EE005A70D1 /* DummyNotificationCenterDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB411AD208931EE005A70D1 /* DummyNotificationCenterDelegate.m */; };
354357
CACBAA96218A6243000ACAA5 /* OSInAppMessageViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = CACBAA8D218A6242000ACAA5 /* OSInAppMessageViewController.h */; };
355358
CACBAA97218A6243000ACAA5 /* OSMessagingController.m in Sources */ = {isa = PBXBuildFile; fileRef = CACBAA8E218A6242000ACAA5 /* OSMessagingController.m */; };
356359
CACBAA98218A6243000ACAA5 /* OSMessagingController.m in Sources */ = {isa = PBXBuildFile; fileRef = CACBAA8E218A6242000ACAA5 /* OSMessagingController.m */; };
@@ -623,9 +626,12 @@
623626
03866CBC2378A33B0009C1D8 /* OutcomeIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OutcomeIntegrationTests.m; sourceTree = "<group>"; };
624627
03866CBF2378A67B0009C1D8 /* RestClientAsserts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RestClientAsserts.h; sourceTree = "<group>"; };
625628
03866CC02378A67B0009C1D8 /* RestClientAsserts.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RestClientAsserts.m; sourceTree = "<group>"; };
626-
03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OneSignalUNUserNotificationCenterSwizzingTest.m; sourceTree = "<group>"; };
629+
03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzlingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OneSignalUNUserNotificationCenterSwizzlingTest.m; sourceTree = "<group>"; };
627630
03CCCC812835D90F004BF794 /* OneSignalUNUserNotificationCenterHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OneSignalUNUserNotificationCenterHelper.m; path = UNNotificationCenter/OneSignalUNUserNotificationCenterHelper.m; sourceTree = "<group>"; };
628631
03CCCC822835D90F004BF794 /* OneSignalUNUserNotificationCenterHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OneSignalUNUserNotificationCenterHelper.h; path = UNNotificationCenter/OneSignalUNUserNotificationCenterHelper.h; sourceTree = "<group>"; };
632+
03CCCC842835F291004BF794 /* UIApplicationDelegateSwizzlingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIApplicationDelegateSwizzlingTests.m; sourceTree = "<group>"; };
633+
03CCCC8B283624F3004BF794 /* SwizzlingForwarder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwizzlingForwarder.h; sourceTree = "<group>"; };
634+
03CCCC8C283624F3004BF794 /* SwizzlingForwarder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwizzlingForwarder.m; sourceTree = "<group>"; };
629635
16664C4B25DDB195003B8A14 /* NSTimeZoneOverrider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSTimeZoneOverrider.m; sourceTree = "<group>"; };
630636
16664C5425DDB2CB003B8A14 /* NSTimeZoneOverrider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSTimeZoneOverrider.h; sourceTree = "<group>"; };
631637
1AF75EAC1E8567FD0097B315 /* NSString+OneSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+OneSignal.h"; sourceTree = "<group>"; };
@@ -886,8 +892,6 @@
886892
CAB269DE21B2038B00F8A43C /* OSInAppMessageBridgeEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OSInAppMessageBridgeEvent.m; sourceTree = "<group>"; };
887893
CAB4112720852E48005A70D1 /* DelayedConsentInitializationParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DelayedConsentInitializationParameters.h; sourceTree = "<group>"; };
888894
CAB4112820852E48005A70D1 /* DelayedConsentInitializationParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DelayedConsentInitializationParameters.m; sourceTree = "<group>"; };
889-
CAB411AC208931EE005A70D1 /* DummyNotificationCenterDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DummyNotificationCenterDelegate.h; sourceTree = "<group>"; };
890-
CAB411AD208931EE005A70D1 /* DummyNotificationCenterDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DummyNotificationCenterDelegate.m; sourceTree = "<group>"; };
891895
CACBAA8D218A6242000ACAA5 /* OSInAppMessageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSInAppMessageViewController.h; sourceTree = "<group>"; };
892896
CACBAA8E218A6242000ACAA5 /* OSMessagingController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OSMessagingController.m; sourceTree = "<group>"; };
893897
CACBAA8F218A6242000ACAA5 /* OSInAppMessagingDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSInAppMessagingDefines.h; sourceTree = "<group>"; };
@@ -1234,7 +1238,8 @@
12341238
7A5A818324899050002E07C8 /* Models */,
12351239
03866CBE2378A5ED0009C1D8 /* Asserts */,
12361240
4529DECD1FA81DE000CEAB1D /* Shadows */,
1237-
03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzingTest.m */,
1241+
03CCCC7D2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzlingTest.m */,
1242+
03CCCC842835F291004BF794 /* UIApplicationDelegateSwizzlingTests.m */,
12381243
CA8E19012193C6B0009DA223 /* InAppMessagingIntegrationTests.m */,
12391244
911E2CBC1E398AB3003112A4 /* UnitTests.m */,
12401245
7AF5174B24FE980400B076BC /* RemoteParamsTests.m */,
@@ -1255,8 +1260,6 @@
12551260
4529DED41FA823B900CEAB1D /* TestHelperFunctions.m */,
12561261
4529DEF41FA8460C00CEAB1D /* UnitTestAppDelegate.h */,
12571262
4529DEF51FA8460C00CEAB1D /* UnitTestAppDelegate.m */,
1258-
CAB411AC208931EE005A70D1 /* DummyNotificationCenterDelegate.h */,
1259-
CAB411AD208931EE005A70D1 /* DummyNotificationCenterDelegate.m */,
12601263
7A123294235DFE3B002B6CE3 /* OutcomeTests.m */,
12611264
7ABAF9E224606E940074DFA0 /* OutcomeV2Tests.m */,
12621265
03866CBC2378A33B0009C1D8 /* OutcomeIntegrationTests.m */,
@@ -1533,6 +1536,8 @@
15331536
7AE28B8725B8ADF400529100 /* OSMacros.h */,
15341537
DE971751274C48B700FC409E /* OSPrivacyConsentController.m */,
15351538
DE971753274C48CF00FC409E /* OSPrivacyConsentController.h */,
1539+
03CCCC8B283624F3004BF794 /* SwizzlingForwarder.h */,
1540+
03CCCC8C283624F3004BF794 /* SwizzlingForwarder.m */,
15361541
);
15371542
path = Source;
15381543
sourceTree = "<group>";
@@ -1845,6 +1850,7 @@
18451850
DE7D182927026F8B002D3A5D /* OneSignalUserDefaults.h in Headers */,
18461851
DE7D187727037A16002D3A5D /* OneSignalCoreHelper.h in Headers */,
18471852
DE7D182F270275FF002D3A5D /* OneSignalTrackFirebaseAnalytics.h in Headers */,
1853+
03CCCC8D283624F3004BF794 /* SwizzlingForwarder.h in Headers */,
18481854
DE7D1875270375FF002D3A5D /* OSReattemptRequest.h in Headers */,
18491855
DE7D1862270374EE002D3A5D /* OSJSONHandling.h in Headers */,
18501856
DE7D1868270374EE002D3A5D /* OneSignalRequest.h in Headers */,
@@ -2403,7 +2409,7 @@
24032409
7ABAF9D22457C3650074DFA0 /* CommonAsserts.m in Sources */,
24042410
03217239238278EB004F0E85 /* DelayedSelectors.m in Sources */,
24052411
CA63AF8720211FF800E340FB /* UnitTestCommonMethods.m in Sources */,
2406-
03CCCC7E2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzingTest.m in Sources */,
2412+
03CCCC7E2835D8CC004BF794 /* OneSignalUNUserNotificationCenterSwizzlingTest.m in Sources */,
24072413
DEAD6F9E270B83A300DE7C67 /* OneSignalExtension.m in Sources */,
24082414
DE7D1863270374EE002D3A5D /* OneSignalClient.m in Sources */,
24092415
DEAD6FA4270B83B300DE7C67 /* OneSignalExtensionRequests.m in Sources */,
@@ -2498,8 +2504,10 @@
24982504
7AAA606A2485D0420004FADE /* OSMigrationController.m in Sources */,
24992505
CACBAA9F218A6243000ACAA5 /* OSInAppMessageView.m in Sources */,
25002506
CA4742E7218B8FF30020DC8C /* OSTriggerController.m in Sources */,
2507+
03CCCC852835F291004BF794 /* UIApplicationDelegateSwizzlingTests.m in Sources */,
25012508
DE9A5DB525D1FD8000FCEC21 /* OSPlayerTags.m in Sources */,
25022509
4529DEEA1FA8360C00CEAB1D /* UIApplicationOverrider.m in Sources */,
2510+
03CCCC8E283624F3004BF794 /* SwizzlingForwarder.m in Sources */,
25032511
7A42744425CDE98E00EE75FC /* OSSMSSubscription.m in Sources */,
25042512
912412281E73342200E41FD7 /* OneSignalMobileProvision.m in Sources */,
25052513
7A93269E25AF4F0300BBEC27 /* OSPendingCallbacks.m in Sources */,
@@ -2529,7 +2537,6 @@
25292537
7ADF891C230DB5BD0054E0D6 /* UnitTestAppDelegate.m in Sources */,
25302538
DE7D18D82703B11B002D3A5D /* OSInAppMessageOutcome.m in Sources */,
25312539
9124123C1E73342200E41FD7 /* OneSignalWebView.m in Sources */,
2532-
CAB411AE208931EE005A70D1 /* DummyNotificationCenterDelegate.m in Sources */,
25332540
4529DEF01FA8433500CEAB1D /* NSLocaleOverrider.m in Sources */,
25342541
A63E9E3B26742B4700EA273E /* LanguageProviderDevice.m in Sources */,
25352542
9129C6BA1E89E59B009CB6A0 /* OSPermission.m in Sources */,
@@ -2546,6 +2553,7 @@
25462553
files = (
25472554
DE7D1874270375FF002D3A5D /* OSReattemptRequest.m in Sources */,
25482555
DE7D183427027A73002D3A5D /* OneSignalLog.m in Sources */,
2556+
03CCCC8F283624F3004BF794 /* SwizzlingForwarder.m in Sources */,
25492557
DE7D183B27027EFC002D3A5D /* NSURL+OneSignal.m in Sources */,
25502558
DE7D186B270374EE002D3A5D /* OneSignalRequest.m in Sources */,
25512559
DE7D182B27027376002D3A5D /* OSNotification.m in Sources */,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#import <Foundation/Foundation.h>
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
/**
6+
Use this in your swizzled methods implementations to ensure your swizzling
7+
does not create side effects.
8+
This is done by checking if there was an existing implementations and also if
9+
the object has a forwardingTargetForSelector: setup.
10+
*/
11+
@interface SwizzlingForwarder : NSObject
12+
/**
13+
Constructor to setup this instance so you can call invokeWithArgs latter
14+
to forward the call onto the correct selector and object so you swizzling does
15+
create any cause side effects.
16+
@param object Your object, normally you should pass in self.
17+
@param yourSelector Your named selector.
18+
@param originalSelector The original selector, the one you would call if
19+
swizzling was out of the picture.
20+
@return Always returns an instance.
21+
*/
22+
-(instancetype)initWithTarget:(id)object
23+
withYourSelector:(SEL)yourSelector
24+
withOriginalSelector:(SEL)originalSelector;
25+
26+
/**
27+
Optionally call before invokeWithArgs to know it will execute anything.
28+
*/
29+
-(BOOL)hasReceiver;
30+
31+
/**
32+
Must call this to call in your swizzled method somewhere to ensure the
33+
original code is still run.
34+
*/
35+
-(void)invokeWithArgs:(NSArray*)args;
36+
@end
37+
38+
NS_ASSUME_NONNULL_END
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#import "SwizzlingForwarder.h"
2+
3+
@implementation SwizzlingForwarder {
4+
id targetObject;
5+
SEL targetSelector;
6+
}
7+
8+
-(instancetype)initWithTarget:(id)object
9+
withYourSelector:(SEL)yourSelector
10+
withOriginalSelector:(SEL)originalSelector {
11+
self = [super init];
12+
13+
// If the class had a pre-existing selector
14+
if ([object respondsToSelector:yourSelector]) {
15+
targetObject = object;
16+
targetSelector = yourSelector;
17+
}
18+
else {
19+
id forwardingTarget = [object forwardingTargetForSelector:originalSelector];
20+
// If there is a forwarding object and ensuring it does have the selector
21+
// The most common case for this is a SwiftUI app with
22+
// @UIApplicationDelegateAdaptor
23+
if (forwardingTarget && [forwardingTarget respondsToSelector:originalSelector]) {
24+
targetObject = forwardingTarget;
25+
targetSelector = originalSelector;
26+
}
27+
}
28+
29+
return self;
30+
}
31+
32+
-(BOOL)hasReceiver {
33+
return targetObject != nil;
34+
}
35+
36+
+(void)callSelector:(SEL)selector
37+
onObject:(id)object
38+
withArgs:(NSArray*)args {
39+
NSMethodSignature *methodSignature = [object methodSignatureForSelector:selector];
40+
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
41+
[invocation setSelector:selector];
42+
[invocation setTarget:object];
43+
for(int i = 0; i < methodSignature.numberOfArguments - 2; i++) {
44+
id argv = [args objectAtIndex:i];
45+
[invocation setArgument:&argv atIndex:i + 2];
46+
}
47+
48+
[invocation invoke];
49+
}
50+
51+
-(void)invokeWithArgs:(NSArray*)args {
52+
if (!targetObject)
53+
return;
54+
55+
[SwizzlingForwarder
56+
callSelector:targetSelector
57+
onObject:targetObject
58+
withArgs:args];
59+
}
60+
@end

iOS_SDK/OneSignalSDK/Source/OneSignalSelectorHelpers.m

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,32 @@ BOOL injectClassSelector(Class newClass, SEL newSel, Class addToClass, SEL makeL
7171

7272
BOOL injectSelector(Class newClass, SEL newSel, Class addToClass, SEL makeLikeSel) {
7373
Method newMeth = class_getInstanceMethod(newClass, newSel);
74-
IMP imp = method_getImplementation(newMeth);
74+
IMP newImp = method_getImplementation(newMeth);
7575

7676
const char* methodTypeEncoding = method_getTypeEncoding(newMeth);
7777
// Keep - class_getInstanceMethod for existing detection.
7878
// class_addMethod will successfuly add if the addToClass was loaded twice into the runtime.
7979
BOOL existing = class_getInstanceMethod(addToClass, makeLikeSel) != NULL;
8080

8181
if (existing) {
82-
class_addMethod(addToClass, newSel, imp, methodTypeEncoding);
83-
newMeth = class_getInstanceMethod(addToClass, newSel);
8482
Method orgMeth = class_getInstanceMethod(addToClass, makeLikeSel);
83+
IMP orgImp = method_getImplementation(orgMeth);
84+
85+
// If implementations are the same then the target selector
86+
// (AKA makeLikeSel) already has the implemenation we want. Without
87+
// this check we would add the implemenation again as newSel. This will
88+
// cause the fowarding logic in our code to think there is an orignal
89+
// implemenation to call, causing an infinite loop.
90+
if (newImp == orgImp) {
91+
return existing;
92+
}
93+
94+
class_addMethod(addToClass, newSel, newImp, methodTypeEncoding);
95+
newMeth = class_getInstanceMethod(addToClass, newSel);
8596
method_exchangeImplementations(orgMeth, newMeth);
8697
}
8798
else
88-
class_addMethod(addToClass, makeLikeSel, imp, methodTypeEncoding);
99+
class_addMethod(addToClass, makeLikeSel, newImp, methodTypeEncoding);
89100

90101
return existing;
91102
}

0 commit comments

Comments
 (0)