effidevFlutter · Cloudflare 엣지 · 클라우드 비용 최적화
한국어

Flutter Swift Package Manager 전환: CocoaPods 완전 대체 완전 가이드

Flutter Swift Package Manager CocoaPods 마이그레이션 아키텍처 다이어그램

CocoaPods의 종말이 시작됐다

2026년 12월 2일, CocoaPods trunk 레지스트리가 영구 read-only로 전환된다. 새 포드를 퍼블리시하거나 기존 포드를 업데이트할 수 없게 된다는 의미다. Flutter iOS 개발자가 10년 가까이 의존해온 의존성 관리 도구의 사실상 종료 선언이다.

Flutter 팀은 이미 2024년부터 Swift Package Manager(SwiftPM) 지원을 준비했다. 그리고 Flutter 3.44에서 SwiftPM이 iOS/macOS 기본 의존성 관리자로 바뀌었다. flutter run을 실행하면 Flutter CLI가 자동으로 SwiftPM 기반으로 Xcode 프로젝트를 업데이트한다.

이 글에서는 두 가지 관점을 모두 다룬다:

  1. 앱 개발자: 기존 CocoaPods 기반 Flutter 프로젝트를 SwiftPM으로 마이그레이션하는 방법
  2. 플러그인 작성자: Package.swift를 추가해 pub.dev 플러그인이 SwiftPM을 지원하도록 하는 방법

지금 마이그레이션하지 않으면 2026년 12월 이후 iOS 의존성이 사실상 동결된다.

CocoaPods vs Swift Package Manager: 핵심 차이

항목 CocoaPods Swift Package Manager
관리 주체 독립 오픈소스 프로젝트 Apple 공식 지원
설정 파일 Podfile Package.swift
Xcode 통합 .xcworkspace 생성 네이티브 Xcode 통합
빌드 속도 느림 (Ruby 기반 전처리) 빠름 (네이티브)
바이너리 캐싱 제한적 내장 (.build 캐시)
2026년 이후 상태 Read-only (종료) 적극 개발 중
pub.dev 점수 페널티 적용 시작 우대

SwiftPM의 가장 큰 장점은 Xcode에 네이티브로 통합된다는 점이다. 별도의 pod install이 필요 없고, .xcworkspace 파일 대신 .xcodeproj로도 바로 빌드할 수 있다.

앱 개발자: 자동 마이그레이션

Flutter 3.44 이상을 사용한다면 대부분의 경우 자동으로 마이그레이션된다.

1. Flutter 버전 확인

flutter --version
# Flutter 3.44.0 이상인지 확인

flutter upgrade  # 필요 시 업그레이드

2. 자동 마이그레이션 트리거

# 기존 프로젝트에서 실행하면 Flutter CLI가 자동으로 SwiftPM 마이그레이션을 시도
flutter run

# 또는 명시적으로 활성화
flutter config --enable-swift-package-manager
flutter run  # 이후 실행 시 SwiftPM 설정 자동 적용

Flutter CLI가 수행하는 자동 마이그레이션 내용:

  1. ios/Runner.xcodeproj/project.pbxproj에 SwiftPM 통합 설정 추가
  2. ios/ 폴더에 FlutterGeneratedPluginSwiftPackage 참조 추가
  3. Xcode 빌드 스킴에 Run Prepare Flutter Framework Script 추가

3. 마이그레이션 성공 검증

# Xcode에서 확인
open ios/Runner.xcworkspace

# 또는 터미널에서
cat ios/Runner.xcodeproj/project.pbxproj | grep "FlutterGeneratedPluginSwiftPackage"
# 해당 문자열이 있으면 SwiftPM 통합 완료

Xcode에서는 Project Navigator → Package Dependencies 탭에 플러그인들이 SwiftPM 패키지로 표시된다.

4. 지원되지 않는 플러그인 처리

아직 SwiftPM을 지원하지 않는 플러그인이 있으면 Flutter CLI가 경고를 출력한다:

