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: 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."