ReviewOS

also looking at this

craft-native/craft

test(ios): install the Watch-enabled app and read the APNs environment it signs

#218
Merged glennmichael123 wants to merge fix/ios-apns-environment-resolved into main
6 files +248 -12
9 days ago

Closes #193, #194, #195 and #196.

Where the four issues stood

All four were filed on 14 September, and each was fixed in the generator the same day, a few hours later:

issuereportedfixed by
#193phone target fails: CraftWatchSession does not conform to WCSessionDelegate6bd84f4 moves the Watch source into a watchOS-only extension, with the iOS-only delegate methods behind #if os(iOS) (5d03387)
#194simctl install refuses: no WKWatchKitApp or WKApplication keyWatchApp.Info.plist.template sets WKWatchKitApp
#195simctl install refuses: "not a WatchKit 2 app"6bd84f4 generates application.watchapp2 plus a watchkit2-extension embedded in it
#196aps-environment is always development611be12: $(CRAFT_APNS_ENVIRONMENT), set to development for Debug and production for Release

None of the fixes was checked where it failed. test:templates built the Watch extension and Watch app targets on their own, which says nothing about the bundle they end up in. Its comment said the embedded app could not be built "without a watchOS runtime", and GitHub's macOS image ships one. index.test.ts checked the APNs change as two strings in project.yml, which proves what was written, not what Xcode signs.

What the gate does now

packages/ios/scripts/compile-templates.ts, run by ci.yml's ios-native-templates job:

The Watch companion (#193–#195). The script builds WatchProbe through its scheme for iOS Simulator, with the Watch app embedded, and installs it on a booted iOS simulator.

  • xcodebuild builds every target in the graph with its own SDK. That covers #193: the phone target compiles.
  • Before installing, watchCompanionProblems checks the built bundle. It requires Watch/<App>Watch.app, WKWatchKitApp (or WKApplication) true, and PlugIns/<App>WatchExtension.appex declaring com.apple.watchkit. Each failure names its issue. The helper has unit tests in watch-bundle.test.ts.
  • simctl install then has the last word, and the app is uninstalled afterwards.

It needs a watchOS simulator runtime matching the selected Xcode. macos-latest ships watchOS 11.5, 26.1 and 26.2. Without one, Xcode's own error ("watchOS N must be installed") fails the step rather than skipping it.

The APNs environment (#196). A push-only fixture is built for the simulator in Debug and Release with ad-hoc signing (CODE_SIGN_IDENTITY=-). Ad-hoc signing needs no team and still runs entitlement processing. The script reads <App>.app-Simulated.xcent, the entitlements Xcode actually produced, and requires development for Debug and production for Release. The build-setting substitution is the one device signing performs; only the signature differs.

Failing without the fixes

Each fix was reverted in the generator in turn, and the same script run:

# WKWatchKitApp removed from WatchApp.Info.plist.template
error: WatchProbe.app: Watch/WatchProbeWatch.app sets neither WKWatchKitApp nor WKApplication to true, so iOS will not install it (#194)

# the Watch app's dependency on its extension removed
error: WatchProbe.app: Watch/WatchProbeWatch.app has no PlugIns/WatchProbeWatchExtension.appex, so it is not a WatchKit 2 app (#195)

# aps-environment hard-coded back to development
ok: Debug signs aps-environment=development
error: Release signs aps-environment=development, expected production

#193 has no separate mutation. Its error cannot occur in the current structure, because the Watch source is compiled only for watchOS. What guards it is the embedded build compiling the phone target at all. The reporter's xcodebuild -target … -sdk iphonesimulator form also no longer applies: forcing one SDK onto every target cannot resolve the watchOS product types. The scheme build is the command Xcode itself runs.

Choices

  • WatchKit 2, not a single-target Watch app. #195 asked for the extension structure and 6bd84f4 generated it, so this PR tests what the generator emits rather than re-deciding it. The checker accepts WKApplication too, so a later move to single-target Watch apps does not have to fight the gate.
  • The APNs environment is derived from the build configuration, with no pushEnvironment option. That is how Xcode's own push capability behaves, and it cannot drift from the configuration being archived.

Verification

  • Locally, with the watchOS 26.5 simulator runtime installed: the Watch and push parts of test:templates pass, and the three mutations above fail.
  • bun test in packages/ios (34, including 6 new), bun run test, bun run typecheck, bun run verify:packages and Pickier.
  • The full template run on macos-latest is this PR's CI.

6 changed files on the files tab, with 0 review threads.

Sign in to comment on this pull request.