every Tech Blog

株式会社エブリーのTech Blogです。

Flutter3.38アップグレードにおけるiOSとAndroidの影響範囲

Flutter3.38アップグレードにおけるiOSとAndroidの影響範囲
Flutter3.38アップグレードにおけるiOSとAndroidの影響範囲

 こんにちは、開発本部 開発2部 RetailHUB NetSuperグループに所属するホーク🦅アイ👁️です。

背景

 現在提供しているネットスーパーアプリはFlutter+Dartで実装しております。一方で、昨年2025年11月1日までに対応が必要であったGoogleからのメモリの16KBページサイズをサポートせよという通知を延長申請して2026年5月31日まで対応を保留にしていました。2026年2月現在、この延長期限も近づいてきていることを理由にFlutterのバージョンを3.38系にアップグレードすることになりました(こちらの公式ブログにも3.38から標準対応したとあります)。

Flutter3.38アップグレードの手順

 通常、Flutterのバージョンをアップグレードする際の流れとしては、以下の2点を気にする必要があり実際にそのプロセスを踏まないといけないことも少なからずあります。

  • パッケージ依存関係の解消
  • 既存ソースコードで改修

 今回、対象のソースコードで利用しているFlutterバージョンは3.24.1と古めのバージョンであるためバージョン差分が大きく、2点とも対応が発生しました。以下にその2点の対応について詳細を記していきます。

パッケージのバージョン依存関係調整

 目的はあくまでAndroidアプリの16KBページサイズに対応することなのでAndroidアプリのビルドをまず意識した以下のバージョンを調整しました。

  • Flutter,Dartのバージョンを上げる
    • Flutter3.38.9、Dart3.10.8にしました
    • DevTools 2.51.1
  • Gradleのバージョンを上げる
    • 8.7にしました
  • AGPのバージョンを上げる
    • 8.5.1にしました
  • Kotlinのバージョンを上げる
    • 2.0.21にしました
  • NDKバージョンを明示指定
    • 29.0.14206865にしました
  • その他利用ライブラリの対応バージョンをtrial and errorで上げる
    • 現状のバージョンのままでビルドしてみてエラーが出たら上げるを繰り返しました

依存関係の解消によって副次的問題が発生

 今回、Androidアプリのためにアップグレードをするので必要なライブラリパッケージも必要最低限のものだけを最小限でアップグレードすることを心がけたのですが、意図せずiPhoneアプリ側の方にも影響を及ぼしてしまうことが判明しました。具体的には以下のことが発生しました。

  • iOSの最小メジャーバージョン番号が12から13以上に引き上げ

 直接的な引き上げ条件は、Flutter公式によれば、swiftコードを利用する場合とありますがFlutter3.38自体がそれに該当するということ(参考ページ)でした。というわけで、必然的にFlutter3.38にしないといけない場合はiOS最小対応バージョンも13以上になるということでした。  最終的には以下に挙げるバージョン対応で一旦、すべての依存関係の競合を解決し、pub get、コード生成、iOS CocoaPodsインストールがすべて成功しました。

1. Dart SDK バージョン

  • 変更: >=3.7.0 <4.0.0>=3.8.0 <4.0.0
  • 理由: json_serializablefreezedの最新版が要求

2. Ferryエコシステム(GraphQLクライアント)

パッケージ 最終バージョン 理由
ferry ^0.16.1 ferry_generator 0.12.0+3との互換性
ferry_generator ^0.12.0+3 build 4.0対応
build_runner ^2.10.3 build 4.0対応
gql_code_builder_serializers ^0.1.0 ferry_generator 0.12.0+で必須
gql_exec ^1.0.0 ferry_generator依存関係
gql_http_link ^1.0.0 gql_execとの互換性
gql_transform_link ^1.0.0 gql_execとの互換性

3. Freezed(コード生成)

パッケージ 最終バージョン 理由
freezed ^3.2.5 build 4.0対応
freezed_annotation ^3.0.0 freezed 3.x対応

