iOS Development Workflow
Architecture
Build happens on ch405 (remote Mac), install/run happens on local machine (where device is plugged in). Communication via reverse SSH tunnel set up by sproject.
Key Tools (~/.bin/)
| Command | Description |
|---|---|
sproject <project> | SSH to ch405, sets up reverse tunnel, opens tmux |
srun-local phy <project> | From ch405 SSH: build remote, install on local physical device |
srun-local sim <project> | From ch405 SSH: build remote, run on local simulator |
srun-phy <project> | Build + install + launch on physical device (local only) |
srun-sim <project> | Build + install + launch on simulator (local only) |
_srun-build <project> <type> | Internal: builds on ch405, copies .app to local /tmp |
Typical Workflow
# From local machine: sproject local_events # SSH to ch405 with reverse tunnel # From ch405 SSH session: srun-local phy local_events # Build on ch405, install on local device srun-local sim local_events # Build on ch405, run on local simulator
Device UUID Configuration
Device UUID is configured in 3 places (all must match):
- •
~/.bin/srun-phy- default inDEVICE_UUID="${IOS_DEVICE_UUID:-<uuid>}" - •
<project>/.ios-device-uuid- read bybin/install-ios-device - •
<project>/bin/run-ios-device- default fallback
To find device UUID: xcrun devicectl list devices (on machine where device is plugged in).
The UDID (different from CoreDevice UUID) is visible in Xcode > Window > Devices and Simulators. Both are needed:
- •CoreDevice Identifier (format
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX): used byxcrun devicectl - •UDID (format
00008140-XXXXXXXXXXXXXXXX): must be registered on developer.apple.com
Code Signing & Keychain
ch405 uses a dedicated CI keychain:
security unlock-keychain -p ci ~/Library/Keychains/ci.keychain-db
_srun-build handles this automatically. For manual builds via SSH:
security list-keychains -d user -s ~/Library/Keychains/ci.keychain-db ~/Library/Keychains/login.keychain-db security unlock-keychain -p ci ~/Library/Keychains/ci.keychain-db
Without unlocking the keychain, codesign fails with errSecInternalComponent.
Provisioning Profiles
Profiles are cached in ~/Library/Developer/Xcode/UserData/Provisioning Profiles/.
Adding a New Device
- •Get UDID from Xcode (Window > Devices and Simulators) on the machine where device is connected
- •Add UDID on developer.apple.com/account/resources/devices/list
- •On ch405, delete cached profiles:
bash
rm ~/Library/Developer/Xcode/UserData/Provisioning\ Profiles/*.mobileprovision
- •In Xcode on ch405, open project, toggle "Automatically manage signing" off/on for each target (Morris, MorrisShareExtension) to force profile regeneration
- •Clean and rebuild:
bash
rm -rf ~/Library/Developer/Xcode/DerivedData/Morris-* security unlock-keychain -p ci ~/Library/Keychains/ci.keychain-db xcodebuild -project ios/Morris.xcodeproj -scheme Morris -allowProvisioningUpdates \ -destination "generic/platform=iOS" -configuration Debug CODE_SIGN_STYLE=Automatic build
- •Update device UUID in the 3 config locations (see above)
Verifying Profiles
Check which devices are in a profile:
security cms -D -i "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/<uuid>.mobileprovision" | grep -A 10 "ProvisionedDevices"
Common Error
This provisioning profile cannot be installed on this device = device UDID not in the embedded profile. Follow "Adding a New Device" steps above.
Build Commands (on ch405 directly)
./bin/build-ios # Build for simulator ./bin/build-ios device # Build for physical device ./bin/run-ios-device # Build + install + run on device (device must be local)