PR

Flutter製アプリのPlay Store申請で「16KBページサイズ」エラーが5回出た話── Flutter 3.24.5 → 3.44.6 アップグレード記録

Flutter

RPG風HIITフィットネスアプリ「MUSCLE QUEST」をFlutterで個人開発し、Google Playへの申請を進めていたときのことです。ワークアウトを管理してキャラクターを育てるゲーム性のあるアプリで、タイマー・アチーブメント・広告まで実装し、ようやく申請にたどり着きました。

ところがPlay Consoleが、何度申請しても同じエラーで弾いてきます。v1からv5まで、5回連続で同じエラーでした。1回つまずくたびに「今度こそ」と修正してリビルド・再申請を繰り返し、合計で丸一日以上を費やすことになりました。

この記事では、その調査と解決の過程を記録として残します。同じ状況で詰まっている方の参考になれば幸いです。

Play Consoleのエラーメッセージ

AAB(Android App Bundle)をPlay Consoleにアップロードすると、以下のような警告が表示されました。

PLAY CONSOLE エラー

This App Bundle contains native code, and you're targeting devices
that require 16 KB page size alignment.

Affected ABIs: arm64-v8a, x86_64

Please update your app to support 16 KB page sizes to avoid issues
on newer devices.

「ネイティブコードを含むバンドルが16KBページサイズに対応していない」という内容で、arm64-v8a(ARMの64bit)とx86_64(x86の64bit)の両方が対象とされていました。

16KBページサイズとは何か

Androidの変更背景

従来のAndroidデバイスはメモリページサイズが4KB(0x1000)でした。Android 15(API 35)以降、特にPixel 9のような最新デバイスでは、カーネルがページサイズ16KB(0x4000)で動作するようになっています。

ELFバイナリ(.soファイル)のLOADセグメントのアライメントが4KBのままだと、16KB環境ではOSが共有ライブラリを正しくメモリにマップできないケースが生じます。Googleはこれに対応していないアプリの新規申請・アップデートを、Play Consoleで弾くようになりました。

BundleConfig.pbを覗いてみる

AABの中にはBundleConfig.pbというprotobufファイルが含まれており、バンドルの設定が格納されています。特にNativeLibrariesフィールド(Field 4)がuseLegacyPackaging: falseになっているかどうかが、16KB対応の指標のひとつです。

v1〜v5で生成したAABを調査したところ、このフィールドがまるごと存在しませんでした。つまりビルドツール(Flutterエンジン)が、16KB対応の設定をAABに埋め込んでいなかったということです。

v1〜v5で試したこと(全部ダメだった)

問題の原因として最初に疑ったのは、サードパーティのネイティブライブラリでした。Flutterエンジン本体は問題ないはずで、特定の.soファイルが悪さをしているのではないかと考えました。

Isar→Drift移行(v2〜v4)

ローカルDBとしてisar_flutter_libsを使っていました。IsarはRustで実装されておりネイティブの.soを持つため、これが16KBに未対応なのではと考え、SQLiteベースのDriftへ全面移行しました。

DB層の書き直しはかなりの作業量でしたが、申請してみると——結果は変わらずエラーでした。

armeabi-v7a の除外(v5)

armeabi-v7a(32bit ARM)のライブラリが混入して問題を起こしているのではと考え、build.gradleに以下を追加しました。

armeabi-v7a(32bit ARM)のライブラリが混入して問題を起こしているのではと考え、build.gradleに以下を追加しました。

それでも同じエラーが出ました。arm64-v8aとx86_64自体が16KBに対応していなかったのです。32bitの問題ではなく、64bit ABIで生成される.soのアライメントがすでに間違っている、という状態でした。

この時点での認識

「どのネイティブライブラリが犯人か」を探していましたが、犯人はFlutterエンジンそのものでした。エンジンが生成するlibflutter.soなど自体のアライメントが4KBのままだったため、何を追加・削除しても意味がなかったわけです。

根本原因:Flutter 3.27.0の壁

5回目の失敗でさすがにアプローチを変え、Flutterの公式リリースノートを掘り返しました。そこで見つけたのが、次の一文です。

Flutter リリースノート(3.27.0)

Flutter 3.27.0 adds support for Android 16KB page sizes.

使用していたFlutterは3.24.5でした。つまり3.27.0より前のバージョンは、16KBに対応していないということです。

Flutterエンジンが生成する.soファイルのLOADセグメントアライメントが4KBのままである以上、Isar/Drift関係なく、どのネイティブライブラリを入れ替えても、Flutterエンジン本体で弾かれる構造でした。

バージョン16KBサポート試した対応
3.24.5なしIsar除去、armeabi-v7a除外など→全て無効
3.27.0以降ありエンジン自体が16KBに対応

解決策は、Flutterを3.27.0以上に更新することでした。今回は最新のstable版である3.44.6に一気にアップグレードすることにしました。

Flutter 3.24.5→3.44.6 アップグレード

アップグレード自体は一行で済みます。

flutter upgrade

ただしその後、Dart/Flutter APIの変更への追従が必要で、複数のビルドエラーが次々と発生しました。遭遇した順番に記録します。

問題① intlバージョン競合

Because flutter_localizations from sdk depends on intl 0.20.2
  and muscletraining_continuation depends on intl ^0.19.0,
  intl 0.20.2 is forbidden.

flutter_localizationsがintl 0.20.2を要求する一方、pubspec.yamlが^0.19.0を指定していて衝突していました。

pubspec.yamlの指定を変更して対処します。

# Before
intl: ^0.19.0

# After
intl: ^0.20.2