4. Firebase(iOS 13対応のため2.x系を使用)

パッケージ 最終バージョン 理由
firebase_core ^2.32.0 iOS 13サポート(3.x+はiOS 13必須)
firebase_analytics ^10.10.7 firebase_core 2.x互換
firebase_crashlytics ^3.5.7 firebase_core 2.x互換
firebase_messaging ^14.7.10 firebase_core 2.x互換 & webパッケージ互換
firebase_remote_config ^4.4.7 firebase_core 2.x互換
firebase_app_installations ^0.2.5+7 firebase_core 2.x互換

Firebase iOS SDK: 10.25.0(iOS 13+をサポート)

5. その他の重要な更新

パッケージ 最終バージョン 理由
intl ^0.20.2 flutter_localizations要求
retrofit_generator ^10.2.1 source_gen 4.0対応
json_annotation ^4.9.0 json_serializable要求(dependenciesに追加)

6. Isar Plus(データベース)モデル修正

isar_plus v4のAPI変更に対応:

変更後(isar_plus v4スタイル):

@collection
class EventLog {
  EventLog({required this.id});

  final int id;  // Auto-increment id (isar_plus v4)
  late String data;
}

主な変更点:

  • @Collection()(大文字)→ @collection(小文字)
  • Id id = Isar.autoIncrementfinal int idとコンストラクタで受け取る
  • 実際のauto-increment IDは isar.collection.autoIncrement()で生成

解決した依存関係の競合

競合1: isar_db_generator

  • 問題: isar_db_generatorパッケージが存在しない
  • 解決: isar_dbは元の isar_generatorを使用することを確認

競合2: intl バージョン

  • 問題: flutter_localizationsintl 0.20.2を要求
  • 解決: intl^0.20.2に更新

競合3: source_gen バージョン

  • 問題: isar_plussource_gen ^4.0.2を要求、retrofit_generator ^8.1.0source_gen ^1.3.0を要求
  • 解決: retrofit_generator^10.2.1に更新(source_gen 4.0対応版)

競合4: build バージョン

  • 問題: build_runner >=2.9.0build ^4.0.0を要求、freezed ^2.xbuild ^2.3.1を要求
  • 解決: freezed^3.2.5に更新(build 4.0対応版)

競合5: gql_exec バージョン

  • 問題: gql_transform_linkが古い gql_execを要求、ferry_generator 0.12.0+3gql_exec ^1.0.0を要求
  • 解決: gql_execgql_http_linkgql_transform_linkをすべて1.x系に更新

競合6: ferry バージョン

  • 問題: ferry ^0.14.2+1ferry_exec ^0.3.1を要求、ferry_generator 0.12.0+3ferry_exec ^0.7.0を要求
  • 解決: ferry^0.16.1に更新

競合7: web パッケージ(iOS 13対応のための調整)

  • 問題: isar_plusweb ^1.1.0を要求、Firebase 4.x系が web ^0.5.1を要求
  • 解決: Firebaseパッケージを2.x系にダウングレード(iOS 13サポートのため)

競合8: Firebase iOS 15要件

  • 問題: Firebase 4.x系(firebase_core 4.0+)はiOS 15を最小要件とする
  • 解決: Firebase 2.x系(firebase_core 2.32.0)を使用してiOS 13をサポート

参考リンク

既存コードの改修作業

 前述にある依存パッケージライブラリをアップグレードすることで破壊的変更が発生してしまった全箇所をエラーがなくなるまで対応していくという作業も相当数発生しました。

1. isar_plus 移行に伴うimport文の変更

  package:isar/isar.dartpackage:isar_plus/isar_plus.dart に変更

2. isar_plus 移行に伴うPodfileの変更

ios/Podfileisar_flutter_libsisar_plus_flutter_libs に変更

