macOS Sequoia 에서 iPhone Duo 시뮬레이터 실행하기

· Midworld Kim

목차

애플이 공개한 리퀴드 글래스는 내 취향에 너무 맞지 않았다. 그래서 나는 내 맥도 세쿼이아에서 업그레이드하지 않았고, 아이폰도 18 버전을 그대로 사용하고 있다. 개인적으로 잘 보이지 않는 것과 쓰잘데기 없는 연산 부하를 싫어하는데 리퀴드 글래스는 그걸 다 만족한다.

이번에 아이폰 듀오가 나오면서 새로운 폼팩터에 대응해야 했는데, 이런, 내 맥 세쿼이아에서는 시뮬레이터가 켜지지 않는다. 예약한 아이폰 듀오도 내년이나 되어야 배송한다고 한다. 그래서 AI 의 도움을 받아 어떻게든 아이폰 듀오 시뮬레이터를 내 맥에서 띄우고자 했다. 결론은 필요한 모든 기능이 동작하고 있으며, 애플의 강제 버전업 종용이 AI 를 통해서 (물론 기존에도 이런 강제를 너무 싫어했던 사람들이 한땀한땀 업그레이드하지 않고 사용하는 레시피들을 공개하였으며 나는 그들을 존경한다.) 점점 힘을 잃게 되지 않을까 하는 생각을 하면서도 맥을 아이패드처럼 만들어버리지 않을까 하는 걱정도 동시에 하게 된다.

먼저 맥 세쿼이아에서 Xcode 27.1 을 다운로드 받고 거기에 포함된 Device Hub 와 DeviceKit 를 수정해 사용했다. Xcode 27.1 의 공식 지원 OS 는 macOS 타호 26.6 이상이므로, 세쿼이아에서의 실행은 공식 지원 범위 밖이다. Apple 시스템 요구사항

테스트 환경 #

항목사용한 버전
컴퓨터Apple M1 Max, Apple Silicon 네이티브 실행
OSSequoia 15.7.7 / 24G720
시뮬레이터 원본Xcode 27.1 / 27A9275
호환 라이브러리 빌드Xcode 26.3 / 17C529, 설치본의 Apple Swift 6.2.4
런타임iOS 27.1 / 24A94232 / arm64
시뮬레이터 기기 타입com.apple.CoreSimulator.SimDeviceType.iPhone-Duo

화면과 동작 확인 #

닫힌 상태 #

닫힌 상태에서는 바깥 화면이 표시되고 클릭 입력이 동작한다. 안전 영역 및 이번에 새로 돌려주는 카메라 영역 API 도 작동한다.

펼친 상태 #

완전히 펼치면 안쪽 화면 전체가 표시된다. 테스트 앱도 안쪽 화면에서 표시되며 멀티태스킹 등도 동작한다.

부분 펼침 #

부분 펼침 상태에서는 전환 애니메이션 (흐린 효과) 이 잠깐 나오다가 꺼지고 내용이 표시된다. 뭔가 계속 흐린 상태로 유지되어야 하는 거 같은데 작동에는 문제 없으니 무시했다.

macOS Sequoia 에서 실행한 iPhone Duo 시뮬레이터의 부분 펼침 상태

  • 펼친 상태에서 90도 회전 가능
  • 닫힌 상태의 회전과 정방향 복귀 가능
  • 실제 좌표를 클릭해 테스트 앱 작동 모두 가능
  • Device Hub를 종료하고 디버거 없이 다시 실행해도 개조가 유지됨

개조한 부분 #

앱 내용의 최소 macOS 버전만 낮춰서는 동작하지 않았다. 빠진 API, 화면 연결의 수명, 아이폰 듀오 전용 플러그인과 화면 합성 문제를 순서대로 수정했다.

세쿼이아에 없는 API #

DeviceKit 이 사용하는 Observation.Observations 등 일부 API가 호스트에 없다. Observation 백포트와 Foundation·Swift runtime·Reality·SwiftUI·Quartz 어댑터를 포함한 호환 라이브러리 여섯 개를 만들고, 필요한 참조를 연결했다.

Observation 백포트는 Archdoog/ObservationsKit 와 Swift 프로젝트 의 구현을 기반으로 했다.

