effidevFlutter・Cloudflareエッジ・クラウドコスト最適化
日本語

Flutter SwiftPM移行: CocoaPods完全代替ガイド

Flutter Swift Package Manager CocoaPods移行アーキテクチャ図

CocoaPodsの終焉が始まった

2026年12月2日、CocoaPods trunkレジストリが永久read-onlyに移行します。新しいPodのパブリッシュや既存Podの更新ができなくなることを意味します。Flutter iOS開発者が10年近く依存してきた依存関係管理ツールの事実上の終了宣言です。

Flutterチームはすでに2024年からSwift Package Manager(SwiftPM)サポートを準備してきました。そしてFlutter 3.44において、SwiftPMがiOS/macOSのデフォルト依存関係マネージャーに変更されました。flutter runを実行すると、Flutter CLIが自動的にSwiftPMベースでXcodeプロジェクトを更新します。

この記事では、2つの観点から解説します:

  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サポートのIssueを作成
  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専用プラグインを除く) 追加警告の表示

100点満点であるpub.devのスコアは、検索順位に直接的な影響を与えます。SwiftPMサポートはもはや選択肢ではなく必須です。

結論

CocoaPodsの終了は、Flutter iOSエコシステムにおける最も重要な変化の1つです。Swift Package Managerへの移行は単なるツールの置き換えではなく、Apple公式エコシステムへの回帰を意味します。

アプリ開発者にとって朗報なのは、ほとんどのケースにおいてflutter runの実行1回で自動移行が行われるという点です。問題が発生するのは、まだ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側最適化も合わせて確認しましょう。