diff --git a/CHANGELOG.md b/CHANGELOG.md index e1cbc7b8..cd0790a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## XX.XX.XX * Added support for reporting the app's current theme (light or dark) when presenting feedback widgets, rating widgets, and content, so they are displayed in matching conditions. +* Added visionOS support for feedback widgets (NPS, Survey, and Rating) and content. * Mitigated an issue where feedback widgets could be closed automatically after about a minute even while the user was still interacting with them. diff --git a/Countly.m b/Countly.m index 18c34838..6f349906 100644 --- a/Countly.m +++ b/Countly.m @@ -1311,7 +1311,7 @@ - (BOOL)isAutoViewTrackingActive } #endif #pragma mark - Star Rating -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) - (void)askForStarRating:(void(^)(NSInteger rating))completion { @@ -1604,7 +1604,7 @@ - (void)attemptToSendStoredRequests } #pragma mark - Interfaces -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) - (CountlyContentBuilder *) content { return CountlyContentBuilder.sharedInstance; diff --git a/Countly.podspec b/Countly.podspec index 8820baba..456469de 100644 --- a/Countly.podspec +++ b/Countly.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| core.public_header_files = 'Countly.h', 'CountlyUserDetails.h', 'CountlyConfig.h', 'CountlyFeedbackWidget.h', 'CountlyRCData.h', 'CountlyRemoteConfig.h', 'CountlyViewTracking.h', 'CountlyExperimentInformation.h', 'CountlyAPMConfig.h', 'CountlySDKLimitsConfig.h', 'Resettable.h', "CountlyCrashesConfig.h", "CountlyCrashData.h", "CountlyContentBuilder.h", "CountlyExperimentalConfig.h", "CountlyContentConfig.h", "CountlyFeedbacks.h" core.preserve_path = 'countly_dsym_uploader.sh' core.ios.frameworks = ['Foundation', 'UIKit', 'UserNotifications', 'CoreLocation', 'WebKit', 'CoreTelephony', 'WatchConnectivity'] - core.visionos.frameworks = ['Foundation', 'UIKit', 'UserNotifications', 'CoreLocation'] + core.visionos.frameworks = ['Foundation', 'UIKit', 'UserNotifications', 'CoreLocation', 'WebKit'] end s.subspec 'NotificationService' do |ns| diff --git a/CountlyCommon.h b/CountlyCommon.h index a3ec89ab..94c7e6b2 100644 --- a/CountlyCommon.h +++ b/CountlyCommon.h @@ -39,7 +39,7 @@ #define CLY_LOG_D(fmt, ...) CountlyInternalLog(CLYInternalLogLevelDebug, fmt, ##__VA_ARGS__) #define CLY_LOG_V(fmt, ...) CountlyInternalLog(CLYInternalLogLevelVerbose, fmt, ##__VA_ARGS__) -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #import #endif @@ -117,6 +117,12 @@ void CountlyPrint(NSString *stringToPrint); - (UIViewController *)topViewController; - (void)tryPresentingViewController:(UIViewController *)viewController; - (void)tryPresentingViewController:(UIViewController *)viewController withCompletion:(void (^ __nullable) (void))completion; ++ (UIWindow *)keyWindow; ++ (CGRect)screenBounds; +#endif + +#if (TARGET_OS_IOS || TARGET_OS_VISION) +- (UIInterfaceOrientation)interfaceOrientation; #endif - (void)observeDeviceOrientationChanges; @@ -133,7 +139,7 @@ void CountlyPrint(NSString *stringToPrint); @end -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface CLYInternalViewController : UIViewController @property (nonatomic, weak) WKWebView* webView; @end diff --git a/CountlyCommon.m b/CountlyCommon.m index ea4f19d0..3f039cdd 100644 --- a/CountlyCommon.m +++ b/CountlyCommon.m @@ -281,13 +281,76 @@ - (void)finishBackgroundTask #endif } -#if (TARGET_OS_IOS || TARGET_OS_TV) -- (UIViewController *)topViewController +#if (TARGET_OS_IOS || TARGET_OS_VISION || TARGET_OS_TV) ++ (UIWindow *)keyWindow +{ + if (@available(iOS 13.0, *)) + { + // connectedScenes is an unordered NSSet, so never rely on iteration order: search + // explicitly for the correct window rather than acting on whichever scene comes first. + NSArray *scenes = UIApplication.sharedApplication.connectedScenes.allObjects; + + // 1) The key window of the foreground-active scene (the one the user is interacting with). + for (UIScene *scene in scenes) + { + if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) + { + for (UIWindow *window in ((UIWindowScene *)scene).windows) + if (window.isKeyWindow) + return window; + } + } + + // 2) Any key window across all scenes. + for (UIScene *scene in scenes) + { + if ([scene isKindOfClass:[UIWindowScene class]]) + { + for (UIWindow *window in ((UIWindowScene *)scene).windows) + if (window.isKeyWindow) + return window; + } + } + + // 3) Fall back to the first window of a foreground-active scene. + for (UIScene *scene in scenes) + { + if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) + { + UIWindow *window = ((UIWindowScene *)scene).windows.firstObject; + if (window) + return window; + } + } + } +#if (TARGET_OS_VISION) + return nil; +#else +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return UIApplication.sharedApplication.keyWindow; +#pragma GCC diagnostic pop +#endif +} + ++ (CGRect)screenBounds { + UIWindow *window = [self keyWindow]; + if (window) + return window.bounds; +#if (TARGET_OS_VISION) + return CGRectZero; +#else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - UIViewController* topVC = UIApplication.sharedApplication.keyWindow.rootViewController; + return UIScreen.mainScreen.bounds; #pragma GCC diagnostic pop +#endif +} + +- (UIViewController *)topViewController +{ + UIViewController* topVC = CountlyCommon.keyWindow.rootViewController; while (YES) { @@ -359,7 +422,7 @@ - (NSURLSession *)ImmediateURLSession return [NSURLSession sessionWithConfiguration:immediateConfig]; } -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) - (bool) hasTopNotch:(UIEdgeInsets)safeArea { return safeArea.top >= 44; @@ -367,19 +430,8 @@ - (bool) hasTopNotch:(UIEdgeInsets)safeArea #endif - (CGSize)getWindowSize{ -#if (TARGET_OS_IOS) - UIWindow *window = nil; - - if (@available(iOS 13.0, *)) { - for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { - if ([scene isKindOfClass:[UIWindowScene class]]) { - window = ((UIWindowScene *)scene).windows.firstObject; - break; - } - } - } else { - window = [[UIApplication sharedApplication].delegate window]; - } +#if (TARGET_OS_IOS || TARGET_OS_VISION) + UIWindow *window = [CountlyCommon keyWindow]; if (!window) return CGSizeZero; @@ -402,12 +454,32 @@ - (CGSize)getWindowSize{ #endif } +#if (TARGET_OS_IOS || TARGET_OS_VISION) +- (UIInterfaceOrientation)interfaceOrientation +{ + if (@available(iOS 13.0, *)) + { + UIWindowScene *windowScene = [CountlyCommon keyWindow].windowScene; + if (windowScene) + return windowScene.interfaceOrientation; + } +#if (TARGET_OS_IOS) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return UIApplication.sharedApplication.statusBarOrientation; +#pragma GCC diagnostic pop +#else + return UIInterfaceOrientationPortrait; +#endif +} +#endif + @end #pragma mark - Internal ViewController -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @implementation CLYInternalViewController : UIViewController - (void)viewWillLayoutSubviews @@ -421,10 +493,7 @@ - (void)viewWillLayoutSubviews UIEdgeInsets insets = UIEdgeInsetsZero; if (@available(iOS 11.0, *)) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - insets = UIApplication.sharedApplication.keyWindow.safeAreaInsets; - #pragma GCC diagnostic pop + insets = CountlyCommon.keyWindow.safeAreaInsets; } self.webView.navigationDelegate = self; @@ -530,10 +599,7 @@ - (void)positionToTopRight:(BOOL)shouldConsiderStatusBar { if (@available(iOS 11.0, *)) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - CGFloat top = UIApplication.sharedApplication.keyWindow.safeAreaInsets.top; -#pragma GCC diagnostic pop + CGFloat top = CountlyCommon.keyWindow.safeAreaInsets.top; if (top) { diff --git a/CountlyConsentManager.m b/CountlyConsentManager.m index ef9ca76c..44515f2e 100644 --- a/CountlyConsentManager.m +++ b/CountlyConsentManager.m @@ -444,7 +444,7 @@ - (void)setConsentForFeedback:(BOOL)consentForFeedback { _consentForFeedback = consentForFeedback; -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) if (consentForFeedback) { CLY_LOG_D(@"Consent for Feedback is given."); @@ -499,7 +499,7 @@ - (void)setConsentForContent:(BOOL)consentForContent else { CLY_LOG_D(@"Consent for Content is cancelled."); -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) [CountlyContentBuilderInternal.sharedInstance exitContentZone]; #endif } diff --git a/CountlyContentBuilder.h b/CountlyContentBuilder.h index 7b1c9934..c9a11bc8 100644 --- a/CountlyContentBuilder.h +++ b/CountlyContentBuilder.h @@ -6,12 +6,12 @@ #import -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif NS_ASSUME_NONNULL_BEGIN @interface CountlyContentBuilder: NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance; /** diff --git a/CountlyContentBuilder.m b/CountlyContentBuilder.m index 007766e1..2799f16f 100644 --- a/CountlyContentBuilder.m +++ b/CountlyContentBuilder.m @@ -9,7 +9,7 @@ #import "CountlyCommon.h" @implementation CountlyContentBuilder -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance { if (!CountlyCommon.sharedInstance.hasStarted) diff --git a/CountlyContentBuilderInternal.h b/CountlyContentBuilderInternal.h index 8314d2b6..ba63b9c3 100644 --- a/CountlyContentBuilderInternal.h +++ b/CountlyContentBuilderInternal.h @@ -5,13 +5,13 @@ // Please visit www.count.ly for more information. #import -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN @interface CountlyContentBuilderInternal: NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @property (nonatomic, strong) NSArray *currentTags; @property (nonatomic, assign) NSTimeInterval zoneTimerInterval; @property (nonatomic) ContentCallback contentCallback; diff --git a/CountlyContentBuilderInternal.m b/CountlyContentBuilderInternal.m index 3c7bccdb..9f5b1298 100644 --- a/CountlyContentBuilderInternal.m +++ b/CountlyContentBuilderInternal.m @@ -19,7 +19,7 @@ @implementation CountlyContentBuilderInternal { dispatch_queue_t _contentQueue; } -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance { static CountlyContentBuilderInternal *instance = nil; static dispatch_once_t onceToken; @@ -368,7 +368,7 @@ - (NSString *)resolutionJson { //TODO: check why area is not clickable and safearea things CGSize size = [CountlyCommon.sharedInstance getWindowSize]; - UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + UIInterfaceOrientation orientation = [CountlyCommon.sharedInstance interfaceOrientation]; BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation); CGFloat lHpW = isLandscape ? size.height : size.width; @@ -404,7 +404,7 @@ - (void)showContentWithHtmlPath:(NSString *)urlString placementCoordinates:(NSDi dispatch_async(dispatch_get_main_queue(), ^ { // Detect screen orientation - UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + UIInterfaceOrientation orientation = [CountlyCommon.sharedInstance interfaceOrientation]; BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation); // Get the appropriate coordinates based on the orientation diff --git a/CountlyContentConfig.h b/CountlyContentConfig.h index b07f5209..a199078d 100644 --- a/CountlyContentConfig.h +++ b/CountlyContentConfig.h @@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) typedef enum : NSUInteger { COMPLETED, @@ -32,7 +32,7 @@ typedef BOOL (^ContentURLHandler)(NSURL *url); @interface CountlyContentConfig : NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) /** * This is an experimental feature and it can have breaking changes * Register global completion blocks to be executed on content. diff --git a/CountlyContentConfig.m b/CountlyContentConfig.m index 369156a3..c1e8bdc3 100644 --- a/CountlyContentConfig.m +++ b/CountlyContentConfig.m @@ -7,7 +7,7 @@ #import "CountlyCommon.h" @interface CountlyContentConfig () -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @property (nonatomic) ContentCallback contentCallback; @property (nonatomic) NSUInteger zoneTimerInterval; @property (nonatomic) WebViewDisplayOption webViewDisplayOption; @@ -24,7 +24,7 @@ - (instancetype)init { if (self = [super init]) { -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) _contentReloadOnStallTimeoutMs = 1000; // default 1 second #endif } @@ -32,7 +32,7 @@ - (instancetype)init return self; } -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) -(void)setGlobalContentCallback:(ContentCallback) callback { _contentCallback = callback; diff --git a/CountlyFeedbackWidget.h b/CountlyFeedbackWidget.h index 5ae8f0fe..6ead8bfb 100644 --- a/CountlyFeedbackWidget.h +++ b/CountlyFeedbackWidget.h @@ -19,7 +19,7 @@ extern NSString* const kCountlyReservedEventNPS; extern NSString* const kCountlyReservedEventRating; @interface CountlyFeedbackWidget : NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @property (nonatomic, readonly) CLYFeedbackWidgetType type; @property (nonatomic, readonly) NSString* ID; diff --git a/CountlyFeedbackWidget.m b/CountlyFeedbackWidget.m index 428c886a..1cdf31f9 100644 --- a/CountlyFeedbackWidget.m +++ b/CountlyFeedbackWidget.m @@ -6,7 +6,7 @@ #import "CountlyCommon.h" #import "CountlyWebViewManager.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif @@ -21,7 +21,7 @@ NSString* const kCountlyFBKeyClosed = @"closed"; NSString* const kCountlyFBKeyShown = @"shown"; -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface CountlyFeedbackWidget () #else @interface CountlyFeedbackWidget () @@ -33,14 +33,14 @@ @interface CountlyFeedbackWidget () @property (nonatomic) NSArray* tags; @property (nonatomic) NSDictionary* data; @property (nonatomic) WidgetCallback widgetCallback; -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @property (nonatomic) CLYInternalViewController* webVC; #endif @end @implementation CountlyFeedbackWidget -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (CountlyFeedbackWidget *)createWithDictionary:(NSDictionary *)dictionary { diff --git a/CountlyFeedbacks.h b/CountlyFeedbacks.h index 446d1e55..90facfe6 100644 --- a/CountlyFeedbacks.h +++ b/CountlyFeedbacks.h @@ -10,7 +10,7 @@ #import "CountlyFeedbackWidget.h" @interface CountlyFeedbacks: NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance; - (void) presentNPS; diff --git a/CountlyFeedbacks.m b/CountlyFeedbacks.m index 5b566c0d..e440a287 100644 --- a/CountlyFeedbacks.m +++ b/CountlyFeedbacks.m @@ -9,7 +9,7 @@ #import "CountlyCommon.h" @implementation CountlyFeedbacks -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance { if (!CountlyCommon.sharedInstance.hasStarted) diff --git a/CountlyFeedbacksInternal.h b/CountlyFeedbacksInternal.h index 85518ebe..7d6c1c2f 100644 --- a/CountlyFeedbacksInternal.h +++ b/CountlyFeedbacksInternal.h @@ -16,7 +16,7 @@ extern NSString* const kCountlyFBKeyID; extern NSString* const kCountlyReservedEventStarRating; @interface CountlyFeedbacksInternal : NSObject -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) + (instancetype)sharedInstance; - (void)showDialog:(void(^)(NSInteger rating))completion; diff --git a/CountlyFeedbacksInternal.m b/CountlyFeedbacksInternal.m index d804ffb2..d93e46ee 100644 --- a/CountlyFeedbacksInternal.m +++ b/CountlyFeedbacksInternal.m @@ -5,7 +5,7 @@ // Please visit www.count.ly for more information. #import "CountlyCommon.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif @@ -16,7 +16,7 @@ + (CountlyFeedbackWidget *)createWithDictionary:(NSDictionary *)dictionary; @interface CountlyFeedbacksInternal () -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @property (nonatomic) UIAlertController* alertController; @property (nonatomic, copy) void (^ratingCompletion)(NSInteger); #endif @@ -42,7 +42,7 @@ @interface CountlyFeedbacksInternal () const CGFloat kCountlyStarRatingButtonSize = 40.0; @implementation CountlyFeedbacksInternal -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) { UIButton* btn_star[5]; } diff --git a/CountlyOverlayWindow.h b/CountlyOverlayWindow.h index 8f562f04..8ccd87c9 100644 --- a/CountlyOverlayWindow.h +++ b/CountlyOverlayWindow.h @@ -3,14 +3,14 @@ // This code is provided under the MIT License. // // Please visit www.count.ly for more information. -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface CountlyOverlayWindow : UIWindow @end #endif diff --git a/CountlyOverlayWindow.m b/CountlyOverlayWindow.m index 174c2e82..89285e7d 100644 --- a/CountlyOverlayWindow.m +++ b/CountlyOverlayWindow.m @@ -5,8 +5,9 @@ // Please visit www.count.ly for more information. #import "CountlyOverlayWindow.h" #import "CountlyWebViewController.h" +#import "CountlyCommon.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @implementation CountlyOverlayWindow - (instancetype)init { @@ -36,7 +37,7 @@ - (instancetype)init if (!initialized) { - if (self = [super initWithFrame:UIScreen.mainScreen.bounds]) + if (self = [super initWithFrame:CountlyCommon.screenBounds]) { initialized = YES; } diff --git a/CountlyWebViewController.h b/CountlyWebViewController.h index 26b100cb..76b868f4 100644 --- a/CountlyWebViewController.h +++ b/CountlyWebViewController.h @@ -4,14 +4,14 @@ // // Please visit www.count.ly for more information. -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface CountlyWebViewController : UIViewController @property(nonatomic, strong) UIView *contentView; - (void)updatePlacementRespectToSafeAreas; diff --git a/CountlyWebViewController.m b/CountlyWebViewController.m index eb96a9fa..68d97a1f 100644 --- a/CountlyWebViewController.m +++ b/CountlyWebViewController.m @@ -5,10 +5,11 @@ // Please visit www.count.ly for more information. // #import "CountlyWebViewController.h" +#import "CountlyCommon.h" #import "PassThroughBackgroundView.h" #import "TouchDelegatingView.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @implementation CountlyWebViewController { UIStatusBarStyle _cachedStatusBarStyle; @@ -47,27 +48,8 @@ - (UIInterfaceOrientationMask)supportedInterfaceOrientations } - (UIWindow *)getKeyWindow { - if (@available(iOS 13.0, *)) { - for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { - if (![scene isKindOfClass:[UIWindowScene class]]) { - continue; - } - - UIWindowScene *windowScene = (UIWindowScene *)scene; - - if (windowScene.activationState == UISceneActivationStateForegroundActive) { - for (UIWindow *window in windowScene.windows) { - if (window.isKeyWindow) { - return window; - } - } - } - } - } else { - return UIApplication.sharedApplication.keyWindow; - } - - return nil; + // Unified key-window resolution (foreground-active scene, correct across multi-scene apps). + return CountlyCommon.keyWindow; } - (BOOL)shouldAutorotate @@ -81,7 +63,7 @@ - (void)loadView CGRect bounds = keyWindow.rootViewController.view.bounds; if (CGRectIsEmpty(bounds)) { - bounds = UIScreen.mainScreen.bounds; + bounds = CountlyCommon.screenBounds; } self.view = [[TouchDelegatingView alloc] initWithFrame:bounds]; diff --git a/CountlyWebViewManager.h b/CountlyWebViewManager.h index 51a9105b..84b306a5 100644 --- a/CountlyWebViewManager.h +++ b/CountlyWebViewManager.h @@ -4,14 +4,14 @@ // // Please visit www.count.ly for more information. -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #import #endif #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) typedef NS_ENUM(NSUInteger, AnimationType) { AnimationTypeSlideInFromBottom, AnimationTypeSlideInFromTop, diff --git a/CountlyWebViewManager.m b/CountlyWebViewManager.m index 1f867ee0..6b7071c5 100644 --- a/CountlyWebViewManager.m +++ b/CountlyWebViewManager.m @@ -10,7 +10,7 @@ #import "PassThroughBackgroundView.h" #import "CountlyContentBuilderInternal.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) // Critical-resource load retries: how many times to reload the web view before // giving up when a critical (JS/CSS) resource fails to load. A single transient // network hiccup — e.g. a connection stalled under a burst of parallel asset @@ -61,7 +61,7 @@ @interface CountlyWebViewManager () @end @implementation CountlyWebViewManager - #if (TARGET_OS_IOS) + #if (TARGET_OS_IOS || TARGET_OS_VISION) - (void)createWebViewWithURL:(NSURL *)url frame:(CGRect)frame appearBlock:(void(^ __nullable)(void))appearBlock @@ -72,13 +72,12 @@ - (void)createWebViewWithURL:(NSURL *)url self.webViewClosed = NO; self.resourceRetryCount = 0; self.pendingReloadBlock = nil; - // TODO: keyWindow deprecation fix _window = [CountlyOverlayWindow new]; CountlyWebViewController *modal = [CountlyWebViewController new]; modal.modalPresentationStyle = UIModalPresentationOverFullScreen; modal.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; _window.rootViewController = modal; - UIViewController *rootViewController = UIApplication.sharedApplication.keyWindow.rootViewController; + UIViewController *rootViewController = CountlyCommon.keyWindow.rootViewController; modal.modalPresentationCapturesStatusBarAppearance = YES; CGRect backgroundFrame = rootViewController.view.bounds; self.backgroundView = [[PassThroughBackgroundView alloc] initWithFrame:backgroundFrame]; @@ -893,7 +892,7 @@ - (void)resizeWebViewWithJSONString:(NSString *)jsonString { } // Determine the current orientation - UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + UIInterfaceOrientation orientation = [CountlyCommon.sharedInstance interfaceOrientation]; BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation); // Select the appropriate dimensions based on orientation diff --git a/Package.swift b/Package.swift index e2d1c11f..b6649983 100644 --- a/Package.swift +++ b/Package.swift @@ -53,7 +53,7 @@ let package = Package( .linkedFramework("IOKit", .when(platforms: [.macOS])), .linkedFramework("UserNotifications", .when(platforms: [.iOS, .macOS, .visionOS])), .linkedFramework("CoreLocation"), - .linkedFramework("WebKit", .when(platforms: [.iOS])), + .linkedFramework("WebKit", .when(platforms: [.iOS, .visionOS])), .linkedFramework("CoreTelephony", .when(platforms: [.iOS])), ]), .testTarget( diff --git a/PassThroughBackgroundView.h b/PassThroughBackgroundView.h index 6e363dae..002310fc 100644 --- a/PassThroughBackgroundView.h +++ b/PassThroughBackgroundView.h @@ -5,7 +5,7 @@ // Please visit www.count.ly for more information. -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #import #endif @@ -13,7 +13,7 @@ #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface PassThroughBackgroundView : UIView diff --git a/PassThroughBackgroundView.m b/PassThroughBackgroundView.m index d1b9ec49..e6477db7 100644 --- a/PassThroughBackgroundView.m +++ b/PassThroughBackgroundView.m @@ -6,7 +6,7 @@ #import "PassThroughBackgroundView.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @implementation PassThroughBackgroundView @synthesize webView; @@ -14,10 +14,11 @@ @implementation PassThroughBackgroundView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; #if (TARGET_OS_IOS) + // Device-orientation and screen-mode change notifications do not exist on visionOS. [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleScreenChange) name:UIDeviceOrientationDidChangeNotification object:nil]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleScreenChange) name:UIScreenModeDidChangeNotification object:nil]; - [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleScreenChange) name:UIApplicationDidBecomeActiveNotification object:nil]; #endif + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleScreenChange) name:UIApplicationDidBecomeActiveNotification object:nil]; return self; } diff --git a/TouchDelegatingView.h b/TouchDelegatingView.h index 72c09a0e..5c4e5c90 100644 --- a/TouchDelegatingView.h +++ b/TouchDelegatingView.h @@ -3,14 +3,14 @@ // This code is provided under the MIT License. // // Please visit www.count.ly for more information. -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) #import #endif #import "CountlyCommon.h" NS_ASSUME_NONNULL_BEGIN -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @interface TouchDelegatingView : UIView @property(nonatomic, weak) UIView *touchDelegate; @end diff --git a/TouchDelegatingView.m b/TouchDelegatingView.m index 11110eb3..35a67ffe 100644 --- a/TouchDelegatingView.m +++ b/TouchDelegatingView.m @@ -6,7 +6,7 @@ // Copyright © 2026 Countly. All rights reserved. // #import "TouchDelegatingView.h" -#if (TARGET_OS_IOS) +#if (TARGET_OS_IOS || TARGET_OS_VISION) @implementation TouchDelegatingView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event