Files
vphone-cli/VPhoneExecutable/VPhoneVirtualization/UI/GuestCommunication/VPhoneGuestControlSetupAssistant.swift
T
LakrandClaude Opus 5.5 4da0847af5 Let the VM window skip Setup Assistant on an activated guest
vphoned reports `setup_pending` in /v1/health and serves `setup.status`
and `setup.skip`. Device › Skip Setup Assistant… is enabled while the
guest reports it pending, and asks before it runs.

SpringBoard decides whether to run Setup once, when it starts. It does
while `SetupDone` in com.apple.purplebuddy is not true, and runs the flow
shown after a software update while `SetupVersion` is below
SetupAssistant.framework's BYBuddyIOSCurrentVersion (an int32, 11 on 26.4
and 27.0). Writing the keys while Setup is on screen does not dismiss it,
and killing Setup only makes SpringBoard start it again. So the skip
writes `SetupDone`, `SetupFinishedAllSteps` and `SetupVersion` through
cfprefsd for user mobile, then restarts SpringBoard. With every other key
in the domain removed, those three still reach the Home Screen, and no
later panes appear.

The experiments are in Research/Guest/setup_assistant_skip.md, including
how to send a guest back to Setup for testing. MCInstall's
SetCloudConfiguration, which pymobiledevice3, go-ios and cfgutil use,
works only on an erased device, so it does not fit here.

Verified on test-26.4 with this bundle: after deleting `SetupDone`,
Setup's hello screen appeared and setup.status reported pending true and
running true. setup.skip without force was refused. With force it
returned pending false, SpringBoard restarted and unlocked to the Home
Screen. Deleting `SetupVersion` then skipping also reached the Home
Screen. Afterwards the domain matched its state before the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 19:36:11 +09:00

17 lines
613 B
Swift

import Foundation
// MARK: - Setup Assistant
/// Skipping Setup Assistant on a guest that is already activated. vphoned
/// marks setup finished for the guest's iOS version and restarts
/// SpringBoard, which then starts at the Lock Screen instead of Setup.
/// `isSetupAssistantPending` follows on the next health probe.
extension VPhoneGuestControl {
func skipSetupAssistant() async throws {
guard guestCapabilities.contains("setup_skip") else {
throw ControlError.unsupportedCapability("setup_skip")
}
_ = try await call("setup.skip", params: ["force": true])
}
}