【ITニュース解説】Your app has native code even if you never wrote C++: the 16 KB page size check in 4 commands
2026年10月15日に「Dev.to」が公開したITニュース「Your app has native code even if you never wrote C++: the 16 KB page size check in 4 commands」について初心者にもわかりやすく解説しています。
ITニュース概要
Androidアプリは2027年2月までに16KBメモリページサイズ対応が必須となる。C++不使用でも、MLやDB等のライブラリ内ネイティブコードが原因で未対応の可能性。APK分析やコマンドで確認し、AGP/NDK更新やライブラリ入れ替えで対応を。未対応だと更新できなくなる。
ITニュース解説
Androidアプリ開発者にとって、Google Playが新たな要件を設けたことは重要な変更点だ。これはアプリの更新が停止する可能性のある問題なので、すべての開発者が内容を理解し、対応を進める必要がある。
これまでAndroidデバイスは、メモリを「4KBのページ」という比較的小さな単位で管理していた。しかし、近年の高性能なデバイスでは、より効率的な「16KBのページ」で動作できるようになっている。Google Playは、このような新しいデバイス環境への対応をアプリに義務付け、16KBページサイズのサポートを要求するようになった。この要件は、Android 15 (APIレベル35) 以降をターゲットとするアプリの更新に適用される。具体的には、2027年2月1日以降、この要件を満たさないアプリの更新はGoogle Playにリリースできなくなるため、期日までに対応を完了させる必要がある。
この新しい要件が特に影響するのは、「ネイティブコード」を含むアプリだ。ネイティブコードとは、JavaやKotlinといったAndroidアプリの主な開発言語ではなく、CやC++のような言語で書かれたプログラム部分を指す。アプリ開発者が直接C++コードを書いていなくても、機械学習の実行環境、動画や音声処理ライブラリ、データベースエンジン、画像処理コーデック、さらには一部の分析SDKなど、多くの外部ライブラリにはネイティブコード(一般的には.soファイルという形式で含まれる)が組み込まれている。もしこれらのライブラリが、古い4KBページ環境にのみ対応するようにビルドされている場合、あなたのアプリは新しい要件を満たせないことになる。Google Play Consoleで警告が表示されるのは、このようなサードパーティ製のライブラリが原因であるケースも多い。
問題の核心にあるのは、「アラインメント」というメモリの配置に関する概念だ。ネイティブライブラリがデバイスのメモリに読み込まれる際、プログラムコードやデータは「セグメント」と呼ばれる塊に分けられて配置される。16KBページで動作するデバイスでは、これらのセグメントがメモリ上の「16KBの境界」から開始される必要がある。しかし、4KBページ専用にビルドされたライブラリは、セグメントが「4KBの境界」から始まるように設計されている。この境界の不一致が原因で、16KBページデバイスではライブラリの読み込みに失敗したり、アプリがクラッシュしたりする可能性がある。この問題は、アプリのJavaやKotlinコードを修正するだけでは解決できず、ネイティブライブラリのビルド方法や、それがアプリパッケージ(APKファイル)内にどのように格納されているかという低レベルな部分に起因する。
自分のアプリがこの問題の影響を受けるかどうかを診断する方法はいくつかある。最も手軽なのは、Android Studioの「Analyze APK」機能を使うことだ。リリース用にビルドしたAPKファイルを開き、その中のlibフォルダー内に.soファイルがあるかを確認する。もし.soファイルが一つもなければ、アプリはネイティブコードを含んでいないため、この問題に関しては心配する必要がない。.soファイルが見つかった場合、そのファイルの「Alignment」という列に警告が表示されていないかを確認する。Android Studioや開発ツールに含まれるlint機能も、16KBアラインメントに対応していない事前ビルド済みライブラリを検出してくれることがある。
より詳細な診断には、コマンドラインツールを使用するのが一般的だ。まず、APKファイルを展開し、展開された各.soファイルのロードセグメントのアラインメントをllvm-objdumpコマンドで確認できる。具体的には、llvm-objdump -p [soファイル名] | grep LOADというコマンドを実行し、表示される「LOAD」行に「align 214」(これは16KBを意味する)以上と記載されているかを確認する。もし「align 213」(8KB)やそれ以下の値が表示されている場合、そのライブラリは再ビルドするか、互換性のあるものに置き換える必要がある。次に、APKファイル自体の「zipアラインメント」をチェックするために、Android Build-Toolsに含まれるzipalignコマンドを使用する。zipalign -v -c -P 16 4 app-release.apkを実行し、最後に「Verification successful」と表示されれば、ライブラリがAPK内に正しく格納されていることになる。App Bundle形式でアプリを配布している場合は、bundletool dump config --bundle=app-release.aab | grep alignmentコマンドを実行し、バンドルがPAGE_ALIGNMENT_16Kを要求していることを確認する必要がある。最後に、最も確実な検証方法として、16KBページサイズをサポートするAndroidエミュレーターイメージ(または対応デバイスの開発者オプション)で実際にアプリをテストすることだ。adb shell getconf PAGE_SIZEコマンドで「16384」と表示されることを確認した後、アプリ内のネイティブコードが関わるすべての機能を試運転させる。4KBページでは問題なく動作していたライブラリが、この環境でクラッシュすれば、それがまさにこの問題の対象となる部分だ。
この問題を解決するための主要なアプローチを説明する。最も簡単な方法は、Android Gradle Plugin (AGP) を8.5.1以上、Android NDK (Native Development Kit) をr28以上にアップグレードすることだ。これらの新しいバージョンでは、特に明示的な設定をしなくても、デフォルトで16KBページに対応したネイティブライブラリがビルドされる。NDK r28以降はデフォルトで16KBアラインメントでコンパイルされるため、Gradleのビルド設定でndkVersionを"28.2.13676358"のように固定して、常に最新のNDKを使用するようにすることが推奨される。
もし、AGPやNDKを最新バージョンにアップグレードできない、または特定の理由で古いバージョンを使い続ける必要がある場合は、自作のC/C++コードに対してリンカーフラグを追加することで対応できる。CMakeを使用しているプロジェクトであればtarget_link_optionsに、NDKのndk-buildを使用しているプロジェクトであればLOCAL_LDFLAGSに、-Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384というオプションを追加することで、16KBアラインメントを強制できる。
他社から提供されている事前ビルド済みのライブラリ(SDKなど)については、自分でソースコードをビルドできないため、リンカーフラグを追加して修正することは不可能だ。この場合は、そのライブラリの新しいバージョンが16KBページサイズをサポートしているかを確認し、アップデートする必要がある。もし対応するバージョンが見つからない場合は、そのライブラリを別のものに置き換えることを検討する必要があるだろう。
また、アプリのパッケージング方法も重要だ。16KBデバイスでは、共有ライブラリが非圧縮で、かつ16KBの境界に沿ってzipアラインされてAPK内に格納されている必要がある。AGP 8.5.1以上にアップグレードすれば、このパッケージング要件もデフォルトで満たされるため、通常は特別な対応は不要だ。古いAGPバージョンを使用している場合、共有ライブラリを圧縮する設定(useLegacyPackaging = true)にすることでこの要件を回避できる場合があるが、その場合、アプリのインストールサイズが増加する可能性がある点に注意が必要だ。
さらに重要な注意点として、ネイティブコード自身がページサイズを4096バイト(4KB)と決め打ちで仮定している場合がある。例えば、PAGE_SIZEという定数に直接依存していたり、mmap()などのメモリ操作APIを呼び出す際にページアラインされた引数を渡す必要がある場合、あるいは独自のカスタムメモリ管理機能を持っている場合などだ。たとえライブラリのアラインメントが正しく修正されても、コード自体が誤ったページサイズを前提にしていると、アプリがクラッシュする可能性がある。このようなコードは、システムから現在のページサイズを取得する関数(例えばgetpagesize()やsysconf(_SC_PAGESIZE))を使うように修正する必要がある。
これらの対応をすべて完了させるためのチェックリストは次の通りだ。まず、リリースAPKに.soファイルが含まれているか、またそれがどのライブラリ由来かを把握しておく。次に、Android Gradle Pluginを8.5.1以降、Android NDKをr28以降にアップデートし、GradleのndkVersionで固定する。そして、llvm-objdumpコマンドを使って、すべてのarm64-v8aおよびx86_64アーキテクチャのライブラリについて、LOADアラインメントが2**14(16KB)以上であることを確認する。zipalign -c -P 16コマンドが「Verification successful」と報告することも重要だ。ネイティブコードが4096バイトページを前提にしていないことを確認し、最後に16KBページサイズのエミュレーターイメージでアプリが正常に動作することを徹底的にテストする。これらの対応は、Google Playの期限である2027年2月1日までに完了させる必要がある。継続的な品質管理のためにも、リリースビルドごとにzipalignとobjdumpのチェックを自動化し、問題があればビルドを失敗させる仕組みを導入することが望ましい。