C/C++ アプリ(NativeActivity)の Android APK を cmake で作るメモ(SDK 28+, Android 9 以降. 2020 年 2 月 2 日時点)

## 背景

* Android Studio でビルドしたくない
  * SDK のダウンロードとかでは使った方が楽かと思います 
* gradle を使いたくない
* C/C++ でグラフィックスや機械学習コードを cli で動かしたいがメインなので, Java レイヤーとか作る必要がない
* cmake のビルドで ./a.out を作る感じで apk まで作りたい(e.g. CI 向け)
 
## 参考情報

C++ メインな Android アプリの APK を gradle を使わずビルドする
https://qiita.com/syoyo/items/1a8a603e5b9bacf5f2b5

NativeActivity サンプル
https://developer.android.com/ndk/samples/sample_na

CMake script for creating/running Android APK
https://github.com/hunter-packages/android-apk

Build Android NDK project with Cmake
https://stackoverflow.com/questions/19207721/build-android-ndk-project-with-cmake

## 環境

ネットで漁るとかなり古い情報(~2013)がひっかかり, 最近の Android SDK では対応していなかったり(e.g. `android` コマンド)するので注意です. 以下の環境を想定します.

* Android SDK tools version 26+
* Android SDK Build-Tools version 29.0.3+
* Android SDK version(API level) 28+(Android 9+)
  * API level 26 から NativeActivity で no JAVA コード実行対応していますので, 一応 minSdkLevel 26 にすれば Android 8 でも動きます. 
* Android NDK r21+(一応 r19+ でも動くと思われます)
* Android sdkmanager で落とせる Android 向けにカスタマイズされた CMake(3.10) or 通常の cmake 3.7 以上 
  * https://developer.android.com/ndk/guides/cmake
 
デバッグ APK 用の鍵生成とか, SDK のダウンロードとかはコマンドラインだとめんどいので, Android Stuio 入れて落としておいたほうが楽かと思います.

また, 開発環境は Linux を想定します(少量の変更で Windows, macOS でも動作させることができると思います)


## 事前準備

NDK, SDK などのインストール, zipalign などへパスを通しておく.

debug 用の keystore はコマンドラインで `keytool` でも生成できます.

debug用keystoreについて調べてみた
https://qiita.com/taka0125/items/c408df4061a0af49c9b3

## 手順

* NativeActivity ベースで `AndroidManifest.xml` を生成する.
  * meta-data に .so の名前を記述しておく必要があるので注意. https://qiita.com/syoyo/items/c4ea702bf2ac4b2600e0
* CMake で .so をビルド
* CMake カスタムコマンドで, 以下を行う
  * APK のファイルレイアウトに添うように `AndroidManifest.xml`, `lib` フォルダ(.so を含んでいる)を配置する
  * `aapt` で APK を作成
  * `jarsigner` or `apksigner` で署名
    * 自前で作った keystore か, Android Studio(or gradle?) で生成されるデバッグ用の鍵 `~/debug.keystone` を使う.
      * storepass, keypass は `android` になっていると思われる. 
  * `zipalign` でアライン
  * optional で `adb` で apk インストールなどする 

jarsigner の場合は zipalign 前, apksigner の場合は zipalign した後に呼ぶ必要があります.

SDK 26 あたりから `apksigner` が推奨になったようですので, 可能なかぎり `apksinger` を使いましょう.

SDK tool に `apksigner` などありますが, Ubuntu 18.04 だと, `aapt`, `apksigner`, `zipalign` は apt でも入ります. 

APK を作る CMake 例は以下を参考ください.
https://github.com/lighttransport/mlspv/tree/master/cmake/android

mlspv のは, OrbitEngine のを参考にしています.
https://github.com/mlomb/OrbitEngine

aapt などはパスが通っていることを想定しています.

OrbitEngine のは古い `android` コマンドや `ant` ビルドを想定していて動かないので, そのあたり mlspv のほうに修正を入れています.

### AndroidManifest.xml

Java コードを使わない(システムにインストールされている NativeActivity)を使う場合は,

```
hasCode="false"
```

にし,

```
activity android:name="android.app.NativeActivity"
```

と `android.app.NativeActivity` を指定します.


```
meta-data android:name="android.app.lib_name"
```

で .so のファイル名を指定します.

`android:exported` は "true" がいいかもしれません.

https://developer.android.com/guide/topics/manifest/service-element

### libc++_shared.so

`ANDROID_STL` を `c++_shared` にしている場合は, `libc++_shared.so` を NDK からコピってきて apk パッケージに入れるのを cmake custom command で記述します.

#### address saintizzer, vulkan validation layers など

その他 .so も, 必要に応じてパッケージングするのを cmake に記述します.

Android Vulkan で ValidationLayers をインストール, 有効にするメモ
https://qiita.com/syoyo/items/2e6f9b999452ac6c041f

Android + cmake で ASAN(Address Sanitizer)を使う
https://qiita.com/syoyo/items/4f01e6946ad0aee733f7

### adb 注意点

adb も含めて cmake custom command で実行する場合, adb でデバイスに接続していないとそのまま反応がないようです. cmake custom command + ninja でビルドするとメッセージが出ずにハマります(Makefile ビルドではメッセージが出る). 

adb コマンドでは timeout 指定できなようなので, bash で timeout 使うなどする必要があります.

https://stackoverflow.com/questions/26985629/adb-wait-for-devices-timeout-nonblocking

Windows は個別のバッチスクリプトをでっちあげないと cmake custom command 実行はa難しいかも?

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/timeout_1

もしくは, fb-adb でなにかできるかも? > https://github.com/facebook/fb-adb

### Windows ビルド対応

このようなバッチスクリプトで, cmake -> ninja で APK ビルドできるようになりました.

https://github.com/lighttransport/mlspv/blob/master/windows-android-apk.bat

現状 SDK, NDK などへいくらかパスを通しておく必要はあります.

### optional

debug build は, `ant` を使う手もありますが, この場合 `build.xml` を作ってくれる `android update project` は廃止されたので, なんらかの方法で `build.xml` など作ることになります.

## TODO

* [ ] 普通に adb install だと Android Studio, Flutter などと比べてインストールまでの処理が遅い気がするので, 高速に adb install できる方法があるか調べる
* [ ] Java 依存をさらに減らす(apksigner などを, C++ で再実装したものなどで代用できないか)
* [ ] cmake で, Android SDK, NDK などのパスをうまく環境変数などから拾ってきて設定する.
* [ ] asset, resource ファイルを扱う.
* [ ] APK 作るところを meson の python で記述し, meson でもビルドできるようにする.
* [ ] Hunter の cmake APK を参考にして, cmake スクリプトを改善する
* [ ] ndk-gdb or lldb で CLI でデバッグする手順を確認する.
* [ ] cmake だけで完結するので, VSCode などと連携できるようにする