SDK-31 Fix full-position IAM safe area handling#996
Conversation
* 'master' of github-iterable:Iterable/iterable-swift-sdk: SDK-218: BCIT End-to-End Deep Link Routing Tests (#993)
Apply safe area insets to WKWebView scrollView content for full-position in-app messages. This ensures content is not hidden behind notch, status bar, or home indicator while maintaining edge-to-edge background coverage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #996 +/- ##
==========================================
+ Coverage 69.78% 70.12% +0.33%
==========================================
Files 111 111
Lines 8983 9030 +47
==========================================
+ Hits 6269 6332 +63
+ Misses 2714 2698 -16 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…area * master: [SDK-305] Fix build errors in SDK 6.6.4+ with Carthage (#994)
…tInsetAdjustment Replace overlay UIWindow approach with standard .overFullScreen modal presentation. For full-position IAMs, inject viewport-fit=cover into the HTML and set contentInsetAdjustmentBehavior=.never so the webview content extends behind the safe area (status bar / Dynamic Island / home indicator). Set the VC's view.backgroundColor to the message's background color as a fallback. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
joaodordio
left a comment
There was a problem hiding this comment.
Good solution on the HTML injection!
Marking this as Request Changes so we are 100% sure on the regex comment.
Other comments:
The PR description needs to be updated, the file InAppPresenter.swift only has whitespaces changes and the description mentions other changes.
Same thing for InAppCalculations.swift which mentions "Removed overlay window dismisser" but I don't see that.
| } | ||
|
|
||
| // Has a viewport meta tag — append viewport-fit=cover to its content | ||
| if let range = html.range(of: #"(<meta\s+name\s*=\s*"viewport"\s+content\s*=\s*")"#, |
There was a problem hiding this comment.
This regex is using double quotes, htmk with content='...' won't work.
Do we know for sure that the HTML we get on the in-app uses "" and never ''
|
|
||
| class InAppPresenter { | ||
| static var isPresenting = false | ||
There was a problem hiding this comment.
Nit pick: This file was probably previously modified but now just has whitespaces changes.
The viewport injection now handles both: - content="..." (double quotes) - content='...' (single quotes) Extracts the quote character from the regex match and uses it to find the matching closing quote.
|
@joaodordio Fixed both issues. Regex now supports single and double quotes. Updated the pattern to match both Removed whitespace changes from InAppPresenter.swift and updated PR description to reflect actual changes only. |
… bgColor Cover all 5 code paths of the viewport-fit injection (already present, name-first meta, content-first meta, no viewport meta with head, no head tag) plus edge cases (idempotency, empty string, non-viewport meta). Also verify calculateAnimationDetail uses the actual background color for .full location and .clear for other positions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Sumeru Chatterjee <sumeru.chatterjee@me.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>


What
Fixes the safe area gap (behind the status bar / Dynamic Island / home indicator) for full-position in-app messages. The background now extends edge-to-edge, matching the HTML content's background.
Approach
Uses standard
.overFullScreenmodal presentation (already set inInAppDisplayer) for all message types. For full-position IAMs, two things ensure the webview content fills the safe area:viewport-fit=coverinjection — The SDK injectsviewport-fit=coverinto the HTML's viewport meta tag before loading. This tells WkWebView the content wants to extend into the safe area. Handles existing viewport tags (appends to content), missing viewport tags (inserts into<head>), and HTML without<head>(prepends). Supports both single and double quotes in HTML attributes.contentInsetAdjustmentBehavior = .never— Prevents the WKWebView's scroll view from automatically insetting content away from the safe area, which would override the viewport-fit directive.Background color fallback — Sets the VC's
view.backgroundColorto the message's background color (when available) for full-position IAMs, so any remaining safe area gaps are filled with the correct color during load/animation.Animation initial bgColor — For full-position messages, the animation starts with the message's background color instead of
.clear, preventing a transparent-to-colored flash during fade-in.Why this doesn't break non-full-position messages
All changes are gated on
location == .fullorinput.location == .full:injectViewportFitCover: Only called whenlocation == .full. Non-full HTML is loaded unmodified.contentInsetAdjustmentBehavior: Only set to.neverwhenlocation == .full. Non-full webviews keep the default behavior.view.backgroundColorinloadView(): Only changed for.fullwith a non-nilbackgroundColor. Non-full messages use the sameinitialViewBackgroundColor(isModal:)as before.calculateAnimationDetail:initialBgColoronly differs from.clearwheninput.location == .full. The existing animation logic for top/center/bottom is completely unchanged.Changes
IterableHtmlMessageViewController.swift— AddedinjectViewportFitCover(html:)for viewport-fit injection (supports both single and double quotes),contentInsetAdjustmentBehavior = .neverfor full-position,view.backgroundColorset to message bgColor for full-position.InAppCalculations.swift— Fixed animation initial bgColor for.fullto use message's background color instead of.clear, preventing transparent flash during fade-in.Testing
Unit tests: All 97 tests pass (InAppTests, InAppPresenterTests, InAppParsingTests, IterableHtmlMessageViewControllerTests).
Manual testing: