diff --git a/SVProgressHUD.podspec b/SVProgressHUD.podspec index a66c9d81..0e84caa2 100644 --- a/SVProgressHUD.podspec +++ b/SVProgressHUD.podspec @@ -18,13 +18,13 @@ Pod::Spec.new do |s| s.subspec 'Core' do |core| core.source_files = 'SVProgressHUD/*.{h,m}' - core.resources = ['SVProgressHUD/SVProgressHUD.bundle'] + core.resources = ['SVProgressHUD/SVProgressHUD.bundle/**'] core.resource_bundles = {'SVProgressHUD' => ['SVProgressHUD/PrivacyInfo.xcprivacy']} end s.subspec 'AppExtension' do |ext| ext.source_files = 'SVProgressHUD/*.{h,m}' - ext.resources = ['SVProgressHUD/SVProgressHUD.bundle'] + ext.resources = ['SVProgressHUD/SVProgressHUD.bundle/**'] ext.resource_bundles = {'AppExtension' => ['SVProgressHUD/PrivacyInfo.xcprivacy']} ext.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SV_APP_EXTENSIONS=1' } end diff --git a/SVProgressHUD/SVProgressHUD.m b/SVProgressHUD/SVProgressHUD.m index 21af1eae..ae89d230 100644 --- a/SVProgressHUD/SVProgressHUD.m +++ b/SVProgressHUD/SVProgressHUD.m @@ -78,54 +78,77 @@ + (SVProgressHUD*)sharedView { #if !defined(SV_APP_EXTENSIONS) + (UIWindow *)mainWindow { - UIApplication *sharedApplication = [UIApplication sharedApplication]; - __block UIWindow *mainWindow = nil; if (@available(iOS 13.0, tvOS 13.0, *)) { - [sharedApplication.connectedScenes enumerateObjectsUsingBlock:^(UIScene *scene, BOOL *stop1) { - if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:UIWindowScene.class]) { - UIWindowScene *windowScene = (UIWindowScene *)scene; - [windowScene.windows enumerateObjectsUsingBlock:^(UIWindow *window, NSUInteger idx, BOOL *stop2) { + // First pass: find key window in active foreground app scenes + for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { + if (![scene isKindOfClass:[UIWindowScene class]]) { + continue; + } + + UIWindowScene *windowScene = (UIWindowScene *)scene; + if (windowScene.activationState == UISceneActivationStateForegroundActive && + [windowScene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { + for (UIWindow *window in windowScene.windows) { if (window.isKeyWindow && !window.isHidden) { - mainWindow = window; - *stop1 = YES; - *stop2 = YES; + return window; } - }]; + } + if (windowScene.windows.count > 0) { + return windowScene.windows.firstObject; + } } - }]; - } - if (!mainWindow) { - [sharedApplication.windows enumerateObjectsUsingBlock:^(UIWindow *window, NSUInteger idx, BOOL *stop) { + } + + // Second pass: any app scene regardless of activation state + for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { + if (![scene isKindOfClass:[UIWindowScene class]]) { + continue; + } + + UIWindowScene *windowScene = (UIWindowScene *)scene; + if (![windowScene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { + continue; + } + + for (UIWindow *window in windowScene.windows) { + if (window.isKeyWindow && !window.isHidden) { + return window; + } + } + if (windowScene.windows.count > 0) { + return windowScene.windows.firstObject; + } + } + + // Third pass: check all application windows + for (UIWindow *window in [UIApplication sharedApplication].windows) { if (window.isKeyWindow && !window.isHidden) { - mainWindow = window; - *stop = YES; + return window; } - }]; - } - // delegate window - if (!mainWindow) { - if (@available(iOS 13.0, tvOS 13.0, *)) { - [sharedApplication.connectedScenes enumerateObjectsUsingBlock:^(UIScene *scene, BOOL *stop) { - if ([scene isKindOfClass:UIWindowScene.class] && [scene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { - UIWindowScene *windowScene = (UIWindowScene *)scene; - if ([windowScene.delegate conformsToProtocol:@protocol(UIWindowSceneDelegate)]) { - id sceneDelegate = (id)windowScene.delegate; - if (sceneDelegate.window) { - mainWindow = sceneDelegate.window; - *stop = YES; - } + } + + // Fourth pass: delegate windows + for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]] && + [scene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + if ([windowScene.delegate conformsToProtocol:@protocol(UIWindowSceneDelegate)]) { + id sceneDelegate = (id)windowScene.delegate; + if (sceneDelegate.window) { + return sceneDelegate.window; } } - }]; - } - if (!mainWindow) { - id appDelegate = sharedApplication.delegate; - if ([appDelegate respondsToSelector:@selector(window)]) { - mainWindow = appDelegate.window; } } } - return mainWindow; + + // Pre-iOS 13 fallback / last resort + id appDelegate = [UIApplication sharedApplication].delegate; + if ([appDelegate respondsToSelector:@selector(window)] && appDelegate.window) { + return appDelegate.window; + } + + return nil; } #endif @@ -135,11 +158,12 @@ + (NSBundle *)imageBundle { #else NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]]; #endif - NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"]; + /*NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"]; if (!url) { return nil; } - return [NSBundle bundleWithURL:url]; + return [NSBundle bundleWithURL:url];*/ + return bundle; } #pragma mark - Setters @@ -554,9 +578,8 @@ - (void)updateMotionEffectForXMotionEffectType:(UIInterpolatingMotionEffectType) - (void)updateViewHierarchy { // Add the overlay to the application window if necessary - if(!self.controlView.superview) { - // Check if containerView is set and still in the view hierarchy - if(self.containerView && self.containerView.window){ + if (!self.controlView.superview) { + if (self.containerView && self.containerView.window) { [self.containerView addSubview:self.controlView]; } else { #if !defined(SV_APP_EXTENSIONS) @@ -566,7 +589,7 @@ - (void)updateViewHierarchy { } #else // If SVProgressHUD is used inside an app extension add it to the given view - if(self.viewForExtension) { + if (self.viewForExtension) { [self.viewForExtension addSubview:self.controlView]; } #endif @@ -766,7 +789,7 @@ - (void)controlViewDidReceiveTouchEvent:(id)sender forEvent:(UIEvent*)event { - (void)showProgress:(float)progress status:(NSString*)status { __weak SVProgressHUD *weakSelf = self; - void (^block)(void) = ^{ + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ __strong SVProgressHUD *strongSelf = weakSelf; if(strongSelf){ if(strongSelf.fadeOutTimer) { @@ -839,12 +862,7 @@ - (void)showProgress:(float)progress status:(NSString*)status { [strongSelf.hapticGenerator prepare]; #endif } - }; - if ([NSThread isMainThread]) { - block(); - } else { - [[NSOperationQueue mainQueue] addOperationWithBlock:block]; - } + }]; } - (void)showImage:(UIImage*)image status:(NSString*)status duration:(NSTimeInterval)duration { @@ -1367,7 +1385,7 @@ - (CGFloat)visibleKeyboardHeight { if (@available(iOS 13.0, tvOS 13.0, *)) { for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { // only handle UIWindowScene - if ([scene isKindOfClass:[UIWindowScene class]]) { + if ([scene isKindOfClass:[UIWindowScene class]] && [scene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { for (UIWindow *testWindow in ((UIWindowScene *)scene).windows) { if(![testWindow.class isEqual:UIWindow.class]) { keyboardWindow = testWindow; @@ -1379,6 +1397,22 @@ - (CGFloat)visibleKeyboardHeight { break; } } + if (keyboardWindow == nil) { + for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { + // only handle UIWindowScene + if ([scene isKindOfClass:[UIWindowScene class]]) { + for (UIWindow *testWindow in ((UIWindowScene *)scene).windows) { + if(![testWindow.class isEqual:UIWindow.class]) { + keyboardWindow = testWindow; + break; + } + } + } + if (keyboardWindow != nil) { + break; + } + } + } } // Fallback to the old method if not iOS 13+ or if no window is found in a multi-scene environment @@ -1419,15 +1453,13 @@ - (UIWindow *)frontWindow { // For iOS 13 and later, we first find the active scene. if (@available(iOS 13.0, tvOS 13.0, *)) { for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { - if (scene.activationState == UISceneActivationStateForegroundActive) { - if ([scene isKindOfClass:[UIWindowScene class]]) { - UIWindowScene *windowScene = (UIWindowScene *)scene; - for (UIWindow *window in windowScene.windows) { - // The isKeyWindow property is often a reliable way to find the main window, - // but we also check other properties for robustness. - if (window.isKeyWindow && window.alpha > 0) { - return window; - } + if (scene.activationState == UISceneActivationStateForegroundActive && + [scene isKindOfClass:[UIWindowScene class]] && + [scene.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + for (UIWindow *window in windowScene.windows) { + if (window.isKeyWindow && window.alpha > 0) { + return window; } } }