The following packages have native iOS code but are not compatible with Swift Package Manager:
  - some_plugin (version: 1.2.3)

Flutter will use CocoaPods for these plugins only.

이 경우 Flutter가 자동으로 폴백: 지원되는 플러그인은 SwiftPM, 미지원 플러그인은 CocoaPods로 혼용한다. Podfile은 그대로 유지되며 pod install이 필요한 플러그인에만 적용된다.

미지원 플러그인 대응 방법:

  1. 플러그인 GitHub에 SwiftPM 지원 이슈 제기
  2. 대체 플러그인 탐색 (pub.dev에서 SwiftPM 지원 여부 확인)
  3. 직접 Package.swift PR 기여

5. 임시 비활성화 (문제 발생 시)

SwiftPM이 빌드 오류를 유발하는 경우 일시적으로 비활성화:

# pubspec.yaml — 임시 비활성화
flutter:
  config:
    enable-swift-package-manager: false

또는:

flutter config --no-enable-swift-package-manager

⚠️ 이 옵션은 임시 우회 수단이다. 2027년경 제거될 예정이므로 의존하지 말 것.

앱 개발자: 수동 마이그레이션 (레거시 프로젝트)

자동 마이그레이션이 실패하거나 오래된 프로젝트를 마이그레이션할 때 수동으로 진행한다.

마이그레이션 전 체크리스트

# 현재 상태 백업
git checkout -b feat/spm-migration
git add -A && git commit -m "chore: before SPM migration"

# 모든 플러그인의 SwiftPM 지원 여부 확인
cat pubspec.yaml | grep -A 50 "dependencies:"

각 Flutter 플러그인의 pub.dev 페이지에서 “Swift Package Manager support” 배지를 확인한다.

Podfile 정리

# ios/Podfile (마이그레이션 후에도 일부 플러그인 폴백용으로 유지)
platform :ios, '13.0'  # iOS 최소 버전 확인

# SwiftPM 마이그레이션 후에는 지원하는 플러그인은 자동으로 제외됨
# CocoaPods에서만 사용하는 플러그인 명시 (필요 시)
target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

  target 'RunnerTests' do
    inherit! :search_paths
  end
end

마이그레이션 실행

cd ios

# 기존 CocoaPods 캐시 정리
rm -rf Pods/ Podfile.lock

# Flutter Clean
cd ..
flutter clean

# 의존성 재설치 (SwiftPM + CocoaPods 혼용)
flutter pub get
cd ios && pod install  # 여전히 필요한 플러그인용
cd ..

# 빌드 테스트
flutter build ios --no-codesign

플러그인 작성자: Package.swift 추가

Flutter 플러그인을 pub.dev에 배포하고 있다면 SwiftPM 지원을 추가해야 한다. pub.dev 점수 시스템이 SwiftPM 지원 여부를 평가 항목에 포함했으므로 미지원 시 점수 페널티가 발생한다.

디렉터리 구조 변경

기존 CocoaPods 구조:

ios/
  Classes/
    MyPlugin.swift
    MyPlugin.h (Obj-C 혼용 시)
  my_plugin.podspec

SwiftPM 지원 후 구조:

ios/
  my_plugin/           # SwiftPM 패키지 루트 (새로 추가)
    Package.swift      # SwiftPM 매니페스트
    Sources/
      my_plugin/       # 타겟명 = 패키지명
        MyPlugin.swift
  Classes/             # CocoaPods 하위 호환용 유지
    MyPlugin.swift
  my_plugin.podspec    # 기존 podspec 유지

SwiftPM은 소스 파일이 반드시 패키지 루트 내부에 있어야 한다. CocoaPods는 루트 밖 경로를 허용했지만 SwiftPM은 엄격히 패키지 내부만 허용한다.

Package.swift 작성

순수 Swift 플러그인의 경우:

