-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Handle UISceneDelegate changes in Auth #4380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
b05d8d1
4550c9c
28202c3
0ed18bd
61213c8
0582329
4a525c7
66055a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,11 @@ typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)( | |
| typedef BOOL (*GULRealOpenURLOptionsIMP)( | ||
| id, SEL, GULApplication *, NSURL *, NSDictionary<NSString *, id> *); | ||
|
|
||
| #if UISCENE_SUPPORTED | ||
| API_AVAILABLE(ios(13.0), tvos(13.0)) | ||
| typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet<UIOpenURLContext *> *); | ||
| #endif // UISCENE_SUPPORTED | ||
|
|
||
| #pragma clang diagnostic push | ||
| #pragma clang diagnostic ignored "-Wstrict-prototypes" | ||
| typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)( | ||
|
|
@@ -289,6 +294,20 @@ + (void)proxyOriginalDelegate { | |
| id<GULApplicationDelegate> originalDelegate = | ||
| [GULAppDelegateSwizzler sharedApplication].delegate; | ||
| [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate]; | ||
|
|
||
| #if UISCENE_SUPPORTED | ||
| if (@available(iOS 13.0, tvOS 13.0, *)) { | ||
| if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) { | ||
| return; | ||
| } else { | ||
| [[NSNotificationCenter defaultCenter] | ||
| addObserver:self | ||
| selector:@selector(handleSceneWillConnectToNotification:) | ||
| name:UISceneWillConnectNotification | ||
| object:nil]; | ||
| } | ||
| } | ||
| #endif // UISCENE_SUPPORTED | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -682,6 +701,15 @@ + (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector | |
| }]; | ||
| } | ||
|
|
||
| #if UISCENE_SUPPORTED | ||
| + (void)handleSceneWillConnectToNotification:(NSNotification *)notification { | ||
| if (@available(iOS 13.0, tvOS 13.0, *)) { | ||
| UIScene *scene = (UIScene *)notification.object; | ||
| [GULAppDelegateSwizzler proxySceneDelegate:scene]; | ||
| } | ||
| } | ||
| #endif // UISCENE_SUPPORTED | ||
|
|
||
| // The methods below are donor methods which are added to the dynamic subclass of the App Delegate. | ||
| // They are called within the scope of the real App Delegate so |self| does not refer to the | ||
| // GULAppDelegateSwizzler instance but the real App Delegate instance. | ||
|
|
@@ -761,6 +789,40 @@ - (BOOL)application:(GULApplication *)application | |
|
|
||
| #endif // TARGET_OS_IOS | ||
|
|
||
| #pragma mark - [Donor Methods] UISceneDelegate URL handler | ||
|
|
||
| #if UISCENE_SUPPORTED | ||
| - (void)scene:(UIScene *)scene | ||
| openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) { | ||
| if (@available(iOS 13.0, tvOS 13.0, *)) { | ||
| SEL methodSelector = @selector(scene:openURLContexts:); | ||
| // Call the real implementation if the real App Delegate has any. | ||
| NSValue *openURLContextsIMPPointer = | ||
| [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; | ||
| GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue]; | ||
|
|
||
| // This is needed for the library to be warning free on iOS versions < 9. | ||
renkelvin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #pragma clang diagnostic push | ||
| #pragma clang diagnostic ignored "-Wunguarded-availability" | ||
| [GULAppDelegateSwizzler | ||
| notifyInterceptorsWithMethodSelector:methodSelector | ||
| callback:^(id<GULApplicationDelegate> interceptor) { | ||
| if ([interceptor | ||
| conformsToProtocol:@protocol(UISceneDelegate)]) { | ||
| id<UISceneDelegate> sceneInterceptor = | ||
| (id<UISceneDelegate>)interceptor; | ||
| [sceneInterceptor scene:scene openURLContexts:URLContexts]; | ||
| } | ||
| }]; | ||
| #pragma clang diagnostic pop | ||
|
|
||
| if (openURLContextsIMP) { | ||
| openURLContextsIMP(self, methodSelector, scene, URLContexts); | ||
| } | ||
| } | ||
| } | ||
| #endif // UISCENE_SUPPORTED | ||
|
|
||
| #pragma mark - [Donor Methods] Network overridden handler methods | ||
|
|
||
| #if TARGET_OS_IOS || TARGET_OS_TV | ||
|
|
@@ -1002,6 +1064,89 @@ + (void)proxyAppDelegate:(id<GULApplicationDelegate>)appDelegate { | |
| } | ||
| } | ||
|
|
||
| #if UISCENE_SUPPORTED | ||
| + (void)proxySceneDelegate:(UIScene *)scene { | ||
| Class realClass = [scene.delegate class]; | ||
|
|
||
| // Skip proxying if the class has a prefix of kGULAppDelegatePrefix, which means it has been | ||
| // proxied before. | ||
| if ([NSStringFromClass(realClass) hasPrefix:kGULAppDelegatePrefix]) { | ||
renkelvin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return; | ||
| } | ||
|
|
||
| NSString *classNameWithPrefix = | ||
| [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)]; | ||
| NSString *newClassName = | ||
| [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; | ||
|
|
||
| if (NSClassFromString(newClassName)) { | ||
| GULLogError(kGULLoggerSwizzler, NO, | ||
| [NSString stringWithFormat:@"I-SWZ%06ld", | ||
| (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005], | ||
|
||
| @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " | ||
| @"%@, subclass: %@", | ||
| NSStringFromClass(realClass), newClassName); | ||
| return; | ||
| } | ||
|
|
||
| // Register the new class as subclass of the real one. Do not allocate more than the real class | ||
| // size. | ||
| Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); | ||
| if (sceneDelegateSubClass == Nil) { | ||
| GULLogError(kGULLoggerSwizzler, NO, | ||
| [NSString stringWithFormat:@"I-SWZ%06ld", | ||
| (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006], | ||
| @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " | ||
| @"%@, subclass: Nil", | ||
| NSStringFromClass(realClass)); | ||
| return; | ||
| } | ||
|
|
||
| NSMutableDictionary<NSString *, NSValue *> *realImplementationsBySelector = | ||
| [[NSMutableDictionary alloc] init]; | ||
|
|
||
| // For scene:openURLContexts: | ||
| SEL openURLContextsSEL = @selector(scene:openURLContexts:); | ||
| [self proxyDestinationSelector:openURLContextsSEL | ||
| implementationsFromSourceSelector:openURLContextsSEL | ||
| fromClass:[GULAppDelegateSwizzler class] | ||
| toClass:sceneDelegateSubClass | ||
| realClass:realClass | ||
| storeDestinationImplementationTo:realImplementationsBySelector]; | ||
|
|
||
| // Store original implementations to a fake property of the original delegate. | ||
| objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: It think readability of the class may be slightly improved if we create a "set" counterpart for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like using |
||
| [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); | ||
| objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass, | ||
| OBJC_ASSOCIATION_RETAIN_NONATOMIC); | ||
|
|
||
| // The subclass size has to be exactly the same size with the original class size. The subclass | ||
| // cannot have more ivars/properties than its superclass since it will cause an offset in memory | ||
| // that can lead to overwriting the isa of an object in the next frame. | ||
| if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) { | ||
| GULLogError(kGULLoggerSwizzler, NO, | ||
| [NSString stringWithFormat:@"I-SWZ%06ld", | ||
| (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007], | ||
| @"Cannot create subclass of App Delegate, because the created subclass is not the " | ||
| @"same size. %@", | ||
| NSStringFromClass(realClass)); | ||
| NSAssert(NO, @"Classes must be the same size to swizzle isa"); | ||
| return; | ||
| } | ||
|
|
||
| // Make the newly created class to be the subclass of the real App Delegate class. | ||
renkelvin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| objc_registerClassPair(sceneDelegateSubClass); | ||
| if (object_setClass(scene.delegate, sceneDelegateSubClass)) { | ||
| GULLogDebug(kGULLoggerSwizzler, NO, | ||
| [NSString stringWithFormat:@"I-SWZ%06ld", | ||
| (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008], | ||
| @"Successfully created App Delegate Proxy automatically. To disable the " | ||
| @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", | ||
| [GULAppDelegateSwizzler correctAppDelegateProxyKey]); | ||
| } | ||
| } | ||
| #endif // UISCENE_SUPPORTED | ||
|
|
||
| #pragma mark - Methods to print correct debug logs | ||
|
|
||
| + (NSString *)correctAppDelegateProxyKey { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.