From 9b0950ddfd06df76d6e7cd36c0e143e024d95cca Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 29 May 2026 23:56:51 -0400 Subject: [PATCH 1/2] Fix xcodegen clobbering Info.plist and entitlements keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XcodeGen's `info:`/`entitlements:` blocks *generate* those files on every `xcodegen generate`, overwriting the hand-authored ones in the source tree. Because project.yml carried no `properties:`, each run silently stripped required keys, and the loss only ever showed up at runtime (CI checks compilation only), so it went unnoticed: - iOS: lost `UIBackgroundModes=[audio]` (background audio for long sessions), `MPNowPlayingInfoPropertyMediaType`, launch screen + orientations. - watchOS: lost `WKApplication=true` — installd then rejects the embedded watch bundle, blocking install of the iOS app on device/simulator. - macOS: lost `NSHighResolutionCapable`, now-playing media type, and the app-sandbox / network.client entitlements (built unsandboxed). Move these keys into project.yml's `info.properties` / `entitlements.properties` so xcodegen emits them every time. Also add `WKCompanionAppBundleIdentifier` to pair the watch app with its iOS host (referenced in a comment but never actually present). Verified: the regenerated bundles carry the keys, the macOS app is sandboxed again, and the full iOS+watch bundle installs. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/apple/CascadeMac/Cascade.entitlements | 12 ++-- apps/apple/CascadeMac/Info.plist | 36 ++++++---- apps/apple/CascadeWatch/Info.plist | 39 +++++++---- apps/apple/CascadeiOS/Info.plist | 79 ++++++++++++---------- apps/apple/project.yml | 42 ++++++++++++ 5 files changed, 140 insertions(+), 68 deletions(-) diff --git a/apps/apple/CascadeMac/Cascade.entitlements b/apps/apple/CascadeMac/Cascade.entitlements index 28d8e54..0ab12df 100644 --- a/apps/apple/CascadeMac/Cascade.entitlements +++ b/apps/apple/CascadeMac/Cascade.entitlements @@ -2,13 +2,9 @@ - - com.apple.security.app-sandbox - - - com.apple.security.network.client - + com.apple.security.app-sandbox + + com.apple.security.network.client + diff --git a/apps/apple/CascadeMac/Info.plist b/apps/apple/CascadeMac/Info.plist index 9d1d8e2..53bed7a 100644 --- a/apps/apple/CascadeMac/Info.plist +++ b/apps/apple/CascadeMac/Info.plist @@ -2,17 +2,29 @@ - CFBundleDisplayName - Cascade - CFBundleName - Cascade - NSHumanReadableCopyright - © 2026 Jacob Stephens - - NSHighResolutionCapable - - - MPNowPlayingInfoPropertyMediaType - 1 + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Cascade + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + MPNowPlayingInfoPropertyMediaType + 1 + NSHighResolutionCapable + + NSHumanReadableCopyright + © 2026 Jacob Stephens diff --git a/apps/apple/CascadeWatch/Info.plist b/apps/apple/CascadeWatch/Info.plist index 90534f0..0817ede 100644 --- a/apps/apple/CascadeWatch/Info.plist +++ b/apps/apple/CascadeWatch/Info.plist @@ -2,18 +2,31 @@ - CFBundleDisplayName - Cascade - CFBundleName - Cascade - WKApplication - - WKWatchOnly - - - NSHumanReadableCopyright - © 2026 Jacob Stephens + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Cascade + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + © 2026 Jacob Stephens + WKApplication + + WKCompanionAppBundleIdentifier + page.stephens.cascade + WKWatchOnly + diff --git a/apps/apple/CascadeiOS/Info.plist b/apps/apple/CascadeiOS/Info.plist index 0c68f49..eebf649 100644 --- a/apps/apple/CascadeiOS/Info.plist +++ b/apps/apple/CascadeiOS/Info.plist @@ -2,40 +2,49 @@ - CFBundleDisplayName - Cascade - CFBundleName - Cascade - UIRequiresFullScreen - - UILaunchScreen - - UIColorName - LaunchBackground - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - - - UIBackgroundModes - - audio - - - MPNowPlayingInfoPropertyMediaType - 1 - NSHumanReadableCopyright - © 2026 Jacob Stephens + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Cascade + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + MPNowPlayingInfoPropertyMediaType + 1 + NSHumanReadableCopyright + © 2026 Jacob Stephens + UIBackgroundModes + + audio + + UILaunchScreen + + UIColorName + LaunchBackground + + UIRequiresFullScreen + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + diff --git a/apps/apple/project.yml b/apps/apple/project.yml index 8035d50..cdb7282 100644 --- a/apps/apple/project.yml +++ b/apps/apple/project.yml @@ -44,8 +44,20 @@ targets: optional: true info: path: CascadeMac/Info.plist + properties: + CFBundleDisplayName: Cascade + NSHighResolutionCapable: true + # Required so MPNowPlayingInfoCenter shows up in Control Center. + MPNowPlayingInfoPropertyMediaType: 1 + NSHumanReadableCopyright: "© 2026 Jacob Stephens" entitlements: path: CascadeMac/Cascade.entitlements + properties: + # App Sandbox: audio + Application Support writes + IOKit power + # assertions + MediaPlayer Now Playing all work under sandbox. + com.apple.security.app-sandbox: true + # Explicit: this app never reaches the network. + com.apple.security.network.client: false settings: base: PRODUCT_BUNDLE_IDENTIFIER: page.stephens.cascade @@ -71,6 +83,26 @@ targets: optional: true info: path: CascadeiOS/Info.plist + properties: + CFBundleDisplayName: Cascade + UIRequiresFullScreen: false + UILaunchScreen: + UIColorName: LaunchBackground + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + "UISupportedInterfaceOrientations~ipad": + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + - UIInterfaceOrientationPortraitUpsideDown + # Keep the audio engine running when the screen locks or the app is + # backgrounded — non-negotiable for an 8-hour focus session player. + UIBackgroundModes: + - audio + # Required so MPNowPlayingInfoCenter shows on the lock screen / Control + # Center for AirPods / headphone-button control. + MPNowPlayingInfoPropertyMediaType: 1 + NSHumanReadableCopyright: "© 2026 Jacob Stephens" entitlements: path: CascadeiOS/Cascade.entitlements settings: @@ -111,6 +143,16 @@ targets: optional: true info: path: CascadeWatch/Info.plist + properties: + CFBundleDisplayName: Cascade + # Marks this as a (modern, single-target) watchOS app. Without it, + # installd rejects the embedded watch bundle ("no WKApplication key"). + WKApplication: true + WKWatchOnly: false + # Pairs the watch app to the iPhone app as its companion — required for + # the embedded watch bundle to install alongside its iOS host. + WKCompanionAppBundleIdentifier: page.stephens.cascade + NSHumanReadableCopyright: "© 2026 Jacob Stephens" entitlements: path: CascadeWatch/Cascade.entitlements settings: From 8630aebb32c1d41b65032f97697ea7aa24ffd5f7 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 30 May 2026 23:16:31 -0400 Subject: [PATCH 2/2] Add install-device.sh: one-command build/sign/install to a connected iPhone Auto-detects the connected device UDID and the Apple Development team (from the signing cert), builds CascadeiOS with automatic signing, and installs + launches it via devicectl. Uses -allowProvisioningDeviceRegistration so a freshly-connected device is registered with the team on first run. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/apple/scripts/install-device.sh | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 apps/apple/scripts/install-device.sh diff --git a/apps/apple/scripts/install-device.sh b/apps/apple/scripts/install-device.sh new file mode 100755 index 0000000..ac9b141 --- /dev/null +++ b/apps/apple/scripts/install-device.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Build, sign, and install CascadeiOS onto a connected iPhone, then launch it. +# +# Prerequisites (one-time): +# 1. iPhone connected + paired (tap "Trust This Computer" on the phone). +# 2. Developer Mode ON: iPhone Settings > Privacy & Security > Developer Mode. +# 3. An Apple ID added to Xcode (Settings > Accounts) so a development +# signing certificate + team exist. A free Apple ID works (7-day apps). +# +# Usage (from apps/apple/): +# ./scripts/install-device.sh [TEAM_ID] [DEVICE_UDID] +# Both args are auto-detected if omitted. +set -euo pipefail +cd "$(dirname "$0")/.." # -> apps/apple + +# --- resolve the device --------------------------------------------------- +UDID="${2:-$(xcrun devicectl list devices 2>/dev/null | awk '/available/{print $3; exit}')}" +[ -n "${UDID:-}" ] || { echo "No connected/paired device found. Plug in + Trust the phone."; exit 1; } +echo "→ device: $UDID" + +# --- resolve the signing team --------------------------------------------- +TEAM="${1:-$(security find-certificate -a -c 'Apple Development' -p 2>/dev/null \ + | openssl x509 -noout -subject 2>/dev/null \ + | grep -oE 'OU *= *[A-Z0-9]{10}' | grep -oE '[A-Z0-9]{10}' | head -1)}" +[ -n "${TEAM:-}" ] || { echo "No Apple Development team found. Add your Apple ID in Xcode > Settings > Accounts, then pass the 10-char Team ID as arg 1."; exit 1; } +echo "→ team: $TEAM" + +# --- build + sign for the device ------------------------------------------ +echo "→ building (automatic signing)…" +xcodebuild -project Cascade.xcodeproj -scheme CascadeiOS -configuration Debug \ + -destination "id=$UDID" -derivedDataPath build/dd-iosdev \ + DEVELOPMENT_TEAM="$TEAM" CODE_SIGN_STYLE=Automatic \ + -allowProvisioningUpdates -allowProvisioningDeviceRegistration build + +APP="build/dd-iosdev/Build/Products/Debug-iphoneos/Cascade.app" +[ -d "$APP" ] || { echo "Build did not produce $APP"; exit 1; } + +# --- install + launch ------------------------------------------------------ +echo "→ installing onto device…" +xcrun devicectl device install app --device "$UDID" "$APP" +echo "→ launching…" +xcrun devicectl device process launch --device "$UDID" page.stephens.cascade || true +echo "✓ Done. If the phone shows 'Untrusted Developer', go to Settings > General" +echo " > VPN & Device Management, trust your cert, then re-run this script."