// ios/my_plugin/Package.swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "my_plugin",
    platforms: [
        .iOS(.v13),
    ],
    products: [
        .library(
            name: "my-plugin",
            targets: ["my_plugin"]
        )
    ],
    dependencies: [],
    targets: [
        .target(
            name: "my_plugin",
            dependencies: [],
            path: "Sources/my_plugin",
            // 외부 Swift 의존성이 있는 경우
            // dependencies: [
            //   .product(name: "SomeSDK", package: "some-sdk"),
            // ]
        )
    ]
)

Swift + Objective-C 혼용 플러그인:

// ios/my_plugin/Package.swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "my_plugin",
    platforms: [
        .iOS(.v13),
    ],
    products: [
        .library(name: "my-plugin", targets: ["my_plugin"])
    ],
    targets: [
        .target(
            name: "my_plugin",
            dependencies: [],
            path: "Sources/my_plugin",
            // Obj-C 퍼블릭 헤더 경로 지정
            publicHeadersPath: "include",
            // Obj-C 파일도 같은 타겟에 포함됨
            cSettings: [
                .headerSearchPath("include"),
            ]
        )
    ]
)

SwiftPM은 같은 타겟 내에서 Swift와 Objective-C를 혼용할 수 없다. 만약 플러그인이 Objective-C와 Swift를 모두 사용한다면 별도 타겟으로 분리해야 한다:

targets: [
    // Objective-C 전용 타겟
    .target(
        name: "my_plugin_objc",
        path: "Sources/my_plugin_objc",
        publicHeadersPath: "include"
    ),
    // Swift 타겟이 Obj-C 타겟에 의존
    .target(
        name: "my_plugin",
        dependencies: ["my_plugin_objc"],
        path: "Sources/my_plugin"
    )
]

소스 파일 구조 재배치

# SwiftPM용 소스 디렉터리 생성
mkdir -p ios/my_plugin/Sources/my_plugin

# 기존 소스 복사 (CocoaPods용은 그대로 유지)
cp ios/Classes/MyPlugin.swift ios/my_plugin/Sources/my_plugin/
cp ios/Classes/MyPlugin.m ios/my_plugin/Sources/my_plugin/  # Obj-C 있는 경우

Flutter Framework 의존성 추가

Flutter 네이티브 API를 사용하는 경우 (FlutterPlugin 프로토콜, FlutterMethodChannel 등) Flutter Framework를 의존성으로 명시해야 한다:

// ios/my_plugin/Package.swift
let package = Package(
    name: "my_plugin",
    platforms: [.iOS(.v13)],
    products: [
        .library(name: "my-plugin", targets: ["my_plugin"])
    ],
    dependencies: [
        // Flutter Framework 의존성 추가 (필수!)
        .package(
            url: "https://github.com/nicehash/flutter",
            from: "1.0.0"
        )
    ],
    targets: [
        .target(
            name: "my_plugin",
            dependencies: [
                .product(name: "Flutter", package: "flutter")
            ],
            path: "Sources/my_plugin"
        )
    ]
)

주의: Flutter 공식 Package.swift URL은 Flutter 팀에서 제공하는 경로를 사용한다. Flutter CLI가 실행 시 자동으로 올바른 Framework를 제공하므로, 실제로는 Flutter SDK에 번들된 경로가 자동 주입된다.

pubspec.yaml 업데이트

# pubspec.yaml (플러그인)
name: my_plugin
version: 2.0.0

flutter:
  plugin:
    platforms:
      ios:
        # CocoaPods 설정 (하위 호환)
        podspec: ios/my_plugin.podspec
        # SwiftPM 설정 추가
        swiftPackage: ios/my_plugin

검증: 예제 앱으로 테스트

# 플러그인 예제 앱에서 SwiftPM 마이그레이션 활성화
cd example

flutter config --enable-swift-package-manager
flutter run -d iPhone  # 실제 기기 또는 시뮬레이터

# Xcode에서 확인
open ios/Runner.xcworkspace
# Package Dependencies에 my_plugin이 보이면 성공

