개발 도구

Godot 4.6 iOS 플러그인 수동 통합 체크리스트 — Xcode 배선 8단계

Godot 4.6 iOS 플러그인 수동 통합 체크리스트 — Xcode 배선 8단계

Godot iOS export 후 매번 초기화되는 Xcode 프로젝트를 재배선하는 8단계 체크리스트. dummy.cpp 등록부터 서명까지 재export 직후 반복해야 하는 작업을 정리했다.

Godot 4.6 iOS 플러그인 수동 통합 체크리스트 — Xcode 배선 8단계

뚝딱 타일 맞추기 iOS 빌드 기준. Godot 은 Godot export → Xcode 순서로 동작하며,
재export 할 때마다 dummy.cpp · project.pbxproj · Info.plist · ttukttak.entitlements 가 통째로 초기화된다.
따라서 아래 배선은 재export 직후 매번 다시 해야 한다. (버전 예: 1.0.7 / build 1)

🤖 스크립트 자동 — ①② (entitlements 포함) 는 재export 배선 스크립트가 자동으로 채운다.
🛠️ Xcode 수동 — ③~⑧ 은 재export 직후 매번 Xcode GUI 에서 직접 배선해야 한다.

배선 순서:
🤖 ① dummy.cpp 등록(소스) → 🤖 ② Info.plist 패치 → 🛠️ ③ 프레임워크 링크 → 🛠️ ④ Capabilities →
🛠️ ⑤ 링커 플래그 → 🛠️ ⑥ godot 제거 → 🛠️ ⑦ SPM → 🛠️ ⑧ 서명 → 검증


① dummy.cpp 플러그인 등록 (소스 — ttukttak/dummy.cpp) · 🤖 스크립트 자동

재export 배선 스크립트가 등록 호출부를 아래처럼 자동으로 채운다. (스크립트 적용 결과 확인용 — 사람이 직접 편집할 필요는 없다)

// Exported Plugins
extern void admob_plugin_init();
extern void admob_plugin_deinit();
extern void register_inappstore_types();
extern void unregister_inappstore_types();
extern void register_gamecenter_types();
extern void unregister_gamecenter_types();
extern void register_review_types();
extern void unregister_review_types();
extern void register_notify_types();
extern void unregister_notify_types();
extern void register_deeplink_types();
extern void unregister_deeplink_types();

// Use Plugins
void godot_apple_embedded_plugins_initialize() {
	admob_plugin_init();
	register_inappstore_types();
	register_gamecenter_types();
	register_review_types();
	register_notify_types();
	register_deeplink_types();
}

void godot_apple_embedded_plugins_deinitialize() {
	admob_plugin_deinit();
	unregister_inappstore_types();
	unregister_gamecenter_types();
	unregister_review_types();
	unregister_notify_types();
	unregister_deeplink_types();
}

⚠️ AdMob 은 debug/release xcframework 가 분리돼 있으니 둘 중 하나만 링크할 것(둘 다 넣으면 admob_plugin_init 중복 심볼). 현 정본은 release 체인.


② Info.plist 패치 (권장) · 🤖 스크립트 자동

  • UIRequiresFullScreen 제거 + iPad 전방향 대응 — Apple 의 '전화면 강제 폐지 / 전방향 필수화' 예고 대비.
  • 배선 스크립트가 ttukttak.entitlementscom.apple.developer.associated-domains(applinks:clayve.co.kr)도 함께 재주입한다(유니버설 링크 딥링크, ④ Capabilities 와 짝).

③ 프레임워크 링크 (타깃 → General → Frameworks, Libraries, and Embedded Content) · 🛠️ Xcode 수동

이 목록에 항목을 추가하는 방법은 두 가지이며, 추가 방식에 따라 임베드 동작이 다르다.

A. +Add Other… → Add Files… 로 직접 추가 (전부 Do Not Embed)

로컬 파일시스템에서 xcframework/바이너리를 직접 선택해서 추가하는 항목들 — 알파벳순:

프레임워크 용도 임베드
AdmobPlugin.release.xcframework 광고 Do Not Embed
deeplink.xcframework 유니버설 링크 딥링크 (continueUserActivity 캡처 → DokkaebiDeepLink) Do Not Embed
gamecenter.xcframework Game Center(세이브 동기화 신원) Do Not Embed
inappstore.xcframework (release 슬라이스) 인앱결제 Do Not Embed
MoltenVK.xcframework 엔진 라이브러리(libgodot.a)의 Vulkan 심볼 해소용 — 링크-타임 의존성, 런타임 미사용 Do Not Embed
notify.xcframework 로컬 알림 Do Not Embed
review.xcframework 인앱 리뷰 + 동작 줄이기(Reduced Motion) 감지 Do Not Embed

godot 항목도 재export 시 이 통합 리스트에 자동으로 같이 생성되지만 링크 대상이 아니다 — ⑥ 에서 제거한다.
deeplink.xcframework신규 시스템 프레임워크가 불필요(UIKit·objc 런타임만 — 이미 링크됨). review 와 동일하게 Do Not Embed. ④ Associated Domains capability 와 짝을 이룬다.