3. NDKバージョンの明示的指定

  • 追加: ndkVersion "29.0.14206865"(安定版最新。r28+ で 16KB アライメント対応のため r29 を使用)
  • ファイル: app/build.gradle
  • 理由: NDK r28以上で16KBアライメントがデフォルト対応。固定していた 28.0.12674087 ではなく、安定版最新 29.0.14206865 を推奨

4. Android app の namespace(AGP 8.x 必須)

  • 追加: namespace "tv.every.fresh"
  • ファイル: app/build.gradle
  • 理由: AGP 8.x ではモジュールに namespace の指定が必須。未指定だと「Namespace not specified」でビルド失敗する。

5. サブプロジェクトへの namespace 注入

  • 追加: Android library プラグインで namespace 未指定のサブプロジェクトに、AndroidManifest.xmlpackage を namespace として設定
  • ファイル: build.gradle(root)
  • 理由: AGP 8.x では全モジュールに namespace 必須。古いパッケージは namespace 未指定のため「Namespace not specified」でビルド失敗する。pub cache は編集しないため、root の subprojects.plugins.withId("com.android.library") で manifest の package を注入する。

6. BuildConfig の有効化

  • 追加: 全 Android サブプロジェクトで buildFeatures.buildConfig true
  • ファイル: build.gradle(root)
  • 理由: AGP 8.x では BuildConfig がデフォルト無効。custom BuildConfig を使うパッケージがあったため「defaultConfig contains custom BuildConfig fields, but the feature is disabled」でビルド失敗する。root の subprojects.afterEvaluate で全モジュールに有効化する。

7. Freezed 3.x マイグレーション(全モデルに abstract 修飾子)

  • 対象: @freezed を付けた全てのモデルクラス
  • 対応: Freezed 3.0 マイグレーションガイドに従い、全てのクラス定義に abstract 修飾子を追加
  • 変更例:
  // 変更前
  @freezed
  class Shop with _$Shop {...}

  // 変更後
  @freezed
  abstract class Shop with _$Shop {...}
  • 理由: Dart 3.10 コンパイラ下で non_abstract_class_inherits_abstract_member エラーを解消するため。Freezed 3.x の生成コード(mixin の抽象メンバー)と互換させるには、公開クラスを abstract class にすることが必要。
  • 実施方法: 上記のとおり、該当する全モデルファイルで classabstract class に手動で置換。
  • 検証: 本対応後に iOSビルド成功し、iOS Simulator(26.2)でアプリ起動を確認済。

8. retrofit / ParseErrorLogger 対応

  • 対象: retrofit パッケージをimportしているREST APIを実装したdartファイル(ex. rest_api.dart)
  • 現象: 旧 retrofit 4.1.0 + retrofit_generator 10.2.1 で生成したコードが型 ParseErrorLogger を参照するが、package:retrofit/http.dart のみの import では参照できずコンパイルエラーになる
  • 対応:
    • retrofit: ^4.1.0^4.9.2 に更新(Dart 3.8 対応バージョン、ParseErrorLogger は package:retrofit/retrofit.dart で提供)
    • rest_api.dart: import 'package:retrofit/retrofit.dart'; を追加し、生成コード(part ファイル)から ParseErrorLogger を参照可能にする。package:retrofit/http.dart は retrofit.dart に含まれるため削除可
  • 結果: build_runner 再生成後も手動修正不要でビルド可能

9. Android 旧埋め込み (PluginRegistry.Registrar) 削除対応

