Skip to content

Commit ba19f72

Browse files
renkelvinryanwilson
authored andcommitted
Add GULSceneDelegateSwizzler (#4524)
* Add GULSceneDelegateSwizzler * Comments updated * Fix build issue on xcode 10.* * Remove empty methods * Format * Fix pr issues * Format * Fix build issue * Fix build issue * Fix build issue * Reuse plist keys for scene delegate swizzler * Add tests for the NSNotificationCenter related code * Fix pr issues * Make proxyOriginalSceneDelegate and isSceneDelegateProxyEnabled callable before ios 13 * Keep interceptors iOS 13+ only * Revert "Make proxyOriginalSceneDelegate and isSceneDelegateProxyEnabled callable before ios 13" This reverts commit 9927c06. * Fix a issue when the header is compiled but the implementation is not This reverts commit a316673. * Format * Reuse [GULAppDelegateSwizzler isAppDelegateProxyEnabled] * Fix build issue * Revert to last green build * Reuse [GULAppDelegateSwizzler isAppDelegateProxyEnabled] and fix other comments * Make proxyOriginalSceneDelegate callable before ios 13 * Fix pr issues
1 parent 5303339 commit ba19f72

File tree

11 files changed

+934
-292
lines changed

11 files changed

+934
-292
lines changed

Firebase/Auth/Source/Auth/FIRAuth.m

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#import <FirebaseCore/FIRLogger.h>
3030
#import <FirebaseCore/FIROptions.h>
3131
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
32+
#import <GoogleUtilities/GULSceneDelegateSwizzler.h>
3233
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
3334

3435
#import "FIREmailPasswordAuthCredential.h"
@@ -384,7 +385,8 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey appName:(NSString *)a
384385
UIApplication *application = [applicationClass sharedApplication];
385386

386387
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
387-
#endif
388+
[GULSceneDelegateSwizzler proxyOriginalSceneDelegate];
389+
#endif // TARGET_OS_IOS
388390

389391
// Continue with the rest of initialization in the work thread.
390392
__weak FIRAuth *weakSelf = self;
@@ -439,7 +441,12 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey appName:(NSString *)a
439441
appCredentialManager:strongSelf->_appCredentialManager];
440442

441443
[GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf];
442-
#endif
444+
#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
445+
if (@available(iOS 13, tvos 13, *)) {
446+
[GULSceneDelegateSwizzler registerSceneDelegateInterceptor:strongSelf];
447+
}
448+
#endif // ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
449+
#endif // TARGET_OS_IOS
443450
});
444451
}
445452
return self;

GoogleUtilities.podspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ other Google CocoaPods. They're not intended for direct public usage.
7676
end
7777

7878
s.subspec 'AppDelegateSwizzler' do |adss|
79-
adss.source_files = 'GoogleUtilities/AppDelegateSwizzler/**/*.[mh]', 'GoogleUtilities/Common/*.h'
80-
adss.public_header_files = 'GoogleUtilities/AppDelegateSwizzler/Private/*.h'
81-
adss.private_header_files = 'GoogleUtilities/AppDelegateSwizzler/Private/*.h'
79+
adss.source_files = 'GoogleUtilities/AppDelegateSwizzler/**/*.[mh]', 'GoogleUtilities/SceneDelegateSwizzler/**/*.[mh]', 'GoogleUtilities/Common/*.h'
80+
adss.public_header_files = 'GoogleUtilities/AppDelegateSwizzler/Private/*.h', 'GoogleUtilities/SceneDelegateSwizzler/Private/*.h'
81+
adss.private_header_files = 'GoogleUtilities/AppDelegateSwizzler/Private/*.h', 'GoogleUtilities/SceneDelegateSwizzler/Private/*.h'
8282
adss.dependency 'GoogleUtilities/Logger'
8383
adss.dependency 'GoogleUtilities/Network'
8484
adss.dependency 'GoogleUtilities/Environment'

GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m

