Skip to main content

Apple Watch

Apple Watch is a first-class Hosanna target with a companion runtime architecture. watchOS does not provide the JavaScriptCore framework used by Hosanna's Apple runtime, so the paired iPhone keeps the live TypeScript application while a native SwiftUI watch app renders the semantic watch model.

Apple Watch using the paired iPhone JavaScriptCore runtime and Wear OS using local Hermes behind one shared watch contractApple Watch using the paired iPhone JavaScriptCore runtime and Wear OS using local Hermes behind one shared watch contract

Runtime Model​

The supported path is:

Hosanna TypeScript on paired iPhone
→ existing JavaScriptCore runtime and native-service bridge
→ WatchConnectivity adapter
→ native SwiftUI watch surface

Interactions travel back through the same layers. While both apps are reachable, WCSession messages deliver selections and current state directly. The native watch app also caches the latest accepted revision so it can render useful state during a temporary disconnect; queued/deferred interactions are reconciled when communication resumes.

Application state, callback ownership, navigation intent, and asynchronous data remain in TypeScript. Swift owns only watchOS lifecycle, connectivity, and the supported native presentation.

Shared Watch API​

IWatchUIManager exposes a deliberately small, watch-shaped contract:

  • root list screen and per-session lifecycle;
  • sections, text items, action items, title/detail text, and enabled state;
  • root, push, update, pop, and pop-to-root navigation;
  • selection and navigation callbacks;
  • visible, interactive, reachable, and ambient state;
  • optional rotary input events;
  • stable screen IDs and increasing revisions.

This API is shared with Wear OS. Apple-specific behavior should stay behind an extension when it cannot be expressed honestly in the common contract. SwiftUI List owns Digital Crown scrolling on Apple Watch, so the watchUI capability's rotaryInput flag is false and raw crown deltas are not sent to TypeScript.

Application Entry​

Provide @hs-platform/AppleWatchAppEntry. It is evaluated inside the paired iPhone's existing JSContext and receives an Apple Watch-scoped launch identity:

export function createAppleWatchApp({watchUI, launchArgs}) {
const app = new MyWatchApplication(watchUI, launchArgs);
app.start();
return app;
}

The entry can return a disposer function or a runtime object with optional onTick and required dispose methods.

A typical application subscribes to lifecycle before reading existing sessions, installs a root for every session, increments a screen revision for updates, and releases both listeners and callback registrations from dispose.

Create and Configure​

Hosanna Tools generates and maintains:

  • the hosanna-watch watchOS application target and scheme;
  • an app-owned @main SwiftUI entry that hosts HosannaWatchRootView;
  • the reusable framework source from HosannaAppleWatch;
  • embedding/dependency from hosanna-ios;
  • watchos.xcconfig, companion identifier, bundle ID, and signing settings.

By default the watch bundle identifier is <ios bundle id>.watch.

Run native:init once when adding the target. Subsequent native:prepare calls validate the app-owned project without recreating it.

npx hst native:init apple-watch
npx hst native:prepare apple-watch --non-interactive --format json
npx hst native:doctor apple-watch
npx hst target:list --platform apple-watch --target sim --json

watchos is accepted as an input alias; commands and generated configuration use the canonical apple-watch name.

Build and Run​

Select the watch simulator. Hosanna Tools resolves its paired iPhone, boots both devices, builds the embedded companion application, installs/launches the iPhone JavaScriptCore host, and then launches the watch application.

npx hst build apple-watch dev sim \
--device "Apple Watch Series 11 (46mm)"
npx hst run apple-watch dev sim \
--device "Apple Watch Series 11 (46mm)"

Current CoreDevice inventory exposes the paired iPhone but does not provide a reliable standalone Watch install/launch destination to HST. For hardware, open the generated project in Xcode, select the paired Watch destination, and run the hosanna-watch/companion scheme. Launch/deploy the paired iPhone companion and its JavaScriptCore runtime as well; launching only the watch can leave it asking the user to open the iPhone app. hst target:list apple-watch --target device reports this limitation explicitly instead of pretending a simulator or iPhone is the watch. Signing must cover both bundle identifiers and the companion relationship.

Reachability and Lifecycle​

WCSession.isReachable is transient. Do not treat it as durable storage or a guarantee that the iPhone process is running. The adapter distinguishes:

  • immediate messaging when the counterpart is reachable;
  • latest-state caching for watch presentation;
  • background/context transfer, whose delivery is opportunistic;
  • lifecycle and reachability changes surfaced to TypeScript;
  • stale revisions, which native code rejects rather than rendering backward.

Pause presentation-only work in ambient mode and disable actions while the surface is not interactive. Guard asynchronous completions by request and session identity.

Validation Checklist​

  • Launch the real paired iPhone + Watch simulator pair through hst run.
  • Verify initial cached/loading state and live JS-driven list content.
  • Select an item and verify the callback reaches JavaScriptCore.
  • Verify a TypeScript state change updates SwiftUI and navigation.
  • Toggle reachability and confirm cached/deferred behavior.
  • Exercise inactive/active, background, ambient, disconnect, reconnect, and session teardown.
  • Repeat on a physical paired iPhone and Apple Watch before production.
  • Confirm signing, privacy usage, notifications/background modes if used, App Store metadata, and accessibility.

The first target does not include complications, widgets, notifications, or standalone on-watch JavaScript. Those are separate capabilities. See Apple's watchOS app guidance, WatchConnectivity session reference, and background execution guidance.

Talk to us