diff --git a/BrazeKit.podspec b/BrazeKit.podspec
index bc3d7123e7..e350aed395 100644
--- a/BrazeKit.podspec
+++ b/BrazeKit.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeKit'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Braze Main SDK library providing support for analytics and push notifications.'
s.homepage = 'https://braze.com'
@@ -9,8 +9,8 @@ Pod::Spec.new do |s|
s.authors = 'Braze, Inc.'
s.source = {
- :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeKit.zip',
- :sha256 => 'b63d2e6ecc4200b77769c38ddc04b4afb732833cb946c1799e59bb7e6c449ec0'
+ :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeKit.zip',
+ :sha256 => '43c0aff33a6d89d5ee8182c19726b75c8c29335fc95dd579e57a959a763ba001'
}
s.swift_version = '5.0'
diff --git a/BrazeKitCompat.podspec b/BrazeKitCompat.podspec
index 1ccaf044fd..44001891cd 100644
--- a/BrazeKitCompat.podspec
+++ b/BrazeKitCompat.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeKitCompat'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Compatibility library for users migrating from AppboyKit.'
s.homepage = 'https://braze.com'
@@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.license = { :type => 'Commercial' }
s.authors = 'Braze, Inc.'
- s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.13.0' }
+ s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.14.0' }
s.swift_version = '5.0'
s.ios.deployment_target = '11.0'
@@ -18,8 +18,8 @@ Pod::Spec.new do |s|
s.source_files = 'Sources/BrazeKitCompat/**/*.{h,m}'
s.public_header_files = 'Sources/BrazeKitCompat/include/*.h'
- s.dependency 'BrazeKit', '5.13.0'
- s.dependency 'BrazeLocation', '5.13.0'
+ s.dependency 'BrazeKit', '5.14.0'
+ s.dependency 'BrazeLocation', '5.14.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
end
diff --git a/BrazeLocation.podspec b/BrazeLocation.podspec
index b8f662adee..9130fabdd7 100644
--- a/BrazeLocation.podspec
+++ b/BrazeLocation.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeLocation'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Braze location library providing support for location analytics and geofence monitoring.'
s.homepage = 'https://braze.com'
@@ -9,8 +9,8 @@ Pod::Spec.new do |s|
s.authors = 'Braze, Inc.'
s.source = {
- :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeLocation.zip',
- :sha256 => 'f7e62e3685dca2028454cbf4e9d1738dd172780455a4f6b12c8affc60e137086'
+ :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeLocation.zip',
+ :sha256 => '9a1fec33eeb9b29baeb9156340a127bf64c99311a3e4d447f270c56d64ef222c'
}
s.swift_version = '5.0'
@@ -21,7 +21,7 @@ Pod::Spec.new do |s|
# Depends on BrazeKit because BrazeKit includes the internal _BrazeLocationClient symbols required
# for linking against BrazeLocation.
- s.dependency 'BrazeKit', '5.13.0'
+ s.dependency 'BrazeKit', '5.14.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
end
diff --git a/BrazeNotificationService.podspec b/BrazeNotificationService.podspec
index 931ededbed..83136dbeb4 100644
--- a/BrazeNotificationService.podspec
+++ b/BrazeNotificationService.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeNotificationService'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Braze notification service extension library providing support for Rich Push notifications.'
s.homepage = 'https://braze.com'
@@ -9,8 +9,8 @@ Pod::Spec.new do |s|
s.authors = 'Braze, Inc.'
s.source = {
- :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeNotificationService.zip',
- :sha256 => '231e81dca0315ddaad4935bdb5e79752b6cf050c0a9aec9f9523e766a3a5e5a0'
+ :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeNotificationService.zip',
+ :sha256 => 'b0f60f74760d63ff3dc3a16dd11e5c711d4c0ed7fdee3681ffe451803542aa5b'
}
s.swift_version = '5.0'
diff --git a/BrazePushStory.podspec b/BrazePushStory.podspec
index 0d2953cf00..85ca3f62a8 100644
--- a/BrazePushStory.podspec
+++ b/BrazePushStory.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazePushStory'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Braze notification content extension library providing support for Push Stories.'
s.homepage = 'https://braze.com'
@@ -9,8 +9,8 @@ Pod::Spec.new do |s|
s.authors = 'Braze, Inc.'
s.source = {
- :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazePushStory.zip',
- :sha256 => 'ad7bf6bfe70c54e0e00f9dcd828eabe71d06c435efaccee0d2c4112b596f85ff'
+ :http => 'https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazePushStory.zip',
+ :sha256 => '2d6e53a749ff54cd0d6ca898b761696c828a8172eafa2522c245706324e1d0c6'
}
s.swift_version = '5.0'
diff --git a/BrazeUI.podspec b/BrazeUI.podspec
index a618540ac2..65a45d6fa6 100644
--- a/BrazeUI.podspec
+++ b/BrazeUI.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeUI'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Braze-provided user interface library for In-App Messages and Content Cards.'
s.homepage = 'https://braze.com'
@@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.license = { :type => 'Commercial' }
s.authors = 'Braze, Inc.'
- s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.13.0' }
+ s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.14.0' }
s.swift_version = '5.0'
s.ios.deployment_target = '11.0'
@@ -17,7 +17,7 @@ Pod::Spec.new do |s|
s.source_files = 'Sources/BrazeUI/**/*.swift'
s.resource_bundles = { 'BrazeUI' => ['Sources/BrazeUI/Resources/**/*'] }
- s.dependency 'BrazeKit', '5.13.0'
+ s.dependency 'BrazeKit', '5.14.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
end
diff --git a/BrazeUICompat.podspec b/BrazeUICompat.podspec
index 3f63198c44..c7930007ed 100644
--- a/BrazeUICompat.podspec
+++ b/BrazeUICompat.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'BrazeUICompat'
- s.version = '5.13.0'
+ s.version = '5.14.0'
s.summary = 'Compatibility UI library for users migrating from AppboyUI.'
s.homepage = 'https://braze.com'
@@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.license = { :type => 'Commercial' }
s.authors = 'Braze, Inc.'
- s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.13.0' }
+ s.source = { :git => 'https://github.com/braze-inc/braze-swift-sdk.git', :tag => '5.14.0' }
s.swift_version = '5.0'
s.ios.deployment_target = '11.0'
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
s.public_header_files = 'Sources/BrazeUICompat/ABK*/**/*.h'
s.resource_bundles = { 'BrazeUICompat' => 'Sources/BrazeUICompat/*/Resources/**/*.*' }
- s.dependency 'BrazeKitCompat', '5.13.0'
+ s.dependency 'BrazeKitCompat', '5.14.0'
s.dependency 'SDWebImage', '>= 5.8.2', '< 6'
s.user_target_xcconfig = { 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES' }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 570b85844d..3ea9356341 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## 5.14.0
+
+##### Fixed
+- VoiceOver now correctly focuses on in-app message views when they are presented.
+- Fixes an issue causing in-app messages with re-eligibility disabled to display multiple times under certain conditions.
+- Fixes an issue where modal and full in-app message headers were truncated on devices running iOS versions lower than 16 when displaying non-ASCII characters.
+- The dynamic variant of `BrazeUI.framework` in the release artifact `braze-swift-sdk-prebuilt.zip` is now an actual dynamic framework. Previously, this specific framework was mistakenly distributed as a static framework.
+
+##### Added
+- Adds the `BrazeSDKAuthDelegate` protocol as a separate protocol from `BrazeDelegate`, allowing for more flexible integrations.
+ - Apps implementing `BrazeDelegate.braze(_:sdkAuthenticationFailedWithError:)` should migrate to use `BrazeSDKAuthDelegate` and remove the old implementation. The `BrazeDelegate` method will be removed in a future major release.
+
## 5.13.0
##### Fixed
diff --git a/Examples/ObjC/Sources/ContentCards/Info.plist b/Examples/ObjC/Sources/ContentCards/Info.plist
new file mode 100644
index 0000000000..0c015f1468
--- /dev/null
+++ b/Examples/ObjC/Sources/ContentCards/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ ContentCards
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ UILaunchStoryboardName
+ LaunchScreen
+
+
diff --git a/Examples/ObjC/Sources/InAppMessages/Info.plist b/Examples/ObjC/Sources/InAppMessages/Info.plist
new file mode 100644
index 0000000000..4f97542122
--- /dev/null
+++ b/Examples/ObjC/Sources/InAppMessages/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ InAppMessages
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ UILaunchStoryboardName
+ LaunchScreen
+
+
diff --git a/Examples/ObjC/manual-integration-setup.sh b/Examples/ObjC/manual-integration-setup.sh
index 326cf26b83..6bb00123cf 100755
--- a/Examples/ObjC/manual-integration-setup.sh
+++ b/Examples/ObjC/manual-integration-setup.sh
@@ -20,7 +20,7 @@ if [ ! -f "manual-integration-setup.sh" ]; then
fi
# Constants
-url="https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/braze-swift-sdk-prebuilt.zip"
+url="https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/braze-swift-sdk-prebuilt.zip"
echo "→" "Cleaning up"
rm -rf braze-swift-sdk-prebuilt
diff --git a/Examples/Swift/Sources/ContentCards/Info.plist b/Examples/Swift/Sources/ContentCards/Info.plist
new file mode 100644
index 0000000000..0c015f1468
--- /dev/null
+++ b/Examples/Swift/Sources/ContentCards/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ ContentCards
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ UILaunchStoryboardName
+ LaunchScreen
+
+
diff --git a/Examples/Swift/Sources/InAppMessages/Info.plist b/Examples/Swift/Sources/InAppMessages/Info.plist
new file mode 100644
index 0000000000..4f97542122
--- /dev/null
+++ b/Examples/Swift/Sources/InAppMessages/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ InAppMessages
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ UILaunchStoryboardName
+ LaunchScreen
+
+
diff --git a/Examples/Swift/manual-integration-setup.sh b/Examples/Swift/manual-integration-setup.sh
index 326cf26b83..6bb00123cf 100755
--- a/Examples/Swift/manual-integration-setup.sh
+++ b/Examples/Swift/manual-integration-setup.sh
@@ -20,7 +20,7 @@ if [ ! -f "manual-integration-setup.sh" ]; then
fi
# Constants
-url="https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/braze-swift-sdk-prebuilt.zip"
+url="https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/braze-swift-sdk-prebuilt.zip"
echo "→" "Cleaning up"
rm -rf braze-swift-sdk-prebuilt
diff --git a/Package.swift b/Package.swift
index 690c943c9f..aca8261494 100644
--- a/Package.swift
+++ b/Package.swift
@@ -47,8 +47,8 @@ let package = Package(
targets: [
.binaryTarget(
name: "BrazeKit",
- url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeKit.zip",
- checksum: "b63d2e6ecc4200b77769c38ddc04b4afb732833cb946c1799e59bb7e6c449ec0"
+ url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeKit.zip",
+ checksum: "43c0aff33a6d89d5ee8182c19726b75c8c29335fc95dd579e57a959a763ba001"
),
.target(
name: "BrazeKitResources",
@@ -65,18 +65,18 @@ let package = Package(
),
.binaryTarget(
name: "BrazeLocation",
- url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeLocation.zip",
- checksum: "f7e62e3685dca2028454cbf4e9d1738dd172780455a4f6b12c8affc60e137086"
+ url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeLocation.zip",
+ checksum: "9a1fec33eeb9b29baeb9156340a127bf64c99311a3e4d447f270c56d64ef222c"
),
.binaryTarget(
name: "BrazeNotificationService",
- url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazeNotificationService.zip",
- checksum: "231e81dca0315ddaad4935bdb5e79752b6cf050c0a9aec9f9523e766a3a5e5a0"
+ url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazeNotificationService.zip",
+ checksum: "b0f60f74760d63ff3dc3a16dd11e5c711d4c0ed7fdee3681ffe451803542aa5b"
),
.binaryTarget(
name: "BrazePushStory",
- url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.13.0/BrazePushStory.zip",
- checksum: "ad7bf6bfe70c54e0e00f9dcd828eabe71d06c435efaccee0d2c4112b596f85ff"
+ url: "https://github.com/braze-inc/braze-swift-sdk/releases/download/5.14.0/BrazePushStory.zip",
+ checksum: "2d6e53a749ff54cd0d6ca898b761696c828a8172eafa2522c245706324e1d0c6"
),
.target(
name: "BrazeKitCompat",
diff --git a/README.md b/README.md
index 44da1828d5..027a0bcc11 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
-
+
+# ⚠️ Xcode 14.3 RC (14E222a) support
+
+The XCFrameworks distributed by this repository are not supported by Xcode 14.3 Release Candidate (14E222a). Please use our alternative repository [`braze-swift-sdk-xcode-14-3-preview`](https://github.com/braze-inc/braze-swift-sdk-xcode-14-3-preview) to build and distribute your application using Xcode 14.3 Release Candidate (14E222a).
+
+Follow this [issue](https://github.com/braze-inc/braze-swift-sdk/issues/52) for updates.
+
# Braze Swift SDK
- [Braze User Guide](https://www.braze.com/docs/user_guide/introduction/ "Braze User Guide")
diff --git a/Sources/BrazeUI/InAppMessageUI/InAppMessageMocks.swift b/Sources/BrazeUI/InAppMessageUI/InAppMessageMocks.swift
index 7168626b49..974e691c0a 100644
--- a/Sources/BrazeUI/InAppMessageUI/InAppMessageMocks.swift
+++ b/Sources/BrazeUI/InAppMessageUI/InAppMessageMocks.swift
@@ -173,6 +173,17 @@ import Foundation
]
)
+ public static let mockTallCharacters = Self(
+ data: .mock,
+ graphic: .icon(""),
+ header: "헤더입니다",
+ message:
+ """
+ 제1항의 탄핵소추는 국회재적의원 3분의 1 이상의 발의가 있어야 하며, 그 의결은 국회재적의원 과반수의 찬성이 있어야 한다. 다만, 대통령에 대한 탄핵소추는 국회재적의원 과반수의 발의와 국회재적의원 3분의 2 이상의 찬성이 있어야 한다.
+ 국가는 건전한 소비행위를 계도하고 생산품의 품질향상을 촉구하기 위한 소비자보호운동을 법률이 정하는 바에 의하여 보장한다. 모든 국민은 능력에 따라 균등하게 교육을 받을 권리를 가진다.
+ """
+ )
+
public static let mockThemed = Self(
data: .mock,
graphic: .icon(""),
@@ -351,6 +362,17 @@ import Foundation
]
)
+ public static let mockTallCharacters = Self(
+ data: .mock,
+ imageURL: .mockImage(width: 1200, height: 1000),
+ header: "헤더입니다",
+ message:
+ """
+ 제1항의 탄핵소추는 국회재적의원 3분의 1 이상의 발의가 있어야 하며, 그 의결은 국회재적의원 과반수의 찬성이 있어야 한다. 다만, 대통령에 대한 탄핵소추는 국회재적의원 과반수의 발의와 국회재적의원 3분의 2 이상의 찬성이 있어야 한다.
+ 국가는 건전한 소비행위를 계도하고 생산품의 품질향상을 촉구하기 위한 소비자보호운동을 법률이 정하는 바에 의하여 보장한다. 모든 국민은 능력에 따라 균등하게 교육을 받을 권리를 가진다.
+ """
+ )
+
public static let mockThemed = Self(
data: .mock,
imageURL: .mockImage(width: 1200, height: 1000),
diff --git a/Sources/BrazeUI/InAppMessageUI/InAppMessageUI.swift b/Sources/BrazeUI/InAppMessageUI/InAppMessageUI.swift
index 304cf68e3e..a367e423ce 100644
--- a/Sources/BrazeUI/InAppMessageUI/InAppMessageUI.swift
+++ b/Sources/BrazeUI/InAppMessageUI/InAppMessageUI.swift
@@ -158,6 +158,7 @@ open class BrazeInAppMessageUI:
} else {
window = Window(frame: UIScreen.main.bounds)
}
+ window.accessibilityViewIsModal = true
window.windowLevel = context.windowLevel
window.rootViewController = viewController
self.window = window
diff --git a/Sources/BrazeUI/InAppMessageUI/InAppMessageUIViewController.swift b/Sources/BrazeUI/InAppMessageUI/InAppMessageUIViewController.swift
index a32e88a8f3..dd1f01aca8 100644
--- a/Sources/BrazeUI/InAppMessageUI/InAppMessageUIViewController.swift
+++ b/Sources/BrazeUI/InAppMessageUI/InAppMessageUIViewController.swift
@@ -57,6 +57,11 @@ extension BrazeInAppMessageUI {
didSet { setNeedsStatusBarAppearanceUpdate() }
}
+ /// The message view initial accessibility element.
+ ///
+ /// If assigned, VoiceOver will focus on this element when the message view is presented.
+ var messageViewInitialAccessibilityElement: Any?
+
// MARK: - Initialization
/// Creates an in-app message view controller.
diff --git a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIFullView.swift b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIFullView.swift
index 0b34af4ad6..bd7356e2b7 100644
--- a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIFullView.swift
+++ b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIFullView.swift
@@ -339,6 +339,11 @@ extension BrazeInAppMessageUI {
.preview()
.frame(maxHeight: 500)
.previewDisplayName("Var. Full | Long (constrained)")
+
+ FullView(message: .mockTallCharacters, presented: true)
+ .preview()
+ .frame(maxHeight: 800)
+ .previewDisplayName("Var. Full | Tall Characters")
}
@ViewBuilder
@@ -393,6 +398,12 @@ extension BrazeInAppMessageUI {
.frame(width: 540, height: 500)
.environment(\.horizontalSizeClass, .regular)
.previewDisplayName("Var. Modal | Long (constrained)")
+
+ FullView(message: .mockTallCharacters, presented: true)
+ .preview()
+ .frame(width: 540, height: 820)
+ .environment(\.horizontalSizeClass, .regular)
+ .previewDisplayName("Var. Modal | Tall Characters")
}
@ViewBuilder
diff --git a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIHtmlView.swift b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIHtmlView.swift
index d728693c0e..3dae261925 100644
--- a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIHtmlView.swift
+++ b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIHtmlView.swift
@@ -199,6 +199,7 @@ extension BrazeInAppMessageUI {
public func present(completion: (() -> Void)? = nil) {
prefersStatusBarHidden = true
+ addVoiceOverHook()
setupWebView()
installPresentationConstraintsIfNeeded()
@@ -429,6 +430,19 @@ extension BrazeInAppMessageUI.HtmlView: WKUIDelegate {
// MARK: - Misc.
+extension BrazeInAppMessageUI.HtmlView {
+
+ fileprivate func addVoiceOverHook() {
+ // This view helps the accessibility engine focus on the message view. Without it, the
+ // accessibility engine will fail to properly focus on an accessible element within the web
+ // view.
+ let voiceOverHook = UIView()
+ insertSubview(voiceOverHook, at: 0)
+ initialAccessibilityElement = voiceOverHook
+ }
+
+}
+
extension WKWebView {
fileprivate func disableDragAndDrop() {
diff --git a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIModalView.swift b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIModalView.swift
index 8cfad91d4f..b4054e021c 100644
--- a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIModalView.swift
+++ b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageUIModalView.swift
@@ -126,9 +126,9 @@ extension BrazeInAppMessageUI {
right: 0
)
textContainer.layoutMargins = .init(
- top: TextViewLayoutConstants.textContainerLayoutMargins.top,
+ top: 0,
left: padding.left,
- bottom: TextViewLayoutConstants.textContainerLayoutMargins.bottom,
+ bottom: 0,
right: padding.right
)
buttonsContainer?.stack.layoutMargins = .init(
@@ -555,20 +555,21 @@ extension BrazeInAppMessageUI {
textView.attributedText = textViewText
}
- }
- private enum TextViewLayoutConstants {
- // Manually-tuned values to get us close to our previous StackView+Label appearance.
-
- // Soak up some vertical space that UITextView leaves above and below its text:
- static let textContainerLayoutMargins = UIEdgeInsets(top: -8, left: 0, bottom: -8, right: 0)
- // Scale factors for label → textview line spacing:
- static let headerLineSpacingScaleFactor = 0.78
- static let messageLineSpacingScaleFactor = 0.47
- // Subtraction offset between header and message:
- // (textview/TextKit renders a tiny bit of extra ascender+descender space that we want to eat up)
- static let headerMessageSpacingOffset: Double = 1.0
+ private enum TextViewLayoutConstants {
+ // Manually-tuned values to get us close to our previous StackView+Label appearance.
+
+ // Soak up some vertical space that UITextView leaves above and below its text:
+ static let textContainerLayoutMargins = UIEdgeInsets(top: -8, left: 0, bottom: -8, right: 0)
+ // Scale factors for label → textview line spacing:
+ static let headerLineSpacingScaleFactor = 0.78
+ static let messageLineSpacingScaleFactor = 0.47
+ // Subtraction offset between header and message:
+ // (textview/TextKit renders a tiny bit of extra ascender+descender space that we want to eat up)
+ static let headerMessageSpacingOffset: Double = 1.0
+ }
}
+
}
// MARK: - Previews
@@ -630,6 +631,11 @@ extension BrazeInAppMessageUI {
.preview(center: .required)
.frame(maxHeight: 375)
.previewDisplayName("Var. | Long (constrained)")
+
+ ModalView(message: .mockTallCharacters, presented: true)
+ .preview(center: .required)
+ .frame(maxHeight: 500)
+ .previewDisplayName("Var. | Tall Characters")
}
@ViewBuilder
diff --git a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageView.swift b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageView.swift
index 43dda0cb09..cb77e336c5 100644
--- a/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageView.swift
+++ b/Sources/BrazeUI/InAppMessageUI/Views/InAppMessageView.swift
@@ -52,6 +52,14 @@ public protocol InAppMessageView: UIView {
extension InAppMessageView {
+ /// The initial accessibility element.
+ ///
+ /// If assigned, VoiceOver will focus on this element when the message view is presented.
+ public var initialAccessibilityElement: Any? {
+ get { controller?.messageViewInitialAccessibilityElement }
+ set { controller?.messageViewInitialAccessibilityElement = newValue }
+ }
+
/// The preferred status bar hidden state.
///
/// Setting this value may have no effect depending of upstream customizations.
@@ -76,6 +84,10 @@ extension InAppMessageView {
return
}
+ // Ensure that VoiceOver moves to initial accessibility element
+ let accessibilityElement = initialAccessibilityElement ?? self
+ UIAccessibility.post(notification: .screenChanged, argument: accessibilityElement)
+
ui.delegate?.inAppMessage(ui, didPresent: controller.message, view: self)
}