Skip to content

Commit b6843f3

Browse files
authored
Merge pull request #377 from Countly/fix_safe_area
fix: safe area res
2 parents 8f0e91c + 7d4b827 commit b6843f3

File tree

4 files changed

+108
-46
lines changed

4 files changed

+108
-46
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 25.1.2
2+
* Mitigated an issue where the safe area resolution was not correctly calculated for the content zone on certain iOS devices.
3+
14
## 25.1.1
25
* Mitigated an issue while setting zone timer interval for content.
36

CountlyContentBuilderInternal.m

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ - (void)enterContentZone:(NSArray<NSString *> *)tags {
4848
return;
4949

5050
if(_requestTimer != nil) {
51-
CLY_LOG_I(@"Already entered for content zone, please exit from content zone first to start again");
51+
CLY_LOG_I(@"%s, Already entered for content zone, please exit from content zone first to start again", __FUNCTION__);
5252
return;
5353
}
5454

@@ -97,7 +97,7 @@ - (void)fetchContents {
9797

9898
NSURLSessionTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:[self fetchContentsRequest] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
9999
if (error) {
100-
CLY_LOG_I(@"Fetch content details failed: %@", error);
100+
CLY_LOG_I(@"%s, Fetch content details failed: %@", __FUNCTION__, error);
101101
self->_isRequestQueueLocked = NO;
102102
return;
103103
}
@@ -106,13 +106,13 @@ - (void)fetchContents {
106106
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
107107

108108
if (jsonError) {
109-
CLY_LOG_I(@"Failed to parse JSON: %@", jsonError);
109+
CLY_LOG_I(@"%s, Failed to parse JSON: %@", __FUNCTION__, jsonError);
110110
self->_isRequestQueueLocked = NO;
111111
return;
112112
}
113113

114114
if (!jsonResponse) {
115-
CLY_LOG_I(@"Received empty or null response.");
115+
CLY_LOG_I(@"%s, Received empty or null response.", __FUNCTION__);
116116
self->_isRequestQueueLocked = NO;
117117
return;
118118
}
@@ -152,30 +152,38 @@ - (NSURLRequest *)fetchContentsRequest
152152
}
153153

154154
- (CGSize)getWindowSize {
155-
CGSize size = CGSizeZero;
155+
UIWindow *window = nil;
156156

157-
// Attempt to retrieve the size from the connected scenes (for modern apps)
158157
if (@available(iOS 13.0, *)) {
159-
NSSet<UIScene *> *scenes = [[UIApplication sharedApplication] connectedScenes];
160-
for (UIScene *scene in scenes) {
158+
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
161159
if ([scene isKindOfClass:[UIWindowScene class]]) {
162-
UIWindowScene *windowScene = (UIWindowScene *)scene;
163-
UIWindow *window = windowScene.windows.firstObject;
164-
if (window) {
165-
size = window.bounds.size;
166-
return size; // Return immediately if we find a valid size
167-
}
160+
window = ((UIWindowScene *)scene).windows.firstObject;
161+
break;
168162
}
169163
}
164+
} else {
165+
window = [[UIApplication sharedApplication].delegate window];
170166
}
171167

172-
// Fallback for legacy apps using AppDelegate
173-
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
174-
if ([appDelegate respondsToSelector:@selector(window)]) {
175-
UIWindow *legacyWindow = [appDelegate performSelector:@selector(window)];
176-
if (legacyWindow) {
177-
size = legacyWindow.bounds.size;
178-
}
168+
if (!window) return CGSizeZero;
169+
170+
UIEdgeInsets safeArea = UIEdgeInsetsZero;
171+
CGFloat screenScale = [UIScreen mainScreen].scale;
172+
if (@available(iOS 11.0, *)) {
173+
safeArea = window.safeAreaInsets;
174+
safeArea.left /= screenScale;
175+
safeArea.bottom /= screenScale;
176+
safeArea.right /= screenScale;
177+
}
178+
179+
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
180+
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
181+
182+
CGSize size = CGSizeMake(window.bounds.size.width, window.bounds.size.height);
183+
184+
if(!isLandscape){
185+
size.width -= safeArea.left + safeArea.right;
186+
size.height -= safeArea.top + safeArea.bottom;
179187
}
180188

181189
return size;
@@ -196,6 +204,8 @@ - (NSString *)resolutionJson {
196204
@"landscape": @{@"height": @(lHpW), @"width": @(lWpH)}
197205
};
198206

207+
CLY_LOG_D(@"%s, %@", __FUNCTION__, resolutionDict);
208+
199209
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:resolutionDict options:0 error:nil];
200210
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
201211
}
@@ -205,7 +215,7 @@ - (void)showContentWithHtmlPath:(NSString *)urlString placementCoordinates:(NSDi
205215
NSURL *url = [NSURL URLWithString:urlString];
206216

207217
if (!url || !url.scheme || !url.host) {
208-
NSLog(@"The URL is not valid: %@", urlString);
218+
CLY_LOG_E(@"%s, The URL is not valid: %@", __FUNCTION__, urlString);
209219
return;
210220
}
211221

@@ -227,17 +237,17 @@ - (void)showContentWithHtmlPath:(NSString *)urlString placementCoordinates:(NSDi
227237
CGRect frame = CGRectMake(x, y, width, height);
228238

229239
// Log the URL and the frame
230-
CLY_LOG_I(@"Showing content from URL: %@", url);
231-
CLY_LOG_I(@"Placement frame: %@", NSStringFromCGRect(frame));
240+
CLY_LOG_I(@"%s, Showing content from URL: %@", __FUNCTION__, url);
241+
CLY_LOG_I(@"%s, Placement frame: %@", __FUNCTION__, NSStringFromCGRect(frame));
232242

233243
CountlyWebViewManager* webViewManager = CountlyWebViewManager.new;
234244
[webViewManager createWebViewWithURL:url frame:frame appearBlock:^
235245
{
236-
CLY_LOG_I(@"Webview appeared");
246+
CLY_LOG_I(@"%s, Webview appeared", __FUNCTION__);
237247
[self clearContentState];
238248
} dismissBlock:^
239249
{
240-
CLY_LOG_I(@"Webview dismissed");
250+
CLY_LOG_I(@"%s, Webview dismissed", __FUNCTION__);
241251
self->_minuteTimer = [NSTimer scheduledTimerWithTimeInterval:60.0
242252
target:self
243253
selector:@selector(enterContentZone)

CountlyWebViewManager.m

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ @interface CountlyWebViewManager()
99

1010
@property (nonatomic, strong) PassThroughBackgroundView *backgroundView;
1111
@property (nonatomic, copy) void (^dismissBlock)(void);
12+
@property (nonatomic) BOOL topMarginApplied;
13+
@property (nonatomic) float topMargin;
1214
@end
1315

1416
@implementation CountlyWebViewManager
@@ -19,9 +21,11 @@ - (void)createWebViewWithURL:(NSURL *)url
1921
dismissBlock:(void(^ __nullable)(void))dismissBlock {
2022
self.dismissBlock = dismissBlock;
2123
UIViewController *rootViewController = UIApplication.sharedApplication.keyWindow.rootViewController;
24+
self.topMarginApplied = NO;
25+
self.topMargin = 0;
2226
CGRect backgroundFrame = rootViewController.view.bounds;
23-
2427
self.backgroundView = [[PassThroughBackgroundView alloc] initWithFrame:backgroundFrame];
28+
[self applyTopMargin];
2529
self.backgroundView.backgroundColor = [UIColor clearColor];
2630
[rootViewController.view addSubview:self.backgroundView];
2731

@@ -50,6 +54,41 @@ - (void)createWebViewWithURL:(NSURL *)url
5054
}];
5155
}
5256

57+
- (void)applyTopMargin{
58+
UIViewController *rootViewController = UIApplication.sharedApplication.keyWindow.rootViewController;
59+
60+
CGRect backgroundFrame = rootViewController.view.bounds;
61+
UIWindow *window = nil;
62+
if (@available(iOS 13.0, *)) {
63+
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
64+
if ([scene isKindOfClass:[UIWindowScene class]]) {
65+
window = ((UIWindowScene *)scene).windows.firstObject;
66+
break;
67+
}
68+
}
69+
} else {
70+
window = [[UIApplication sharedApplication].delegate window];
71+
}
72+
73+
if (@available(iOS 11.0, *)) {
74+
UIEdgeInsets safeArea = window.safeAreaInsets;
75+
CGFloat screenScale = [UIScreen mainScreen].scale;
76+
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
77+
if(!UIInterfaceOrientationIsLandscape(orientation) && !self.topMarginApplied){
78+
self.topMarginApplied = YES;
79+
CGRect newFrame = self.backgroundView.frame;
80+
newFrame.origin.y += safeArea.top;
81+
self.backgroundView.frame = newFrame;
82+
self.topMargin = safeArea.top;
83+
} else if(UIInterfaceOrientationIsLandscape(orientation) && self.topMarginApplied){
84+
self.topMarginApplied = NO;
85+
CGRect newFrame = self.backgroundView.frame;
86+
newFrame.origin.y -= self.topMargin;
87+
self.backgroundView.frame = newFrame;
88+
}
89+
}
90+
}
91+
5392
- (void)configureWebView:(WKWebView *)webView {
5493
webView.layer.shadowColor = UIColor.blackColor.CGColor;
5594
webView.layer.shadowOpacity = 0.5;
@@ -274,6 +313,8 @@ - (void)resizeWebViewWithJSONString:(NSString *)jsonString {
274313
CGFloat y = [dimensions[@"y"] floatValue];
275314
CGFloat width = [dimensions[@"w"] floatValue];
276315
CGFloat height = [dimensions[@"h"] floatValue];
316+
317+
[self applyTopMargin];
277318

278319
// Animate the resizing of the web view
279320
[UIView animateWithDuration:0.3 animations:^{
@@ -284,7 +325,7 @@ - (void)resizeWebViewWithJSONString:(NSString *)jsonString {
284325
frame.size.height = height;
285326
self.backgroundView.webView.frame = frame;
286327
} completion:^(BOOL finished) {
287-
CLY_LOG_I(@"Resized web view to width: %f, height: %f", width, height);
328+
CLY_LOG_I(@"%s, Resized web view to width: %f, height: %f", __FUNCTION__, width, height);
288329
}];
289330
}
290331

PassThroughBackgroundView.m

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,38 @@ - (void)adjustWebViewForTraitCollection:(UITraitCollection *)traitCollection {
4949
}
5050

5151
CGSize getWindowSize(void) {
52-
CGSize size = CGSizeZero;
52+
UIWindow *window = nil;
5353

54-
// Attempt to retrieve the size from the connected scenes (for modern apps)
5554
if (@available(iOS 13.0, *)) {
56-
NSSet<UIScene *> *scenes = [[UIApplication sharedApplication] connectedScenes];
57-
for (UIScene *scene in scenes) {
55+
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
5856
if ([scene isKindOfClass:[UIWindowScene class]]) {
59-
UIWindowScene *windowScene = (UIWindowScene *)scene;
60-
UIWindow *window = windowScene.windows.firstObject;
61-
if (window) {
62-
size = window.bounds.size;
63-
return size; // Return immediately if we find a valid size
64-
}
57+
window = ((UIWindowScene *)scene).windows.firstObject;
58+
break;
6559
}
6660
}
61+
} else {
62+
window = [[UIApplication sharedApplication].delegate window];
6763
}
6864

69-
// Fallback for legacy apps using AppDelegate
70-
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
71-
if ([appDelegate respondsToSelector:@selector(window)]) {
72-
UIWindow *legacyWindow = [appDelegate performSelector:@selector(window)];
73-
if (legacyWindow) {
74-
size = legacyWindow.bounds.size;
75-
}
65+
if (!window) return CGSizeZero;
66+
67+
UIEdgeInsets safeArea = UIEdgeInsetsZero;
68+
CGFloat screenScale = [UIScreen mainScreen].scale;
69+
if (@available(iOS 11.0, *)) {
70+
safeArea = window.safeAreaInsets;
71+
safeArea.left /= screenScale;
72+
safeArea.bottom /= screenScale;
73+
safeArea.right /= screenScale;
74+
}
75+
76+
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
77+
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
78+
79+
CGSize size = CGSizeMake(window.bounds.size.width, window.bounds.size.height);
80+
81+
if(!isLandscape){
82+
size.width -= safeArea.left + safeArea.right;
83+
size.height -= safeArea.top + safeArea.bottom;
7684
}
7785

7886
return size;
@@ -96,7 +104,7 @@ - (void)updateWindowSize {
96104
height];
97105
[self.webView evaluateJavaScript:postMessage completionHandler:^(id result, NSError *err) {
98106
if (err != nil) {
99-
CLY_LOG_E(@"[PassThroughBackgroundView] updateWindowSize, %@", err);
107+
CLY_LOG_E(@"%s updateWindowSize, %@", __FUNCTION__, err);
100108
}
101109
}];
102110
}

0 commit comments

Comments
 (0)