From cf808483e0e92ac50dc036fe3146be93e12a3b3e Mon Sep 17 00:00:00 2001 From: Talon Date: Mon, 21 Sep 2026 03:10:25 +0200 Subject: [PATCH] Fix physical iOS device deployment --- .../apple/VoiceCat.iOS/VoiceCat.iOS.csproj | 1 + clients/apple/build-ios-device.sh | 7 +++-- docs/ios-deploy.md | 29 +++++++++++++++++-- .../PublishServerScriptTests.cs | 14 +++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clients/apple/VoiceCat.iOS/VoiceCat.iOS.csproj b/clients/apple/VoiceCat.iOS/VoiceCat.iOS.csproj index 2835b5d..606854d 100644 --- a/clients/apple/VoiceCat.iOS/VoiceCat.iOS.csproj +++ b/clients/apple/VoiceCat.iOS/VoiceCat.iOS.csproj @@ -15,6 +15,7 @@ Info.plist full $(NoWarn);XCODE_27_0_PREVIEW + $(WarningsNotAsErrors);IL2104 true iossimulator-arm64 ios-arm64 diff --git a/clients/apple/build-ios-device.sh b/clients/apple/build-ios-device.sh index 6433989..2bad783 100755 --- a/clients/apple/build-ios-device.sh +++ b/clients/apple/build-ios-device.sh @@ -21,9 +21,12 @@ done project="$root/clients/apple/VoiceCat.iOS/VoiceCat.iOS.csproj" "$root/scripts/build-native-ios.sh" "$dotnet_host" restore "$project" --locked-mode -p:VoiceCatIosStatic=true -"$dotnet_host" restore "$project" --locked-mode -r ios-arm64 --no-dependencies +device_lock="obj/packages.device.lock.json" +"$dotnet_host" restore "$project" -r ios-arm64 --no-dependencies \ + -p:RestorePackagesWithLockFile=true -p:RestoreLockedMode=false -p:NuGetLockFilePath="$device_lock" -set -- build "$project" -c "$configuration" -r ios-arm64 --no-restore -m:1 +set -- build "$project" -c "$configuration" -r ios-arm64 --no-restore -m:1 \ + -p:NuGetLockFilePath="$device_lock" if [ -n "${VOICECAT_CODESIGN_KEY:-}" ]; then set -- "$@" -p:CodesignKey="$VOICECAT_CODESIGN_KEY"; fi if [ -n "${VOICECAT_CODESIGN_PROVISION:-}" ]; then set -- "$@" -p:CodesignProvision="$VOICECAT_CODESIGN_PROVISION"; fi "$dotnet_host" "$@" diff --git a/docs/ios-deploy.md b/docs/ios-deploy.md index 03c6d0a..28c951f 100644 --- a/docs/ios-deploy.md +++ b/docs/ios-deploy.md @@ -35,6 +35,16 @@ clients/apple/deploy-ios-device.sh \ The verified bundle is staged at `dist/ios-managed-device/VoiceCat.iOS.app`. Omit `--no-build` to build and deploy in one command. Add `--console` to attach the launch to device logs. +The device build first validates the checked-in managed dependency locks, then generates +`obj/packages.device.lock.json` for the single `ios-arm64` app restore. This keeps a preceding +simulator restore from making the device build fail with `NU1004`; root-level generated lock +files under `clients/apple/VoiceCat.iOS` are not inputs to the device build. + +.NET's iOS linker reports `IL2104` aggregate warnings for the pinned BouncyCastle and +Google.Protobuf assemblies. The iOS project leaves those aggregate warnings visible but does not +promote them to errors. All other warnings remain subject to the repository-wide +`TreatWarningsAsErrors` policy. + Confirm that the process stayed alive: ```bash @@ -81,15 +91,30 @@ them after runtime changes, then verify that dependency versions did not change: --force-evaluate ``` +The device script should not require this command merely because a simulator was built first. If +it does, confirm that it is using `obj/packages.device.lock.json` for its `ios-arm64` restore. + +### Command-line signing identity appears missing + +Xcode being signed in and `security find-identity -v -p codesigning` returning no identities can +be a shell sandbox or keychain-access artifact. Run the identity check from an ordinary Terminal +session before changing certificates. A successful build prints the selected Apple Development +identity, provisioning profile, bundle ID, and app ID before linking. + ### Developer disk image cannot be mounted CoreDevice errors 10003 or 12040 mean the phone locked. Unlock it, keep the display awake, and rerun deployment with `--no-build`. +CoreDevice can also install the app successfully and then reject only the launch with error +10002 and reason `Locked`. In that case, unlock the phone and rerun the same `--no-build` +deployment; rebuilding is unnecessary. Occasional CoreDeviceService initialization timeouts while +listing devices or processes do not imply that an already-confirmed install or launch failed. + ## Verified hardware result -On 2026-09-19, the Debug build completed with .NET 10.0.401 and Xcode 27.0. The host and +On 2026-09-21, the Debug build completed with .NET 10.0.401 and Xcode 27.0. The host and ReplayKit extension were signed under team `FJV8L966W4`, installed wirelessly on Talon's iPhone, -launched as `me.iamtalon.voicecat`, and remained in the device process list. Audio, +and launched as `me.iamtalon.voicecat`; the running UI was confirmed on the device. Audio, background/lock behavior, Bluetooth, ReplayKit, ScreenCaptureKit, and VoiceOver remain separate manual hardware gates. diff --git a/tests/VoiceCat.Tests/PublishServerScriptTests.cs b/tests/VoiceCat.Tests/PublishServerScriptTests.cs index 53b01a3..87992ba 100644 --- a/tests/VoiceCat.Tests/PublishServerScriptTests.cs +++ b/tests/VoiceCat.Tests/PublishServerScriptTests.cs @@ -39,6 +39,20 @@ public class PublishServerScriptTests Assert.Contains("com.apple.security.cs.allow-jit", entitlements); } + [Fact] + public async Task IosDeviceBuildUsesAnIntermediateDeviceLockAndScopesKnownTrimWarnings() + { + string root = FindRoot(); + string script = await File.ReadAllTextAsync(Path.Combine(root, "clients", "apple", "build-ios-device.sh")); + string project = await File.ReadAllTextAsync(Path.Combine( + root, "clients", "apple", "VoiceCat.iOS", "VoiceCat.iOS.csproj")); + + Assert.Contains("NuGetLockFilePath=\"$device_lock\"", script); + Assert.Contains("RestoreLockedMode=false", script); + Assert.Contains("$(WarningsNotAsErrors);IL2104", project); + Assert.DoesNotContain("false", project); + } + [Fact] public async Task DefaultPublishTargetsWindowsAndLinuxWhileRuntimeCanSelectOne() {