아이폰 듀오 플러그인에서는 새 SwiftUI task modifier 로 초기화한 뒤 구형 타입의 metadata 와 witness 를 선택하는 경로도 맞춰야 한다. 필요한 심볼 별칭이 빠지면 빌드와 서명 검사를 통과해도 플러그인을 로드할 때 실패한다.

크래시 없이 시뮬레이터가 켜졌으나 #

시뮬레이터가 켜진 후에 화면이 보였다가 바로 사라져버렸다. 화면 연결용 작업의 Task.sleep(nanoseconds: UInt64.max) 가 거의 즉시 반환되었는데, 대기 인자를 Int64.max 로 바꾼 뒤에는 연결이 유지됐다.

기기 외형에 가려지는 안쪽 화면 #

화면을 계속 나오게 한 후에도 기기 외부 화면만 보이고 안쪽 영상이 제대로 안 나왔다 (일부가 가려진 느낌). 바깥·안쪽 display provider 와 화면 뷰가 만들어져 있는 것을 확인하고, 화면 호스트의 상위 합성 그룹을 앞으로 올렸더니 영상 전체가 나타났다.

보정은 이 패치 앱이 macOS 15 에서 실행될 때, 아이폰 듀오 플러그인의 화면 호스트에만 적용했으므로 다른 기기에는 영향이 없다. mesh, framebuffer 크기, 화면 변환과 입력 라우팅은 유지해도 문제 없었다.

빌드와 기존 환경 영향 주의점 #

수정 내용을 Python 빌드 스크립트와 Swift·Objective-C·C 소스로 정리했다. 스크립트는 CPU 환경, Xcode·Swift 버전과 원본 바이너리의 SHA-256을 확인하고, 원본 명령어의 바이트가 예상과 일치할 때에만 사본에 패치를 적용한다.

재빌드에서는 호환 라이브러리 여섯 개를 소스부터 만든다. 빌드 스크립트는 설치된 Xcode 나 시스템 프레임워크를 수정하지 않는다. 다만 사전 준비에 사용한 xcodebuild -runFirstLaunch 는 /Library 의 공용 개발 구성요소를 업데이트한다. 따라서 기존 Xcode 에도 영향을 줄 수 있으므로 해당 부분의 백업을 추천한다. 나는 별 문제 없이 구버전 Xcode 도 사용할 수 있었다.

개조된 앱은 원본 Xcode 의 일부 프레임워크를 절대 경로로 참조하므로 패치한 후 복제해서 쓰지 않고 새 환경에서는 새로 패치하는 게 좋겠다. SIP, Gatekeeper 는 건드리지 않아도 문제 없었다. 개조 앱에는 호환 라이브러리를 로드하기 위한 라이브러리 검증 예외를 추가했다.

필요한 파일과 패치 명령어 #

내가 쓴 파일과 소스는 아래와 같다. Device Hub 와 DeviceKit 은 Xcode 27.1 안에 들어 있어서 따로 받을 필요는 없다.

파일받는 곳과 버전
Xcode 27.1Apple Developer Downloads 에서 정식 버전의 .xip 다운로드. 빌드 번호는 27A9275
Xcode 26.3Apple Developer Downloads 에서 다운로드. 빌드 번호는 17C529. 호환 라이브러리를 컴파일하는 데 사용하며, 이미 설치돼 있으면 다시 받을 필요 없음
iOS 27.1 시뮬레이터 런타임아래 명령으로 다운로드. 내가 테스트한 버전은 24A94232, arm64
패치 소스GitHub 저장소. README, 빌드 스크립트와 호환 소스가 들어 있음

Apple 계정 로그인이 필요할 수 있다. Python 3.9 이상과 수십 GB 의 여유 공간도 필요하며, 런타임 다운로드만 약 8 GB 이다.

소스 받고 경로 지정 #

Xcode 의 .xip 을 풀고, 26.3 은 /Applications/Xcode.app, 27.1 은 /Applications/Xcode-27.1.app 에 둔다. 기존 Xcode 를 덮어쓰지 않도록 이름으로 구분한다. 아래 명령은 내가 쓴 경로 기준이므로 다른 위치에 뒀다면 바꿔야 한다. 터미널은 macOS 기본 zsh 기준이다.

패치 소스는 GitHub 에서 받는다.

