Files
ipx/ios/project.yml
Ray Slakinski 171c77475a iOS: the app's settings in Settings, not behind a shake; iPhone upright (#445)
The server address and the player token were set from alerts that
opened on shaking the phone, which nobody finds. Settings now has a This
device section in the app: the server, the player token and its
address, and a Make button that creates an API token and hands it
straight to the app's keychain. The app sends what it has at ready
(appSettings) and takes setServer, setToken and clearToken; a new
server rebuilds the web view as the alert did. The first-launch prompt
and the Cannot reach alert stay native, since there is no page then.

The iPhone is portrait only; the iPad keeps all four orientations, which
Split View and Slide Over need (#434 checked the iPad's layout).

Build 14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 08:39:54 -05:00

146 lines
5.6 KiB
YAML

# XcodeGen makes the .xcodeproj from this, so the project is something a diff can show rather
# than a pbxproj nobody reviews. On a Mac:
#
# brew install xcodegen && cd ios && xcodegen generate && open iPX.xcodeproj
name: iPX
options:
bundleIdPrefix: net.sdf1
deploymentTarget:
iOS: "17.0"
createIntermediateGroups: true
settings:
base:
SWIFT_VERSION: "5.9"
TARGETED_DEVICE_FAMILY: "1,2"
CODE_SIGN_STYLE: Automatic
targets:
iPX:
type: application
platform: iOS
sources:
- Sources
- Shared
- Resources/Assets.xcassets
dependencies:
- target: iPXWidgets
info:
path: Resources/Info.plist
properties:
CFBundleDisplayName: iPX
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: "14"
# Playing on with the screen locked. A plist key, not a signed entitlement.
UIBackgroundModes: [audio, fetch, remote-notification]
# The unread badge's refresh while the app is closed (#421).
BGTaskSchedulerPermittedIdentifiers: [net.sdf1.ipx.refresh]
# HTTPS only, so TestFlight need not ask the export-compliance question on every build.
ITSAppUsesNonExemptEncryption: false
UILaunchScreen: {}
UIApplicationSceneManifest:
UIApplicationSupportsMultipleScenes: false
UISceneConfigurations:
UIWindowSceneSessionRoleApplication:
- UISceneConfigurationName: Default Configuration
UISceneDelegateClassName: $(PRODUCT_MODULE_NAME).SceneDelegate
# The car's screen (#420), a scene of its own beside the phone's.
CPTemplateApplicationSceneSessionRoleApplication:
- UISceneConfigurationName: CarPlay
UISceneClassName: CPTemplateApplicationScene
UISceneDelegateClassName: $(PRODUCT_MODULE_NAME).CarPlaySceneDelegate
# Upright only on a phone, where the page's layout is made for portrait; every way on an
# iPad, which also needs all four for Split View and Slide Over.
UISupportedInterfaceOrientations~iphone:
- UIInterfaceOrientationPortrait
UISupportedInterfaceOrientations~ipad:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
# Plain HTTP only for a server on your own network (192.168.1.130:8099); the tunnel is HTTPS.
NSAppTransportSecurity:
NSAllowsLocalNetworking: true
# The page's service worker runs only for these, so iPX opens offline only at them
# (#435): the server, and Cloudflare Access and Authentik, where its sign-in goes. Ten at
# most, and a server not here loses the bridge (WebViewController.makeWebView).
WKAppBoundDomains:
- ipodderx.sdf1.net
- rays-sdf1.cloudflareaccess.com
- authentik.sdf1.net
# The icon's count pushed by ipx (#433). Development here; Xcode makes it production when it
# exports for TestFlight.
entitlements:
path: Resources/iPX.entitlements
properties:
aps-environment: development
# Shared with the widget (#428), which reads what the app last knew from it.
com.apple.security.application-groups: [group.net.sdf1.ipx]
# Granted by Apple on request (2026-11-09); the App ID has it under Additional Capabilities.
com.apple.developer.carplay-audio: true
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipx
MARKETING_VERSION: "0.1.0"
DEVELOPMENT_TEAM: 8743L8D729
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
# The script below writes into the built Info.plist, which the sandbox would refuse.
ENABLE_USER_SCRIPT_SANDBOXING: NO
postBuildScripts:
# A debug build is app-bound to localhost too, so the simulator can test the service
# worker against a page served on the Mac (#435). Never in a release.
- name: App-bound localhost (debug)
basedOnDependencyAnalysis: false
script: |
if [ "$CONFIGURATION" = Debug ]; then
/usr/libexec/PlistBuddy -c "Add :WKAppBoundDomains: string localhost" "$TARGET_BUILD_DIR/$INFOPLIST_PATH"
fi
# The widget (#428): the unread count and the last episode, from what the app writes to the App
# Group. Its build number has to match the app's, or App Store Connect refuses the upload.
iPXWidgets:
type: app-extension
platform: iOS
sources:
- Widgets
- Shared
info:
path: Widgets/Info.plist
properties:
CFBundleDisplayName: iPX
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: "14"
NSExtension:
NSExtensionPointIdentifier: com.apple.widgetkit-extension
entitlements:
path: Widgets/iPXWidgets.entitlements
properties:
com.apple.security.application-groups: [group.net.sdf1.ipx]
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipx.widgets
MARKETING_VERSION: "0.1.0"
DEVELOPMENT_TEAM: 8743L8D729
# Shared/ is built here too, where the app's player does not exist.
SWIFT_ACTIVE_COMPILATION_CONDITIONS: $(inherited) WIDGET
iPXTests:
type: bundle.unit-test
platform: iOS
sources:
- Tests
dependencies:
- target: iPX
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipx.tests
GENERATE_INFOPLIST_FILE: YES
schemes:
iPX:
build:
targets:
iPX: all
iPXTests: [test]
test:
targets:
- iPXTests