CI 파이프라인 업데이트

# .github/workflows/test.yml
- name: Flutter iOS Build (SwiftPM)
  run: |
    flutter config --enable-swift-package-manager
    flutter build ios --no-codesign --simulator
  env:
    FLUTTER_VERSION: "3.44.0"

# 기존 CocoaPods 빌드도 병렬 테스트 (하위 호환 확인)
- name: Flutter iOS Build (CocoaPods fallback)
  run: |
    flutter config --no-enable-swift-package-manager
    flutter build ios --no-codesign --simulator

마이그레이션 타임라인 및 위험도

시점 사건 위험도
Flutter 3.44 (현재) SwiftPM 기본값 낮음 (폴백 있음)
2026년 12월 2일 CocoaPods trunk read-only 높음
2027년 상반기 (예상) Flutter에서 opt-out 옵션 제거 매우 높음

지금 해야 할 것:

2026년 12월 전까지 반드시 완료:

트러블슈팅: 자주 만나는 오류

오류 1: “Sources folder not found”

error: Source files for target 'my_plugin' should be located under 'Sources/my_plugin'

원인: SwiftPM은 소스 파일이 패키지 루트 내 Sources/<타겟명>/ 경로에 있어야 한다.
해결: 소스 파일을 ios/my_plugin/Sources/my_plugin/으로 이동.

오류 2: “Cannot use Swift and Objective-C in the same target”

원인: SwiftPM은 같은 타겟 내 언어 혼용 불가.
해결: Obj-C 전용 타겟과 Swift 타겟으로 분리.

오류 3: pod install 후에도 여전히 CocoaPods만 사용

# 강제 SwiftPM 모드 확인
flutter config | grep swift-package-manager

# 활성화되어 있지 않으면
flutter config --enable-swift-package-manager
flutter clean && flutter pub get

오류 4: “FlutterGeneratedPluginSwiftPackage not found”

# Xcode 캐시 정리
rm -rf ~/Library/Developer/Xcode/DerivedData
cd ios && xcodebuild -resolvePackageDependencies

오류 5: Bitcode 관련 경고

SwiftPM은 Bitcode를 기본적으로 비활성화한다. iOS 16 이후 Apple이 Bitcode를 deprecated 처리했으므로 경고는 무시해도 된다.

pub.dev 점수 영향

pub.dev는 2025년부터 플러그인 점수 산정에 SwiftPM 지원 여부를 포함했다. 점수 카테고리:

지원 수준 pub.dev 점수 영향
SwiftPM + CocoaPods 모두 지원 만점
CocoaPods만 지원 페널티 (-10점 수준)
미지원 (Dart-only 플러그인 제외) 추가 경고 표시

100점 만점인 pub.dev 점수는 검색 순위에 직접적인 영향을 미친다. SwiftPM 지원은 더 이상 선택이 아닌 필수다.

결론

CocoaPods의 종료는 Flutter iOS 생태계에서 가장 중요한 변화 중 하나다. Swift Package Manager로의 전환은 단순한 도구 교체가 아니라 Apple 공식 생태계로의 귀환이다.

앱 개발자에게 좋은 소식은 대부분의 경우 flutter run 한 번으로 자동 마이그레이션이 이루어진다는 점이다. 문제가 생기는 경우는 아직 SwiftPM을 지원하지 않는 플러그인에 의존할 때다.

플러그인 작성자라면 지금 바로 Package.swift를 추가해야 한다. 2026년 12월 이후 CocoaPods에 새 버전을 올리는 것 자체가 불가능해진다.

행동 계획:

  1. flutter config --enable-swift-package-manager 실행
  2. flutter run으로 빌드 테스트
  3. 경고 플러그인 목록 확인 후 대응책 수립
  4. (플러그인 작성자) Package.swift 추가 후 pub.dev 배포

관련 글: Flutter 16KB 페이지 크기와 Google Play 최적화에서 Flutter 앱의 Android 측 최적화를 함께 확인하자.