Repository navigation
fix: [SDK-5654] lay out IAMs for iPhone Duo and resizable scenes - #1789
fadi-george wants to merge 20 commits into
Conversation
Size the IAM window and WebView from the window scene bounds instead of UIScreen bounds, which report a single panel on foldables. Compute banner heights from the view's safe area insets so relayouts don't collapse them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unfolded (resizable) scenes don't re-query prefersStatusBarHidden when the IAM window becomes key, so full-bleed IAMs kept the status bar over the close button until a rotation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This reverts commit 3766b06.
abdulraqeeb33
left a comment
There was a problem hiding this comment.
The layout rework reads right: scene bounds over UIScreen, the constraint teardown fixes a real per-rotation leak, and the verticalGuide is equivalent to the old anchors for every placement. Two things block, both outside what the simulator matrix can show.
- The iOS 27.1 reserved-region branch compiles out of the release binaries (inline on the
#if). sceneViewfalls back silently to the banner window (inline).
Not inline because the line isn't in the diff: OSInAppMessageView.m:155 never calls completion on a getPageMetaData() error, so a fold whose JS call fails leaves messageView.hidden = true under a live alert-level window. Pre-existing, but fold/unfold is the hot path now. completion(nil) and rebuilding without a height change would recover it.
Smaller:
updateHorizontalInsetsnever re-assignsmessageView.horizontalInsets; harmless today since every remeasure is preceded by an assignment, but a one-liner closes it.region.framealready includes UIKit's interactive margins per the header, and we addMESSAGE_MARGINon top. Fine if intended; worth a word in the comment.- No log records which window
sceneViewchose, the scene bounds, or the computed insets. OneVERBOSEline peraddConstraintsForMessage(not per layout pass) would make a Duo layout report reconstructible. - The inset math has no seam and no tests. Pulling
(margin, safeArea, width, regions, isFullscreen) -> UIEdgeInsetsinto a pure function would let the straddling-region anduseWidthMargin == NOcases be unit tested instead of screenshot-only.
Release frameworks are built with an SDK older than iOS 27.1, which compiled the camera clearance out of shipped binaries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also keep the message view's insets in sync on layout, log the chosen scene window and insets, and note that region frames include margins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re the review summary (52f0398):
|
abdulraqeeb33
left a comment
There was a problem hiding this comment.
Everything from both rounds is addressed. I checked the runtime shim in isolation: Class-through-protocol dispatch, nil on a missing class, and @available with a version the SDK doesn't know all behave, so the camera clearance ships under the 15.2 pin. You're right on coordinateSpace too: UIWindowSceneGeometry.coordinateSpace is 26+, not 16+, so keeping the deprecated property is the right call on a 15.0 target.
One non-blocking ask inline (ticket link for the toolchain bump). Merge once CI reports green on this head.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The HTML is given the app window's insets before the message window exists, and a page resize doesn't always follow to correct them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nan-li
left a comment
There was a problem hiding this comment.
Looks good. Three notes inline, none blocking. The Scope list has no bullet for the full screen insets change, and the manual testing section predates it.
| // The HTML was given the app's insets, and a page resize doesn't always follow to correct them | ||
| - (void)viewSafeAreaInsetsDidChange { | ||
| [super viewSafeAreaInsetsDidChange]; | ||
| if (self.isFullscreen && self.didPageRenderingComplete) { |
There was a problem hiding this comment.
non-blocking: This only fires when the insets change. On a home-button iPhone the message window's insets are all zero once the bar hides, so if the view attaches after that, the app's 20pt top inset stays in the HTML. Was this checked on an SE?
There was a problem hiding this comment.
One cheap way to make this order-independent: also call updateContentInsets from the existing isFullscreen branch in viewDidAppear. That covers attach-after-hide; this callback covers hide-after-attach.
| [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:errorMessage]; | ||
| // Still complete so a rotation or fold re-shows the message at its previous height | ||
| [self setupWebViewConstraints]; | ||
| completion(nil); |
There was a problem hiding this comment.
non-blocking: The header declares newHeight non-null (it's under NS_ASSUME_NONNULL_BEGIN), but this passes nil. NSNumber * _Nullable newHeight in the .h would match the caller's nil check.
| let heightMessage = [NSString stringWithFormat:@"In App Message Height: %f", self.message.height.doubleValue]; | ||
| [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:heightMessage]; | ||
| UIView *sceneView = [self sceneView]; | ||
| let layoutMessage = [NSString stringWithFormat:@"In App Message layout: scene view %@ (level %.0f) bounds %@ safe area %@ horizontal insets %@", |
There was a problem hiding this comment.
non-blocking: The vertical position comes from the guide constants in updateVerticalInsets, which aren't logged here. Adding them would make a Duo layout report complete.
abdulraqeeb33
left a comment
There was a problem hiding this comment.
Looked at eaa970c. The own-window source is right for full-bleed and the guard ordering holds: didPageRenderingComplete is set on the WK callback before the window exists, so setSafeAreaInsets is defined by the first insets change, and it is cleared on dismiss so a late callback cannot push app insets into a torn-down webview. Initial load and PageResize are unchanged in effect. Approval stands.
Two small asks:
- Add a scope bullet for this in the description; the Testing matrix predates it.
- Was full-bleed recaptured on the unfolded Duo and an SE-class sim? Those are the displays where the top inset actually moves when the bar hides.
Description
One Line Summary
Lay out IAMs correctly on iPhone Duo (folded and unfolded) and other resizable scenes, keeping them clear of side safe areas and hardware.
Details
Motivation
On the iPhone Duo,
UIScreenbounds report a single panel while UIKit sizes windows to the scene, so IAMs were sized and positioned for the wrong display. Banners also overlapped the side camera in landscape, and full-bleed IAMs left the status bar visible when unfolded.Scope
UIApplication displayBoundsuses the window scene's bounds instead ofUIScreenbounds for the IAM window, webview, and layout.addConstraintsForMessageremoves previous messageView constraints before adding new ones, so a stale initial Y constraint can't keep the message offscreen after a size transition.viewDidAppearrefreshes status bar appearance, since resizable scenes don't re-queryprefersStatusBarHiddenwhen the IAM window becomes key.Out of scope: full screen "no margin" and default HTML close buttons landing on the camera. The SDK already passes the safe area (which covers the camera) through
setSafeAreaInsets; the templates ignore the side insets. Tracked in SDK-5657.No public API changes. Behavior on non-resizable iPhones is unchanged except margins now use max(margin, safe area) instead of their sum.
Note: I did adjust the padding for safe area so things like distance to status bar (right or bottom) now are smaller.
Before:
After:
Testing
Manual testing
Captured with the IAM screenshot tool (
capture.sh --all), covering every IAM type (top/bottom/center/full-screen, with and without margins, carousel) plus push banners on the demo app:Also checked rotating and folding/unfolding while an IAM is shown.
Screenshots
iPhone 18 Pro
iPad Pro 11-inch
iPhone Duo
Affected code checklist
Checklist
Overview
Testing
Final pass
🤖 Generated with Claude Code