Readme · Guides · Reference · Contributing
The Optimization SDK Suite is pre-release (alpha). Breaking changes can be published at any time.
Reference app for native iOS bridge and preview-panel validation work. This app exercises two iOS
shells against the mock server in lib/mocks/ and hosts the XCUITest suite.
This is not a published iOS SDK package. For package status, see
packages/ios.
Use this app when you need to validate native iOS bridge and preview-panel behavior against the shared mock API. The app includes two host shells:
OptimizationAppSwiftUI - SwiftUI shell, with sources under swiftui/.OptimizationAppUIKit - UIKit shell, with sources under uikit/.Both apps share shared/ for configuration, Contentful fetching, and analytics event storage. They
run the same UI test source tree from uitests/ against their respective host apps so SDK behavior
can be compared across UI frameworks.
The app defines one locale in shared config, passes it to the native SDK as top-level locale, and
passes it directly to the shared raw CDA fetch helper. Entries passed to SDK resolution use the
standard single-locale CDA entry shape. Do not use all-locale CDA responses or locale=*, because
entry resolution expects direct single-locale fields such as fields.nt_experiences and
fields.nt_variants. See
Locale handling in the Optimization SDK Suite
for the broader locale model and
Entry personalization and variant resolution
for the entry contract.
This mock app uses one Contentful locale. A production app can derive the application locale from
its own navigation, i18n, or account-preference layer and pass that value to both SDK locale and
CDA requests when they should stay aligned.
http://localhost:8000.The Xcode project is generated by XcodeGen from
project.yml. Regenerate the project after you add, rename, or move a source file:
brew install xcodegen
xcodegen generate
From the monorepo root, start the mock API server before running UI tests:
pnpm serve:mocks
The bootstrap script runs preflight checks, then configures, builds, and launches the app on an iOS Simulator with the mock server running. When it finishes it leaves a simulator booted with the reference app and the mock server running in the foreground:
cd implementations/ios-sdk
./scripts/bootstrap.sh
The preflight checks verify that you are on macOS with Xcode (full IDE, not just the Command Line Tools), an iOS Simulator runtime, Node.js, and pnpm. If a check fails, the script prints the exact remediation steps and stops before building anything. XcodeGen is installed automatically via Homebrew if it is missing.
Useful environment variables:
APP_SHELL — swiftui (default) or uikit.IOS_SIM_NAME — simulator device name (default iPhone 16); falls back to the first available
iPhone if the named device is absent.SKIP_BUILD — set to true to reuse the last build.Unlike the Android app, no port forwarding is required: the iOS Simulator shares the host network,
so the app reaches the mock server at localhost:8000 directly.
Use this app when you need a debuggable native iOS surface for changes in
packages/ios/ContentfulOptimization or the shared JS bridge. The Xcode project references the SDK
as a local Swift Package, so app builds compile the package from workspace source rather than from a
published artifact.
The app schemes include a pre-action that builds @contentful/optimization-js-bridge before Swift
Package resource resolution when bridge source is newer than the copied UMD resource. The pre-action
writes its output to /tmp/optimization-ios-build-js-bridge.log; check that file if Xcode appears
to use a stale bridge bundle or cannot find pnpm.
The normal loop is:
packages/ios/ContentfulOptimization/Sources/... or bridge TypeScript in
packages/universal/optimization-js-bridge/src/....OptimizationAppSwiftUI or OptimizationAppUIKit scheme. Xcode recompiles the
local Swift Package and refreshes the bridge bundle when needed.From the command line, build a shell from implementations/ios-sdk/:
xcodebuild build \
-project OptimizationApp.xcodeproj \
-scheme OptimizationAppSwiftUI \
-destination 'platform=iOS Simulator,name=iPhone 16'
Run the smallest check that covers the changed surface:
| Change area | Suggested validation |
|---|---|
| Bridge TypeScript only | pnpm --filter @contentful/optimization-js-bridge typecheck and pnpm --filter @contentful/optimization-js-bridge build |
| Swift package behavior | Targeted xcodebuild test for the affected app shell or XCUITest class |
| Preview-panel or cross-platform behavior | Targeted preview-panel XCUITest plus the matching shared scenario contract review |
| Documentation-only README changes | Prettier on touched Markdown and git diff --check |
Common local pitfalls:
xcodegen generate after changing project.yml or adding, moving, or renaming iOS sources.pnpm, launch Xcode from a shell where pnpm --version works or check the
pre-action log for the exact PATH issue.iPhone 16.Run the full suite against both app shells from implementations/ios-sdk/:
xcodebuild test \
-project OptimizationApp.xcodeproj \
-scheme OptimizationAppSwiftUI \
-destination 'platform=iOS Simulator,name=iPhone 16'
xcodebuild test \
-project OptimizationApp.xcodeproj \
-scheme OptimizationAppUIKit \
-destination 'platform=iOS Simulator,name=iPhone 16'
Run a single test class against the SwiftUI shell:
xcodebuild test \
-project OptimizationApp.xcodeproj \
-scheme OptimizationAppSwiftUI \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:OptimizationAppUITestsSwiftUI/PreviewPanelOverridesTests
Add the .swift file to uitests/Tests/ and run xcodegen generate. Both UI test bundles pick up
the file from the generated project.
The preview-panel override suite mirrors the React Native Detox suite in
implementations/react-native-sdk/e2e/preview-panel-overrides.test.js. Both reference the shared
contract document at implementations/PREVIEW_PANEL_SCENARIOS.md. Keep scenario names and fixture
IDs identical across platforms so cross-platform regressions are visible in CI diffs.