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 configures native SDK contentfulLocales and an app/content locale, then uses
client.locale in the shared raw CDA fetch helper. Experience API calls use that resolved locale by
default unless nested api.locale is configured as an explicit API override. 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, so ContentfulLocales(default: "en-US") is enough. Add
supported only when a production app needs device-locale matching across multiple Contentful
locales.
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.