★★MoltenVK.xcframework 는 Godot export 가 이미 자동 링크하므로(pbxproj 에 포함) 보통 손댈 일이 없다 — 제거하지 말 것. 이 앱은 gl_compatibility(OpenGL ES) 렌더러라 MoltenVK(Vulkan→Metal 변환 레이어)를 런타임에 전혀 쓰지 않는다. 그런데도 링크가 필요한 이유는, 공식 프리컴파일 엔진 라이브러리 libgodot.aVulkan 백엔드까지 함께 포함해 빌드돼 있어 외부 Vulkan API 심볼 약 127개(vkCreateInstance·vkAllocateMemory 등)를 미정의로 참조하기 때문이다. ⑤ -force_load 플래그가 아카이브의 모든 오브젝트를 강제 로드하므로 런타임에 안 타는 Vulkan 심볼까지 링크에 포함되고, 그 심볼들을 정의하는 것이 MoltenVK 다. 안 링크하면 undefined symbol 링커 에러로 빌드가 실패한다.

B. +Filter 검색어로 추가 (시스템 프레임워크, 자동 Do Not Embed)

Apple 시스템 프레임워크는 Filter 검색으로 찾아 선택하면 임베드 설정이 자동으로 Do Not Embed 로 고정된다 — 시스템 프레임워크는 iOS 에 이미 포함돼 있어 임베드 자체가 불가능하기 때문. 추가로 임베드 값을 바꿀 필요 없음.

프레임워크 용도
GameKit.framework Game Center 시스템
StoreKit.framework IAP 동작 전제
UserNotifications.framework 알림 시스템 (★review 와 달리 신규 링크 필요)

④ Capabilities (Signing & Capabilities) · 🛠️ Xcode 수동

재export 는 SystemCapabilities 를 빈 값으로 초기화하므로 다시 추가한다.

  • Game Center — 세이브 동기화 신원(gamecenter).
  • In-App Purchase+ Capability 로 추가(Apple Developer 포털 App ID 동기화용). StoreKit 링크(③)로 기능은 이미 충족되지만, 서명 동기화를 위해 GUI 에서 켠다.
  • Associated Domains+ Capability 로 추가 후 도메인에 applinks:clayve.co.kr 입력(유니버설 링크 딥링크, deeplink 플러그인과 짝).
    • Apple Developer 포털에서도 App ID(kr.co.clayve.ttukttak)의 Associated Domains 를 활성화(1회)해야 프로비저닝 프로파일에 반영된다. 안 하면 서명은 되나 유니버설 링크가 동작하지 않음.
    • entitlements(ttukttak.entitlements)의 com.apple.developer.associated-domains 는 재export 배선 스크립트가 자동 재주입 — Capability 는 서명·포털 동기화용.
    • 검증: 도메인 루트에 AASA(https://clayve.co.kr/.well-known/apple-app-site-association, application/json)가 이미 서빙 중이어야 함.

pbxproj 를 손으로 편집하지 말 것 — Xcode GUI 가 포털 동기화까지 처리한다.


⑤ Other Linker Flags (Build Settings — Debug · Release 둘 다) · 🛠️ Xcode 수동

+ 버튼으로 아래 4개 항목을 각각 별도 행으로 추가한다 — 공백 포함 통짜 문자열 하나로 넣으면 -force_load 가 인자를 받지 못한다. 버튼을 눌러 항목별로 복사한 뒤 각 행에 붙여넣는다.

-ObjC
-ld_classic
-force_load
$(PROJECT_DIR)/ttukttak.xcframework/ios-arm64/libgodot.a

이 단계가 없으면 링크 자체가 안 된다.


⑥ Link Binary 정리 · 🛠️ Xcode 수동

  • Link Binary With Libraries 목록에서 godot 항목 제거.

⑦ Swift Package Manager (SPM) · 🛠️ Xcode 수동

  • GoogleMobileAds 12.14.0
  • GoogleUserMessagingPlatform 3.1.0

⑧ 서명 · 🛠️ Xcode 수동

목적 방법
기기 테스트(Run) 자동 서명(Development), 본인 Team ID
제출(Archive) Distribution 프로파일 + Apple Distribution, Product → Archive

배포 프로파일로는 기기에 직접 설치되지 않는다(MIInstaller 0xe800801f). 실기기 QA 는 Development 자동 서명으로.


배선 후 검증

빌드 전, 자동 점검으로 배선 누락을 잡는다:

bash .claude/skills/release-check/release_check.sh --fast
  • dummy.cpp 플러그인 등록 FAIL → PASS 로 바뀌는지
  • review.xcframework / notify.xcframework 미링크 WARN 이 해소됐는지
  • 엔진↔플러그인 ABI 체인 일치(char const*, release)

실기기 QA 핵심

  • 동작 줄이기(Reduced Motion): 설정 ▸ 손쉬운 사용 ▸ 동작 줄이기 ON → 흔들림·폭죽·화면 셰이크가 축약되고, 결과·콤보·보상 표시는 유지(정보 손실 0). OFF → 기존 연출 100%.
    • 이 실기기 확인을 통과한 뒤에만 App Store Connect 접근성 섹션에 'Reduced Motion 지원' 라벨을 표기한다.
  • 인앱결제 샌드박스, 알림 도착, 광고 없이 소프트락 0 도 함께 확인.

재export 후 반복되는 iOS 수동 통합 단계를 공개용으로 정리한 체크리스트입니다.