export DUO_XCODE='/Applications/Xcode-27.1.app'
export DUO_COMPILER_XCODE='/Applications/Xcode.app'
export DUO_RECIPE="$HOME/Developer/iphone-duo-simulator-sequoia"
export DUO_WORK="$HOME/Developer/Duo-Sequoia"
export DUO_OUTPUT="$DUO_WORK/build-01"
mkdir -p "$DUO_WORK"

git clone https://github.com/midworld/iphone-duo-simulator-sequoia.git "$DUO_RECIPE"

python3 --version
DEVELOPER_DIR="$DUO_COMPILER_XCODE/Contents/Developer" \
  /usr/bin/xcrun swiftc --version

Swift 는 6.2.3, 6.2.4 에서 확인했는데 아마 비슷한 버전이면 문제 없을 것 같다 (다른 버전은 스크립트에서 허용되게 수정해야 함). 호환 라이브러리는 소스에서 새로 컴파일하므로 이전 결과물과 바이트까지 같을 필요는 없다. 대신 ABI 와 필요한 심볼은 맞아야 한다. Swift 라이브러리 호환성 설명

공용 구성요소와 런타임 설치 #

공용 구성요소 설치를 처음 한다면 README 의 백업 절차부터 진행한다. 그 다음 라이선스를 확인하고 구성요소를 설치한다. 이미 완료한 환경에서는 -checkFirstLaunchStatus 로 상태를 확인하면 된다.

sudo env DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcodebuild -license
sudo env DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcodebuild -runFirstLaunch
DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcodebuild -checkFirstLaunchStatus

iOS 27.1 의 Apple Silicon 용 런타임을 받고 기기 타입도 확인한다.

DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcodebuild -downloadPlatform iOS -buildVersion 27.1 \
  -architectureVariant arm64
DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcrun simctl list runtimes
DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcrun simctl list devicetypes

목록에 iOS 27.1 / 24A94232 와 iPhone Duo 가 있는지 확인한다.

패치 앱 만들기 #

실제로 패치하는 명령은 아래와 같다. 버전과 원본 해시를 검사하고, 사본을 만들어 패치한 뒤 서명한다.

python3 "$DUO_RECIPE/tools/build_devicehub.py" \
  --xcode "$DUO_XCODE" \
  --compiler-xcode "$DUO_COMPILER_XCODE" \
  --output "$DUO_OUTPUT"

출력 폴더는 새 폴더여야 한다. 실패하거나 다시 빌드한다면 export DUO_OUTPUT="$DUO_WORK/build-02" 처럼 새 경로를 지정한 뒤 빌드 명령을 다시 실행하면 된다. 빌드 결과는 $DUO_OUTPUT/DeviceHub-Duo.app 이다.

아이폰 듀오 기기 생성 및 실행 #

아래 명령으로 아이폰 듀오 시뮬레이터 기기를 생성하고 부팅한다.

DUO_UDID=$(DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcrun simctl create 'iPhone Duo' \
  com.apple.CoreSimulator.SimDeviceType.iPhone-Duo \
  com.apple.CoreSimulator.SimRuntime.iOS-27-1)
DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcrun simctl boot "$DUO_UDID"
DEVELOPER_DIR="$DUO_XCODE/Contents/Developer" \
  /usr/bin/xcrun simctl bootstatus "$DUO_UDID" -b
open "$DUO_OUTPUT/DeviceHub-Duo.app"

Device Hub 에서 아이폰 듀오를 선택하고 Start 를 누른다. Closed, Partially Open, Open 과 회전 버튼이 동작하는지 확인하면 된다.

재현 스크립트 #

위 패치를 재현할 수 있는 빌드 도구와 소스를 GitHub 저장소 에 올렸다. Xcode 와 시뮬레이터 런타임은 Apple 에서 별도로 받아야 한다.

빌드 스크립트가 자동화하는 범위는 Device Hub 이며, Xcode IDE 전체 패치는 README 의 별도 항목에 참고 기록으로 남겼다. 내가 해보니까 화면 가장자리에 리퀴드 글래스 UI 버튼들 아래로 깔려야 하는 본문 코드가 그냥 버튼이랑 겹쳐서 나오는 문제가 있다. 버튼 누르는 것이나 기능에는 별 문제가 없었다.

위 명령을 직접 수행하거나, 각자가 쓰는 AI 도구에게 저장소를 참고해서 진행하라고 하면 된다. 나처럼 구버전 macOS 에서 아이폰 듀오를 테스트하고 싶은 사람에게 도움이 되길 바란다.