Watch apps: one entry point, a phone-watch channel, and a simulator that can run the pair - #5487
Open
shai-almog wants to merge 262 commits into
Open
Watch apps: one entry point, a phone-watch channel, and a simulator that can run the pair#5487shai-almog wants to merge 262 commits into
shai-almog wants to merge 262 commits into
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
isWatch()existed without a product on top of it. This turns the watch renderslice into a watch app: one setting builds it on both platforms, the two apps can
talk, and you can develop the pair on your desktop.
Bugs this fixes
Wearables are new and nothing depends on them, so these are fixed rather than
preserved:
codename1.watchMainbecame abuild argument only on the local path; the server lifts only
codename1.arg.*keys out of the uploaded settings file, so the daemon asked for
watchMainandgot nothing.
companiondefault never embedded the watch app.watchNative.embedCompaniondefaulted tofalse, so the "Embed Watch Content"phase was actively removed even in companion mode.
watchMainreached only iOS. Wear OS was enabled by an unrelatedandroid.wearhint, so a project had to declare the same intent twice.JavaSEPortnever overrodeisWatch(), so the guide's advice to iterate on a watch layout locally wasuntrue.
onGenericMotionEventread only the mouseaxes; rotary input arrives on
SOURCE_ROTARY_ENCODER/AXIS_SCROLL.so the safe area came back zero.
What is new
One setting.
codename1.watchMainis the entire opt-in on both platforms.Nine build hints are deleted; bundle id, deployment target, team id and display
name are derived.
codename1.watchStandaloneis the only other setting — the onething not inferable from the project. Net new hints: zero.
com.codename1.wearable— the phone↔watch channel, same API on Apple Watchand Wear OS, modelled on
com.codename1.car(portable API, SPI bridge, inertwhen there is nothing on the other end). It exposes the three transports the
platforms actually give us, because picking the wrong one is the usual reason a
watch app "never gets the update":
sendMessagefor a live answer,putDataforstate that survives sleep and relaunch,
transferFilefor bulk. Callbacks arriveon the EDT and are queued across a cold start — the platform starts an app purely
to hand it a payload. Backed by
WCSessionon Apple and the Wearable Data Layeron Android, both gated by API scan so apps that never talk to a watch link
nothing.
A simulator that runs the pair. Four generated watch skins (Apple Watch 41/45,
Wear round, Wear square),
isWatch()and the"watch"override layer, and aWatch menu that launches
watchMainin a second process wired to the first — sosendMessageandputDatagenuinely round-trip on the desktop. Two processes,not two windows:
Displayis a singleton and sharing it would hide the bugs thatonly appear once the pair is real.
Complications as surfaces families. A complication is a WidgetKit widget in
an accessory family, so
WATCH_CIRCULAR/RECTANGULAR/INLINE/CORNERjoinWidgetSizerather than getting an API of their own.The guide, rewritten around the two-app model, with the data-sharing decision
table as its centre.
Not yet done, and stated as such
that render the watch families are not generated yet. The guide says so.
codename1.watchMain, and boots a watch stub. Verified end to end: the watchtarget compiles, links and renders on the watchOS simulator (166 pass / 3 fail
/ 2 skip). Tree-shaking is real -- the phone tree carries 24 generated SVG
classes, the watch tree none -- and that is also the one known regression:
those classes are reached reflectively, so
SVGStatic,SVGAnimatedScreenshotTestandLottieAnimatedScreenshotTestfall back to aplaceholder render. The watch pass needs the same reflective roots the phone
pass keeps. A project whose watch entry point IS the phone main keeps a single
translation and is unaffected.
Verification
CI is the gate. Everything below is what was additionally checked locally before
pushing, and the numbers move as the branch does.
codenameone-maven-plugin: 466 pass, 1 skippedcore-unittests: 4754 pass, with SpotBugs, PMD and Checkstyle at zerotype-check against a stub harness (nothing in CI compiles them) and the
WatchConnectivity native passes
clang -fsyntax-onlyfor iphoneos/arm64--failure-level WARN, Vale, capitalizationbuild-ios-watchdoes run in CI -- it is a job in Test iOS UI buildscripts, on macos-15 with
DEVELOPER_DIRpointed at Xcode 26, and this PRtouches paths that trigger it. It is the real gate for anything that alters
the generated Xcode project. It is not run on the authoring machine, and
during the rapid review cycle several of its runs were cancelled by
supersession, so check it against the CURRENT head rather than an older run.
Server-side half: codenameone/BuildDaemon#watch-apps-product
🤖 Generated with Claude Code