Lines changed: 3 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)(
3131
typedef BOOL (*GULRealOpenURLOptionsIMP)(
3232
id, SEL, GULApplication *, NSURL *, NSDictionary<NSString *, id> *);
3333

34-
#if UISCENE_SUPPORTED
35-
API_AVAILABLE(ios(13.0), tvos(13.0))
36-
typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet<UIOpenURLContext *> *);
37-
#endif // UISCENE_SUPPORTED
38-
3934
#pragma clang diagnostic push
4035
#pragma clang diagnostic ignored "-Wstrict-prototypes"
4136
typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)(
@@ -80,11 +75,12 @@ typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)(
8075
// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change
8176
// we disable App Delegate proxying when either of these two flags are set to NO.
8277

83-
/** Plist key that allows Firebase developers to disable App Delegate Proxying. */
78+
/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */
8479
static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey =
8580
@"FirebaseAppDelegateProxyEnabled";
8681

87-
/** Plist key that allows developers not using Firebase to disable App Delegate Proxying. */
82+
/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying.
83+
*/
8884
static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey =
8985
@"GoogleUtilitiesAppDelegateProxyEnabled";
9086

@@ -294,20 +290,6 @@ + (void)proxyOriginalDelegate {
294290
id<GULApplicationDelegate> originalDelegate =
295291
[GULAppDelegateSwizzler sharedApplication].delegate;
296292
[GULAppDelegateSwizzler proxyAppDelegate:originalDelegate];
297-
298-
#if UISCENE_SUPPORTED
299-
if (@available(iOS 13.0, tvOS 13.0, *)) {
300-
if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) {
301-
return;
302-
} else {
303-
[[NSNotificationCenter defaultCenter]
304-
addObserver:self
305-
selector:@selector(handleSceneWillConnectToNotification:)
306-
name:UISceneWillConnectNotification
307-
object:nil];
308-
}
309-
}
310-
#endif // UISCENE_SUPPORTED
311293
});
312294
}
313295

@@ -703,17 +685,6 @@ + (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector
703685
}];
704686
}
705687

706-
#if UISCENE_SUPPORTED
707-
+ (void)handleSceneWillConnectToNotification:(NSNotification *)notification {
708-
if (@available(iOS 13.0, tvOS 13.0, *)) {
709-
if ([notification.object isKindOfClass:[UIScene class]]) {
710-
UIScene *scene = (UIScene *)notification.object;
711-
[GULAppDelegateSwizzler proxySceneDelegateIfNeeded:scene];
712-
}
713-
}
714-
}
715-
#endif // UISCENE_SUPPORTED
716-
717688
// The methods below are donor methods which are added to the dynamic subclass of the App Delegate.
718689
// They are called within the scope of the real App Delegate so |self| does not refer to the
719690
// GULAppDelegateSwizzler instance but the real App Delegate instance.
@@ -793,36 +764,6 @@ - (BOOL)application:(GULApplication *)application
793764

794765
#endif // TARGET_OS_IOS
795766

796-
#pragma mark - [Donor Methods] UISceneDelegate URL handler
797-
798-
#if UISCENE_SUPPORTED
799-
- (void)scene:(UIScene *)scene
800-
openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) {
801-
if (@available(iOS 13.0, tvOS 13.0, *)) {
802-
SEL methodSelector = @selector(scene:openURLContexts:);
803-
// Call the real implementation if the real App Delegate has any.
804-
NSValue *openURLContextsIMPPointer =
805-
[GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
806-
GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue];
807-
808-
[GULAppDelegateSwizzler
809-
notifyInterceptorsWithMethodSelector:methodSelector
810-
callback:^(id<GULApplicationDelegate> interceptor) {
811-
if ([interceptor
812-
conformsToProtocol:@protocol(UISceneDelegate)]) {
813-
id<UISceneDelegate> sceneInterceptor =
814-
(id<UISceneDelegate>)interceptor;
815-
[sceneInterceptor scene:scene openURLContexts:URLContexts];
816-
}
817-
}];
818-
819-
if (openURLContextsIMP) {
820-
openURLContextsIMP(self, methodSelector, scene, URLContexts);
821-
}
822-
}
823-
}
824-
#endif // UISCENE_SUPPORTED
825-
826767
#pragma mark - [Donor Methods] Network overridden handler methods
827768

828769
#if TARGET_OS_IOS || TARGET_OS_TV
@@ -1065,97 +1006,6 @@ + (void)proxyAppDelegate:(id<GULApplicationDelegate>)appDelegate {
10651006
}
10661007
}
10671008

