Upgrade to Pro — share decks privately, control downloads, hide ads and more …

FlutterKaigi2026_SPM移行LT.pdf

 FlutterKaigi2026_SPM移行LT.pdf

Avatar for MEDLEY, INC.

MEDLEY, INC.

November 02, 2026

More Decks by MEDLEY, INC.

Other Decks in Programming

Transcript

  1. そもそも CocoaPods と SPM とは Before After CocoaPods SPM サードパーティ製(Ruby

    製) Swift Package Manager 長く iOS 開発を支えてきた 2024年8月に maintenance mode を宣言 Apple 公式の依存管理ツール Xcode に統合されていて 追加のインストールが要らない 2026年12月2日 CocoaPods のレジストリが読み取り専用になる ©2026 MEDLEY, INC . 株式会社メドレー 03
  2. なぜ移行しないといけないのか 読み取り専用になると 新しいバージョンを 公開できない Firebase・Sentry など SDK を更新できない 主要な SDK

    は 新機能も すでに公開を 止め始めている セキュリティ修正も 受け取れない Flutter アプリも例外ではない iOS 側のネイティブ依存はこれまで CocoaPods で管理されてきた プラグインが使っている Firebase や Sentry も同じ → SPM 対応が必要 ©2026 MEDLEY, INC . 株式会社メドレー 04
  3. Flutter の SPM 対応はどこまで来たか 2024.08.06 Flutter 3.24:SPM 対応が入る(opt-in・デフォルト OFF) 2024.08.13

    CocoaPods が maintenance mode を宣言 2026.05.19 Flutter 3.44:デフォルトが SPM に反転(opt-out は可能) 2026.08.12 Flutter 3.47:上位100 iOS プラグインの92%が SPM 対応済 2026.12.02 CocoaPods のレジストリが読み取り専用に opt-out はできるが、公式ドキュメントは "In general, don't do this." と明言 特別な理由がない限り、早めに移行したほうがいい ©2026 MEDLEY, INC . 株式会社メドレー 05
  4. 移行は本当に数行 pubspec.yaml flutter: config: enable-swift-package-manager: true SPM 対応のプラグインは一括で移行(プラグインごとには選べない) 未対応のプラグインは CocoaPods

    に残る → 両方が同居する構成になる 設定の追加は数行、作業は30分で終わった ©2026 MEDLEY, INC . 株式会社メドレー 06
  5. 移行の途中で3つの落とし穴にハマった CI でビルド 署名してアップロード Apple 側の検査 ① ② ③ CI

    が固まって ビルドが 終わらない 署名が足りず アップロードで 弾かれる 権限が足りず アップロードで 弾かれる 前提:macOS の CI で 非公開の git 依存を トークン付き HTTPS で取得 前提:署名せずにアーカイブ し 書き出すときに署名 前提:なし (CI の構成によらず起きる) ②と③は同じアップロードの段階で別の理由で2回弾かれた ©2026 MEDLEY, INC . 株式会社メドレー 07
  6. ① CI が固まってビルドが終わらない iOS のビルドがエラーも出さずに最初で止まり、タイムアウトする 前提:社内の非公開パッケージを git 依存で使い、CI ではトークン付き URL

    に差し替えて clone 原因:キーチェーンの確認ダイアログを待ち続けていた git の clone が成功 トークンが キーチェーンに 保存される SwiftPM が キーチェーンに 認証情報を聞く ダイアログを 出せず 永久に待つ 別のプロセスが保存した項目を読むには確認ダイアログが必要。でも CI には画面がない ©2026 MEDLEY, INC . 株式会社メドレー 08
  7. ① 対処:キーチェーンに保存させない PR #2289:.github/actions/pj_setup/action.yml の差分 対処 あわせて安全のため キーチェーンに保存させない 差し替えは対象リポジトリだけ credential

    helper を無効にする(54行目) insteadOf の範囲を絞る(48行目) トークン付き HTTPS で非公開依存を取る macOS の CI なら、最初から入れておく ©2026 MEDLEY, INC . 株式会社メドレー 09
  8. ② 署名が足りず、アップロードで弾かれる 症状 TestFlight へのアップロードが「署名が不正」で弾かれる fastlane のログは「成功」。後続ジョブのタイムアウトで初めて気づく 原因 SPM が埋め込んだスタブに、リンカーの仮署名が残っていた

    Sentry・Firebase の Privacy Manifest 用スタブ5つ(Sentry.framework など) 背景:なぜ署名せずにアーカイブしているのか CI では署名せずにアーカイブし、書き出すときに App Store Connect の API キーで署名している 証明書を CI に置かずに済み、年1回の証明書の更新も要らないため その代わり、アーカイブの中のフレームワークは自分で署名しないといけない ©2026 MEDLEY, INC . 株式会社メドレー 10
  9. ② 対処:フレームワークを署名し直す commit ad1153ea1:.github/workflows/qa_deploy.yml の差分(release_deploy.yml も同じ) 対処 書き出しの前に、Frameworks 内のフレームワークを すべて

    ad-hoc 署名し直す CI のビルドステップに1行足すだけ(258行目) 署名せずにアーカイブしている CI なら、最初から入れておく ©2026 MEDLEY, INC . 株式会社メドレー 11
  10. ③ 権限が足りず、アップロードで弾かれる 「カメラの利用目的が書かれていない」と弾かれる(ITMS-90683) このアプリはカメラを使っていない DKCamera file_picker 画像ピッカー ファイル選択 DKImagePickerController カメラ部分。カメラ・位置

    情報の API を参照 CocoaPods SPM 必要な部分だけ取り込めた 一式が入る 写真選択の部分(subspec)だけ カメラ部分は入らない 画像ピッカーを丸ごと取り込む カメラ部分も入り、検査で見つかる ©2026 MEDLEY, INC . 株式会社メドレー 12
  11. ③ 対処:利用目的を書く 今回の対処 Info.plist に利用目的を書く カメラ(NSCameraUsageDescription) 位置情報(NSLocationWhenInUseUsageDescription) 根本対処 file_picker 12

    以降で依存が外れる ただし API に破壊的変更があるため、優先度を見て今回は利用目的の追加を選んだ SPM 対応済みのパッケージでも、SPM 版では依存を分けていないことがある ©2026 MEDLEY, INC . 株式会社メドレー 13
  12. 影響が出る範囲を絞り込む 公式ドキュメントが案内するのは「SPM 統合ができたか」の確認まで 動作の検証方法は自分たちで考える 変わらない 変わる Dart のコード(1行も変わらない) iOS ネイティブ依存の

    Android リンク方式だけ UI・ビジネスロジック SDK のバージョンは変わっていない 影響が出るのはこの2つだけ ① ネイティブ連携を経由する機能 ©2026 MEDLEY, INC . ② ビルド・配布の流れ(①〜③の問題) 株式会社メドレー 14
  13. ネイティブ連携を経由する8項目 Sentry Analytics Remote Config プッシュ通知 ディープリンク Adjust CocoaPods に

    残ったプラグイン TestFlight 配布 動かなくなってもエラーが出ない クラッシュせず、データが送られなくなるだけ 起動して確認するだけでは気づけない ©2026 MEDLEY, INC . 株式会社メドレー 15
  14. 8項目を実際に動かして確かめる 一時コードを 仕込む ビルド番号入りの イベントと わざと投げるエラー TestFlight で配布 届いたかを 確かめる

    確認できたら revert 本番と同じ 配布経路で試す GA4 リアルタイム Sentry コンソール 一時コードは 残さない GA4 は他の QA メンバーの操作と混ざる イベントにビルド番号を入れて、自分のビルドだと特定する ©2026 MEDLEY, INC . 株式会社メドレー 16