Flutter 3.38 では v1 Android 埋め込み API(PluginRegistry.Registrar / registerWith)が削除されている。以下のパッケージを更新済み。

  • path_provider: ^2.1.3^2.1.5(path_provider_android 2.2.5+ を要求し、v1 削除済み)
  • shared_preferences: ^2.2.3^2.3.4(shared_preferences_android 2.2.3+ で v1 削除済み)
  • url_launcher_android: ^6.0.38>=6.3.3 <6.3.27(6.3.3 で v1 削除。6.3.27+ は androidx.browser 1.9.0 が AGP 8.9.1 を要求するため 6.3.26 以下に制限)
  • compileSdkVersion: 34 → 36(path_provider_android 等が SDK 36 を要求。app/build.gradle

10. iOS CocoaPods更新

iOS最小デプロイメントターゲットをiOS 13.0にFixしました。

platform :ios, '13.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'

Flutter バージョン別 カート追加時パフォーマンス比較レポート

 新しいバージョンになったのでそれだけでどれだけ既存アプリのパフォーマンスにも影響を及ぼしたか気になったのでFlutter DevToolsでプロファイリングしてTimeline Eventsを3.24.1と3.38.9でベンチマーク比較してみました。

 以下は、同じカート追加アクションで取得したDevToolsの計測データを用い、Flutter 3.24.1Flutter 3.38.9 のパフォーマンスを比較したレポートです。

項目 Flutter 3.24.1 Flutter 3.38.9
総フレーム数 96 107

比較サマリー

指標 Flutter 3.24.1 Flutter 3.38.9 差分 傾向
平均FPS 19.8 fps 48.3 fps +28.5 fps ✅ 大幅改善
平均フレーム時間 50.47 ms 20.71 ms -29.76 ms ✅ 約59%短縮
平均ビルド時間 7.23 ms 1.25 ms -5.98 ms ✅ 約83%短縮
平均ラスター時間 26.86 ms 15.32 ms -11.54 ms ✅ 約43%短縮
平均Vsyncオーバーヘッド 5.96 ms 1.46 ms -4.50 ms ✅ 約75%短縮
最大フレーム時間 274.89 ms 85.51 ms -189.38 ms ✅ 約69%短縮
最大ビルド時間 115.16 ms 18.66 ms -96.50 ms ✅ 約84%短縮
最大ラスター時間 145.56 ms 41.46 ms -104.10 ms ✅ 約72%短縮
Janky率 100.0% 88.8% -11.2pt ✅ 改善
重度Jank率 (>33ms) 38.5% 4.7% -33.8pt ✅ 大幅改善

結論

  • Flutter 3.38.9 は 3.24.1 と比較して、カート追加時のパフォーマンスが全体的に大きく改善しています。
  • 平均FPSが 19.8 → 48.3 と約2.4倍になり、体感の滑らかさが向上しています。
  • ビルド時間・ラスター時間・Vsyncオーバーヘッドのいずれも短縮。最大フレーム時間は 274.89ms → 85.51ms(約69%短縮) と、改善が確認できます。
  • 重度Jank率は 38.5% → 4.7% と約1/8に減少。

主な改善要因(推測)

  • Flutterエンジン・Skiaの最適化
  • ビルドパイプラインの効率化(ビルド時間の大幅短縮)
  • Vsyncまわりのオーバーヘッド低減

今後の検討

  • 3.38.9 時点でも Janky率 88.8%、平均FPS 48.3 であり、60fps目標にはまだ余裕があります。
  • ラスターが主なボトルネックのため、画像最適化・RepaintBoundary・Clip削減などの施策を続けると、さらに改善の余地があります。

まとめ

 本ブログでは、Android15以降でサポートされている16KBページサイズに対応するためFlutterのバージョンを3.38系にアップグレードすると既存アプリにどのような影響を及ぼすことになるかについてお話ししました。

 一旦は、両OSともビルドが成功してアプリ起動までは確認が取れたのでこれから5月31日まであまり日がないですが以下のようなThe next stepsに基づいて進めていく予定であることをお知らせして結びとさせていただきます。

1. テスト

  • 単体テストの実行
  • 統合テストの実行
  • 手動テスト(特にデータベース操作とGraphQL操作)

2. iOS 11-12ユーザーへの対応検討

  • アプリストアで古いバージョンを継続提供
  • ユーザーへの事前通知
  • 段階的な移行計画

最後に

エブリーでは、ともに働く仲間を募集しています。

テックブログを読んで少しでもエブリーに興味を持っていただけた方は、ぜひ一度カジュアル面談にお越しください!

corp.every.tv