
얼마 전에 KMP 공통 모듈에 iOS 팀 Swift 라이브러리를 SwiftPM 한 줄로 걸었는데요. 빌드는 초록불인데 코틀린 쪽 자동완성엔 심볼이 하나도 안 뜨더라고요. 로그를 삼십 분 넘게 뒤졌습니다.
dependencies 한 줄로 3년째 쓰던 Swift 라이브러리가 그대로 붙을 줄 알았는데, 빌드만 통과하고 코틀린 쪽엔 심볼이 하나도 안 떴습니다. 왜 안 붙는지, 어디서 깨지는지 순서대로 풀어볼게요.
브릿지 파일 네 개를 손으로 짜던 KMP iOS 라이브러리 공유
코틀린(Kotlin) 2.4 이전에는 iOS 전용 SwiftPM 라이브러리를 공통 모듈에서 쓰려면 손이 많이 갔습니다. Package.swift, 헤더 .h, module.modulemap, 그리고 .def 파일까지 네 개를 수동으로 맞물려야 했거든요.
이게 하나만 어긋나도 링크가 통째로 실패합니다. 날짜 포맷이나 결제 SDK처럼 iOS 팀이 오래 굴린 라이브러리를 당겨 쓰려다가, 브릿지 세팅에만 반나절씩 날리는 일이 반복됐어요.
그래서 "이제 그냥 의존성 한 줄로 그대로 붙는다"는 기대가 생기는 게 자연스러운데요. 문제는 그 "그대로"가 생각보다 좁은 조건에서만 성립한다는 점입니다.

KMP SwiftPM 의존성을 Gradle에서 선언하는 Kotlin 2.4 문법
코틀린 2.4부터는 KMP Gradle 플러그인에서 SwiftPM 의존성을 직접 선언할 수 있게 됐습니다. 정확히는 플러그인 2.4.0 이상이 필요한데, 초기엔 RC·Beta 계열로 풀려서 버전 표기가 릴리스마다 조금씩 달라요. 도입 전에 공식 릴리스 노트를 다시 확인하시는 게 안전합니다.
애플(Apple) 타깃에 SwiftPM 의존을 선언하면, 해당 패키지가 노출한 Objective-C API를 코틀린으로 import 할 수 있게 됩니다. 로컬 패키지든 원격 패키지든 DSL로 지정하는 구조예요.
여기서 의외로 반가운 건 전이 의존성 자동 처리입니다. 하위 모듈에만 SwiftPM 의존을 걸어놔도, 상위 테스트나 프레임워크를 링크할 때 필요한 머신 코드를 플러그인이 알아서 챙겨준다고 해요. 멀티모듈 세팅에서 .def를 층층이 복사하며 삽질하던 걸 크게 줄여주는 지점이더라고요.
빌드가 통과해도 심볼이 안 뜨는 "그대로"의 함정
여기가 제가 삼십 분을 태운 자리입니다. 핵심은 이거예요. Kotlin/Native가 직접 알아듣는 언어는 C와 Objective-C뿐이라는 점입니다. Swift와는 직접 상호운용이 안 됩니다.
Swift는 안정된 ABI도, 자동으로 노출되는 헤더도 없거든요. 그래서 @objc가 붙거나 NSObject를 상속해서 Objective-C 호환 표면을 내놓은 API만 코틀린 쪽에 나타납니다. 제가 걸었던 라이브러리는 값 타입과 제네릭, async/await 중심의 순수 Swift였고, 그래서 심볼이 정확히 0개였던 거였어요.
정리하면 이렇게 갈립니다.
- Objective-C 호환 API(
@objc/NSObject노출)가 많은 라이브러리 → 의존성 선언만으로 상당 부분 그대로 붙습니다. - 순수 Swift(value type, 제네릭, async/await, SwiftUI) 중심 → 심볼이 안 뜨고, Objective-C 브릿지 래퍼를 직접 짜야 합니다.
재작성을 피하려다 오히려 브릿지를 다 짜게 되는 역설이 여기서 생겨요. 그래서 붙이기 전에 그 라이브러리의 Objective-C 노출 비중부터 확인하시는 걸 권합니다. 순수 Swift 비중이 높다면, 제 생각엔 억지로 브릿지를 얹기보다 로직을 KMP 공통 코드로 재작성하는 쪽이 장기 유지보수엔 더 나아 보여요.