問題② flutter_genのsynthetic-package廃止

Flutter 3.44.6では、flutter_genの--synthetic-packageフラグが廃止されました。l10nの生成ファイルの出力先パスが変わり、従来のimportパスが使えなくなります。

// Before
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// After
import 'package:muscletraining_continuation/l10n/app_localizations.dart';

プロジェクト内でこのimportを使っていたファイルが22ファイルあったため、手作業ではなくsedで一括置換しました。

find lib -name "*.dart" -exec sed -i '' \
  's|package:flutter_gen/gen_l10n/app_localizations.dart|package:muscletraining_continuation/l10n/app_localizations.dart|g' \
  {} \;

ポイントは、l10n.yamlの設定(output-localization-file: app_localizations.dart)は変更不要で、importパスだけを書き換えればよいという点です。

問題③ CardTheme/DialogThemeの型変更

The argument type 'CardTheme' can't be assigned to the parameter type 'CardThemeData?'
The argument type 'DialogTheme' can't be assigned to the parameter type 'DialogThemeData?'

Flutter 3.44.6でテーマクラスの型名が変わっていました。

// lib/core/theme/app_theme.dart
// Before
cardTheme: CardTheme(...)
dialogTheme: DialogTheme(...)

// After
cardTheme: CardThemeData(...)
dialogTheme: DialogThemeData(...)

問題④ google_fonts 6.2.1がDart 3.12非互換

Error: The key 'FontWeight {value: 100}' does not have a primitive operator '=='
  (google_fonts_variant.dart:153)

google_fonts 6.2.1の内部で、constマップのキーとしてFontWeightが使われていました。Dart 3.12ではこれがエラーになります。

pubspec.yamlで最新版に変更して対処します。

# Before
google_fonts: 6.2.1

# After
google_fonts: ^8.1.0

問題⑤ Gradle/AGPのバージョン要件

Flutter 3.44.6は最低Gradle 8.7.0、AGP(Android Gradle Plugin)8.6.0を要求します。

Your project's Gradle version (8.4.0) is lower than Flutter's minimum supported version of 8.7.0
Your project's Android Gradle Plugin version (8.3.0) is lower than Flutter's minimum supported version of 8.6.0

2つのファイルを更新して対処します。

ポイントは、Kotlinも1.9.22→2.0.21に上げる必要があるという点です。AGPだけ上げてもエラーが続きます。

問題⑥ NDKバージョン競合(非ブロッキング)

Your project is configured with Android NDK 25.1.8937393,
but the following plugin(s) depend on a different Android NDK version: [27.0.12077973]

ビルドは通るものの、プラグイン群がNDK 27.0.12077973を要求する一方、build.gradleは25.1.8937393を指定しているという警告です。27系に変えてみましたが、Apple Silicon Macでは両バージョンともdarwin-x86_64ビルドのNDKしか入っておらず、実質どちらでも変わりませんでした。ビルドへの実害はないため、25.1.8937393のままにしています。

問題⑦ strippingエラー(Xcode非インストール環境)

Release app bundle failed to strip debug symbols from native libraries.
xcrun: error: unable to find utility "xcodebuild", not a developer tool or in PATH

Flutter 3.44.6がmacOS上でデバッグシンボルのstrippingにxcrun xcodebuildを使おうとしますが、Xcode本体がインストールされておらず(CommandLineToolsのみ)、エラーになります。

ただし、AABファイル自体は生成されます。BUNDLE-METADATA/com.android.tools.build.debugsymbols/にネイティブシンボルが自動的に埋め込まれた状態で出力されるため、Play Consoleへのアップロードには支障がありません。ファイルサイズがstripped版より大きくなる(今回は65.5MB)のはそのためです。

Xcodeをインストールすれば解消しますが、15GB超のダウンロードが必要なため、今回はそのままアップロードしました。

これらすべての問題を修正したうえで、ビルドコマンドを実行します。

flutter build appbundle --release --obfuscate --split-debug-info=symbols

Flutter 3.44.6製のAAB(version code 6)が生成され、BundleConfig.pbにはNativeLibrariesフィールドが含まれており、正しく16KB対応の設定が埋め込まれていました。

まとめ

試みと結果を表にまとめます。

バージョン対応内容16KBエラー
v1初回申請(Flutter 3.24.5+Isar)✗ エラー
v2〜v4Isar→Drift移行✗ エラー
v5armeabi-v7a除外✗ エラー
v6Flutter 3.44.6へアップグレード✓ 解消

16KBページサイズエラーは「特定のネイティブライブラリが悪い」のではなく、Flutterエンジン自体のバージョンが原因でした。Play StoreにFlutterアプリを申請するなら、Flutter 3.27.0以上でビルドすることが必須条件です。

アップグレード後の追従作業(intl、l10n importパス、テーマ型名、google_fonts、Gradle/AGP/Kotlin)は地味に手間がかかりました。ただ、定期的にFlutterバージョンを上げて変更の差分を小さく保っておけば、今回のようにまとめて詰まることはないはずです。「リリース直前に大きなアップグレードをする」のではなく、普段からバージョンを最新に近い状態で維持することが大事だと実感しました。

同じエラーで詰まっている方は、まずFlutterのバージョンを確認してみてください。3.27.0未満であれば、それが原因である可能性が高いです。

最後まで読んでいただきありがとうございました。

→ MUSCLE QUESTの詳細はこちら:RPG×HIITフィットネスアプリ「MUSCLE QUEST」をリリースしました→ Flutter備忘録はこちら:Flutter リリースビルド時にAPIが利用できないときの対応法

コメント