Androidでアプリをインストールしようとすると、必ずと言っていいほど登場する「APK」という言葉。ふだん意識することはあまりありませんが、実際にはどんな形をしていて、インストールのときに何が起きているのでしょうか。ここでは、APKの正体から中身の構造、インストールの流れ、署名の仕組み、そして最近主流になっているAABとの関係まで、基本的なところを整理してみます。
APKの正体はただのZIPファイル
APK(Android Package Kit、あるいはAndroid Application Package)は、Androidアプリを配布・インストールするためのファイル形式で、拡張子は.apkです。スマホにアプリを入れるとき、実際にやり取りされているのはこのAPKファイルそのものです。
面白いのは、APKの正体が単なるZIP形式のアーカイブだという点です。試しに拡張子を.zipに変えてみれば、普段使っている解凍ソフトでそのまま中身を開くことができます。特殊な暗号化がされているわけではなく、「決まった構造を持つZIPファイル」というのがAPKの本質です。
展開すると何が入っているか
APKを展開すると、だいたい次のようなファイルやフォルダが出てきます。
sample.apk
├── AndroidManifest.xml # アプリの設定情報(バイナリ形式)
├── classes.dex # コンパイルされたJava/Kotlinコード
├── resources.arsc # コンパイル済みリソースの索引
├── res/ # 画像・レイアウト・文字列などのリソース
│ ├── drawable/
│ ├── layout/
│ └── values/
├── assets/ # コンパイルされない生ファイル
├── lib/ # ネイティブライブラリ(.so)
│ ├── arm64-v8a/
│ ├── armeabi-v7a/
│ └── x86/
└── META-INF/ # 署名・証明書情報
├── MANIFEST.MF
├── CERT.SF
└── CERT.RSA
AndroidManifest.xmlには、パッケージ名や必要な権限、画面(Activity)構成、対応OSバージョンといった、アプリの基本情報がまとめて書かれています。実際にアプリのロジックを動かしているのはclasses.dexで、JavaやKotlinのソースコードをAndroidランタイム(ART)が実行できる形式に変換したバイトコードです。
画像やレイアウトといったリソース本体はres/フォルダに入り、resources.arscはそれらを参照するための索引の役割を果たします。少し毛色が違うのがassets/で、こちらはコードから直接読み込む生データ(フォントや設定ファイルなど)の置き場所です。C/C++で書かれたネイティブコードがあればlib/フォルダに格納され、CPUアーキテクチャ(ABI)ごとにフォルダが分かれます。そしてMETA-INF/には、APKが改ざんされていないかを確認するための署名・証明書情報が入っています。
インストール時にAndroidの内部で起きていること
APKをタップしてインストールするとき、Android OSの内部ではおおよそ次のような処理が進みます。
まずMETA-INF内の証明書を使って、ファイルが改ざんされていないかを検証します。次にAndroidManifest.xmlに書かれている権限をユーザーに提示し、確認を取ります。そのあとAPKの中身を展開してシステムの所定の場所に配置し、必要に応じてclasses.dexをARTが扱いやすい形式に変換していきます。すべての処理が終わると、ホーム画面やアプリ一覧にアイコンが表示されてインストール完了です。
この最後の変換処理は「dexopt」と呼ばれるものですが、Android 7.0以降のARTは、インストール時にすべてを一括で最適化するのではなく、AOTコンパイル・JITコンパイル・インタプリタ実行を組み合わせたハイブリッドな方式に変わっています。よく使う部分は端末が充電中でアイドル状態のときにバックグラウンドで最適化されるため、インストール自体は以前よりずっと速くなっています。
署名がなぜ重要なのか
すべてのAPKは、公開する前に開発者の秘密鍵でデジタル署名される必要があります。インストール時に署名を検証することで第三者による不正な改変を検出できますし、同じ署名を持つAPKは同じ開発者が作ったものだと判別できるため、なりすましのアプリを見分ける手がかりにもなります。さらに、既存アプリを上書き更新する場合は署名が一致していないとインストールできない仕組みになっていて、これによって別人が勝手に「アップデート」を装って別のアプリを送り込むことを防いでいます。
ここまで紹介したのはMETA-INFを使った従来の署名方式(APK Signature Scheme v1)ですが、Android 7.0以降はより堅牢なv2、Android 9以降はv3という署名方式も導入されていて、実際には複数の仕組みが組み合わさって改ざん検知を行っています。Google Playで配布する場合は、開発者自身の鍵に加えて、Googleの「Play App Signing」という機能に署名鍵自体の管理を任せるケースが一般的になっています。
APKはどこで手に入るのか
もっとも一般的なのはGoogle Playストアからのインストールで、Google Play Protectによる自動スキャンもあり安全性は高めです。AmazonアプストアやGalaxy Storeといったサードパーティストアも存在しますが、審査基準はストアによって異なります。
そのほか、APKファイルを直接ダウンロードして手動でインストールする「サイドローディング」という方法もあります。社内アプリやベータ版のように、ストアを経由せず開発者が直接配布するケースもこれに近い形です。
サイドローディングのリスクと安全装置
サイドローディングは自由度が高い一方で、リスクも伴います。Androidには「提供元不明のアプリ」を許可しない限りストア外のAPKをインストールできない仕組みが用意されていて、これは意図的に設けられた安全装置です。とはいえ、非公式サイトで配布されているAPKの中には、正規アプリを改造してマルウェアを仕込んだものも実際に存在するため油断はできません。
公式アプリと同じ署名になっているかどうかを確認すれば、改造版かどうかをある程度判断することもできます。またGoogle Play Protectは、Playストア外からインストールしたアプリについてもスキャンしてくれるので、多少の安心材料にはなります。とはいえ、信頼できる配布元以外からのインストールは慎重に行うのが賢明でしょう。
AAB(Android App Bundle)との違い
最近、Google Playへの新規アプリ公開ではAAB(.aab)形式が主流になっています。APKとAABの違いを整理すると、次のようになります。
| 項目 | APK | AAB |
|---|---|---|
| 用途 | 端末に直接インストールする最終形式 | Google Playに提出する配布用の「元データ」 |
| ダウンロードサイズ | 全端末共通の内容を含むため大きくなりがち | 端末ごとに必要な分だけ配信され、サイズを最適化できる |
| 生成の仕組み | 開発者が直接ビルド | Google PlayがAABから端末最適化されたAPKを動的に生成(Dynamic Delivery) |
つまりAABは、あくまでストア側で処理するための「元データ」であり、実際に端末にインストールされるのは、今も昔も最適化されたAPKだということになります。
開発者がよく使うコマンド
Android開発でAPKを扱う場面では、次のようなコマンドをよく目にします。
# 実機/エミュレータへインストール
adb install app.apk
# インストールサイズの最適化(アライメント調整)
zipalign -v 4 app-unsigned.apk app-aligned.apk
# APKへの署名(zipalignの後に行うのがポイント)
apksigner sign --ks my-key.jks app-aligned.apk
# APKの中身を解析(パッケージ情報など)
aapt dump badging app.apk
apksignerでv2以降の署名方式を使う場合、APKの整列情報も署名の対象に含まれるため、署名した後にファイルへ手を加えると署名自体が無効になってしまいます。そのため、zipalignで整列させてからapksignerで署名する、という順番を守る必要があります。
さいごに
APKについてざっと整理してきましたが、突き詰めれば「ZIP形式のパッケージに、コードとリソースと署名情報がまとまって入っているもの」というシンプルな話です。ただしその中には、改ざん検知や配布の仕組みなど、Androidのセキュリティを支える工夫がいくつも詰まっています。何気なくタップしている「インストール」ボタンの裏側でこれだけの処理が走っていると考えると、少し見え方が変わってくるのではないでしょうか。