cinterop·Swift export와 SwiftPM import가 다루는 방향
방향을 헷갈리면 안 됩니다. cinterop과 SwiftPM import는 iOS 쪽을 코틀린으로 가져오는 방향이고, Swift export는 코틀린을 Swift로 내보내는 반대 방향이에요. 그리고 Swift export는 2026년 현재도 Alpha 단계로, 젯브레인스(JetBrains)가 KotlinConf'26 키노트 등을 통해 2026년 내 표준화를 목표로 잡아둔 상태로 알려져 있어요.
여기서 잘 안 알려진 함정이 하나 있는데요. SwiftPM import를 쓰는 KMP 모듈을 다시 Swift 패키지로 export하는 건 미지원이라 "might not work"라고 공식 문서에 적혀 있습니다. shared 모듈을 XCFramework로 묶어 iOS에 배포하는 표준 KMP 구조와 정면으로 부딪힐 수 있는 대목이지요. SwiftPM export 파일 생성 자체는 EAP 계열에서 순차적으로 도입되어 XCFramework 옆에 만들어진다고 하니, 쓰기 전에 공식 릴리스 노트에서 상태를 확인하셔야 합니다.
"코틀린 2.4면 이제 Swift를 직접 호출한다"는 오해가 도는데, 그건 아니에요. 여전히 C·Objective-C를 경유합니다. 상위 이슈는 YouTrack KT-53877로 추적되고 있어요.

spm4Kmp vs 공식 SwiftPM import, 프로덕션이 급하다면
공식 기능이 아직 Experimental이라 프로덕션에 못 올리겠다 싶으면, 커뮤니티 플러그인 spm4Kmp(frankois944) 가 현실적인 대안입니다. 네이티브 SPM을 그대로 쓰고 서드파티 의존도 없어서, 덜 침습적이고 더 안정적이라는 평가를 받고 있어요.
빌드 시간도 공식 대비 약 2배 빠르다는 벤치가 있는데, 이건 특정 프로젝트 기준의 벤더 측 수치라 그대로 일반화하긴 조심스럽습니다. 커뮤니티 중론은 "공식 import는 내일의 표준, spm4Kmp는 오늘의 실용적 경로"(2026.5 ProAndroidDev) 정도로 모이더라고요.
다만 리스크도 분명합니다. spm4Kmp는 유지보수자 한 명에 크게 기대고 있어서 장기 지원이 불확실하고, 나중에 공식으로 갈아탈 때 마이그레이션 비용이 듭니다. 공식 쪽도 마이너 버전마다 DSL이 바뀔 수 있어서 코드가 금방 낡아요.
무엇보다 둘 다 macOS·Xcode 툴체인에 강하게 묶여서 CI 이식성이 낮습니다. .def나 modulemap이 어긋나면 디버깅 난도가 확 올라가니, 도입 전에 CI에서 먼저 굴려보시는 걸 권합니다.
저라면 순서를 이렇게 잡겠습니다. 붙이려는 라이브러리의 Objective-C 표면이 얼마나 넓은지부터 재보고, 순수 Swift 덩어리가 크면 공통 코드 재작성을 먼저 검토하겠어요. 그다음 진짜 SwiftPM 의존이 필요하다면, 공식 기능이 안정화되기 전까지는 spm4Kmp가 더 실용적인 카드라고 봅니다. "SwiftPM 지원!"이라는 릴리스 노트 한 줄이 아니라, 그 라이브러리가 Objective-C를 얼마나 내놓느냐가 성패를 가르니까, 결국 그것부터 재보고 들어가는 게 삼십 분을 안 태우는 길이었어요.

'Android 개발 > 트러블슈팅' 카테고리의 다른 글
| 안드로이드 메모리 누수, LeakCanary와 프로파일러로 20회 재현 실측 일지 (0) | 2026.10.05 |
|---|---|
| 지하철에서 요청이 죽던 자리, 지수 백오프로 안드로이드 네트워크 재시도 다시 짠 일지 (0) | 2026.09.27 |
| Kotlin Native GC 동시 마킹, iOS 앱 멈칫이 진짜 줄었나 재봤습니다 (0) | 2026.09.10 |
| 부팅 90초가 8초로, 안드로이드 에뮬레이터 느림 잡은 5가지 점검 (0) | 2026.09.08 |
| WorkManager 사용법: 예약 작업이 기기마다 안 돌던 이유 (0) | 2026.08.30 |