1068-
#if UISCENE_SUPPORTED
1069-
+ (void)proxySceneDelegateIfNeeded:(UIScene *)scene {
1070-
Class realClass = [scene.delegate class];
1071-
NSString *className = NSStringFromClass(realClass);
1072-
1073-
// Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`)
1074-
// or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before.
1075-
if (className == nil || [className hasPrefix:kGULAppDelegatePrefix]) {
1076-
return;
1077-
}
1078-
1079-
NSString *classNameWithPrefix = [kGULAppDelegatePrefix stringByAppendingString:className];
1080-
NSString *newClassName =
1081-
[NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString];
1082-
1083-
if (NSClassFromString(newClassName)) {
1084-
GULLogError(
1085-
kGULLoggerSwizzler, NO,
1086-
[NSString
1087-
stringWithFormat:@"I-SWZ%06ld",
1088-
(long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidSceneDelegate],
1089-
@"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class"
1090-
@": %@, subclass: %@",
1091-
className, newClassName);
1092-
return;
1093-
}
1094-
1095-
// Register the new class as subclass of the real one. Do not allocate more than the real class
1096-
// size.
1097-
Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0);
1098-
if (sceneDelegateSubClass == Nil) {
1099-
GULLogError(
1100-
kGULLoggerSwizzler, NO,
1101-
[NSString
1102-
stringWithFormat:@"I-SWZ%06ld",
1103-
(long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidSceneDelegate],
1104-
@"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class"
1105-
@": %@, subclass: Nil",
1106-
className);
1107-
return;
1108-
}
1109-
1110-
NSMutableDictionary<NSString *, NSValue *> *realImplementationsBySelector =
1111-
[[NSMutableDictionary alloc] init];
1112-
1113-
// For scene:openURLContexts:
1114-
SEL openURLContextsSEL = @selector(scene:openURLContexts:);
1115-
[self proxyDestinationSelector:openURLContextsSEL
1116-
implementationsFromSourceSelector:openURLContextsSEL
1117-
fromClass:[GULAppDelegateSwizzler class]
1118-
toClass:sceneDelegateSubClass
1119-
realClass:realClass
1120-
storeDestinationImplementationTo:realImplementationsBySelector];
1121-
1122-
// Store original implementations to a fake property of the original delegate.
1123-
objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey,
1124-
[realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1125-
objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass,
1126-
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1127-
1128-
// The subclass size has to be exactly the same size with the original class size. The subclass
1129-
// cannot have more ivars/properties than its superclass since it will cause an offset in memory
1130-
// that can lead to overwriting the isa of an object in the next frame.
1131-
if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) {
1132-
GULLogError(
1133-
kGULLoggerSwizzler, NO,
1134-
[NSString
1135-
stringWithFormat:@"I-SWZ%06ld",
1136-
(long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidSceneDelegate],
1137-
@"Cannot create subclass of Scene Delegate, because the created subclass is not the "
1138-
@"same size. %@",
1139-
className);
1140-
NSAssert(NO, @"Classes must be the same size to swizzle isa");
1141-
return;
1142-
}
1143-
1144-
// Make the newly created class to be the subclass of the real Scene Delegate class.
1145-
objc_registerClassPair(sceneDelegateSubClass);
1146-
if (object_setClass(scene.delegate, sceneDelegateSubClass)) {
1147-
GULLogDebug(
1148-
kGULLoggerSwizzler, NO,
1149-
[NSString
1150-
stringWithFormat:@"I-SWZ%06ld",
1151-
(long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidSceneDelegate],
1152-
@"Successfully created Scene Delegate Proxy automatically. To disable the "
1153-
@"proxy, set the flag %@ to NO (Boolean) in the Info.plist",
1154-
[GULAppDelegateSwizzler correctAppDelegateProxyKey]);
1155-
}
1156-
}
1157-
#endif // UISCENE_SUPPORTED
1158-
11591009
#pragma mark - Methods to print correct debug logs
11601010

11611011
+ (NSString *)correctAppDelegateProxyKey {

GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
1919
#import <GoogleUtilities/GULMutableDictionary.h>
2020

21-
#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
22-
#define UISCENE_SUPPORTED 1
23-
#endif
24-
2521
@class GULApplication;
2622

2723
NS_ASSUME_NONNULL_BEGIN
@@ -54,17 +50,6 @@ NS_ASSUME_NONNULL_BEGIN
5450
*/
5551
+ (id<GULApplicationDelegate>)originalDelegate;
5652

57-
#if UISCENE_SUPPORTED
58-
59-
/** ISA Swizzles the given appDelegate as the original app delegate would be.
60-
*
61-
* @param scene The scene whose delegate needs to be isa swizzled. This should conform to the
62-
* scene delegate protocol.
63-
*/
64-
+ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0));
65-
66-
#endif // UISCENE_SUPPORTED
67-
6853
@end
6954

7055
NS_ASSUME_NONNULL_END

GoogleUtilities/Common/GULLoggerCodes.h

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,38 @@
1818

1919
typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) {
2020
// App Delegate Swizzling.
21-
kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000
22-
kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001
23-
kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002
24-
kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003
25-
kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004
26-
kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005
27-
kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006
28-
kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007
29-
kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008
30-
kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009
31-
kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010
32-
kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011
33-
kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012
34-
kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013
35-
kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014
36-
kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidSceneDelegate = 1015, // I-SWZ001015
21+
kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000
22+
kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001
23+
kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002
24+
kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003
25+
kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004
26+
kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005
27+
kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006
28+
kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007
29+
kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008
30+
kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009
31+
kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010
32+
kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011
33+
kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012
34+
kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013
35+
kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014
36+
37+
// Scene Delegate Swizzling.
38+
kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100
39+
kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101
40+
kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102
41+
kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103
42+
kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104
43+
kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105
44+
kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106
45+
kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107
46+
kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108
47+
kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109
48+
kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110
49+
kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111
50+
kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112
51+
kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113
52+
kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114
3753

3854
// Method Swizzling.
3955
kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000

0 commit comments

Comments
 (0)