
- 背景
- Flutter3.38アップグレードの手順
- パッケージのバージョン依存関係調整
- 解決した依存関係の競合
- 既存コードの改修作業
- 1. isar_plus 移行に伴うimport文の変更
- 2. isar_plus 移行に伴うPodfileの変更
- 3. NDKバージョンの明示的指定
- 4. Android app の namespace(AGP 8.x 必須)
- 5. サブプロジェクトへの namespace 注入
- 6. BuildConfig の有効化
- 7. Freezed 3.x マイグレーション(全モデルに abstract 修飾子)
- 8. retrofit / ParseErrorLogger 対応
- 9. Android 旧埋め込み (PluginRegistry.Registrar) 削除対応
- 10. iOS CocoaPods更新
- Flutter バージョン別 カート追加時パフォーマンス比較レポート
- まとめ
- 最後に
こんにちは、開発本部 開発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_serializableとfreezedの最新版が要求
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.autoIncrement→final int idとコンストラクタで受け取る- 実際のauto-increment IDは
isar.collection.autoIncrement()で生成
解決した依存関係の競合
競合1: isar_db_generator
- 問題:
isar_db_generatorパッケージが存在しない - 解決:
isar_dbは元のisar_generatorを使用することを確認
競合2: intl バージョン
- 問題:
flutter_localizationsがintl 0.20.2を要求 - 解決:
intlを^0.20.2に更新
競合3: source_gen バージョン
- 問題:
isar_plusがsource_gen ^4.0.2を要求、retrofit_generator ^8.1.0がsource_gen ^1.3.0を要求 - 解決:
retrofit_generatorを^10.2.1に更新(source_gen 4.0対応版)
競合4: build バージョン
- 問題:
build_runner >=2.9.0がbuild ^4.0.0を要求、freezed ^2.xがbuild ^2.3.1を要求 - 解決:
freezedを^3.2.5に更新(build 4.0対応版)
競合5: gql_exec バージョン
- 問題:
gql_transform_linkが古いgql_execを要求、ferry_generator 0.12.0+3がgql_exec ^1.0.0を要求 - 解決:
gql_exec、gql_http_link、gql_transform_linkをすべて1.x系に更新
競合6: ferry バージョン
- 問題:
ferry ^0.14.2+1がferry_exec ^0.3.1を要求、ferry_generator 0.12.0+3がferry_exec ^0.7.0を要求 - 解決:
ferryを^0.16.1に更新
競合7: web パッケージ(iOS 13対応のための調整)
- 問題:
isar_plusがweb ^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をサポート
参考リンク
- isar_plus v4 ドキュメント
- ferry_generator changelog
- freezed 3.0 migration
- Firebase Flutter changelog
- firebase_core 3.0.0 breaking changes
既存コードの改修作業
前述にある依存パッケージライブラリをアップグレードすることで破壊的変更が発生してしまった全箇所をエラーがなくなるまで対応していくという作業も相当数発生しました。
1. isar_plus 移行に伴うimport文の変更
package:isar/isar.dart → package:isar_plus/isar_plus.dart に変更
2. isar_plus 移行に伴うPodfileの変更
ios/Podfileで isar_flutter_libs → isar_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.xmlのpackageを 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にすることが必要。 - 実施方法: 上記のとおり、該当する全モデルファイルで
class→abstract 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 に含まれるため削除可
- retrofit:
- 結果: 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.1 と Flutter 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ユーザーへの対応検討
- アプリストアで古いバージョンを継続提供
- ユーザーへの事前通知
- 段階的な移行計画
最後に
エブリーでは、ともに働く仲間を募集しています。
テックブログを読んで少しでもエブリーに興味を持っていただけた方は、ぜひ一度カジュアル面談にお越しください!