CMakeでAndroidアプリを作る
- https://github.com/okuoku/grpcore0
- http://d.hatena.ne.jp/mjt/20160421/p1
- 前々回(XboxOne)
- http://d.hatena.ne.jp/mjt/20160511/p1
- 前回(EmscriptenによるJavaScript)
Androidは基本的に全てのアプリは何らかのJavaクラスでなければならない。Android2.3以降にはNativeActivityクラスが存在し一応Javaなしで開発できるように配慮はされている。が、結局AndroidシステムなりミドルウェアなりのJavaクラスとやりとりする機会がいつか出てきてしまうので、Javaコードを書く余地を残しておくことが望ましい。
一般的なCMakeのプロジェクトモデルと合わないのは:
そもそもCMake自身のJavaサポートが厳しい。今回はCMakeはCコードのビルドにだけ使用している。Java(を使ったパッケージング)はAndroid公式のGradleを使っている。
マルチアーキテクチャである。Androidのネイティブアプリケーションは、
に分けられる。
もっとも、実際にはリリースされているIntelベースAndroidのほぼ全てでARMバイナリは実行可能で、かつ、Unity5のようなメジャーゲームエンジンがARM NEON必須だったりといった状況があるので、真剣にマルチアーキテクチャ対応を行う意義は薄い。重要なのはIntel向けのバイナリを用意するとホスト側のIntel版Androidエミュレータで実行できるという点。
今回はVisualStudioでネイティブ側の開発を行いたいのでMSが用意しているCMakeパッチを使用した。
- https://blogs.msdn.microsoft.com/vcblog/2014/11/12/cross-platform-mobile-development-with-visual-c/
- Android MDDの導入
- https://blogs.msdn.microsoft.com/vcblog/2015/12/15/support-for-android-cmake-projects-in-visual-studio/
- CMakeパッチの説明
blogで説明されているようにパッチされたCMakeをビルドし、
cmake.exe -G "Visual Studio 14 ARM" -DCMAKE_SYSTEM_NAME=VCMDDAndroid c:\path\to\here
のようにしてCMakeを実行すれば、Androidの.soを生成するソリューションが作成される。
...当然.so単体ではAndroid上で実行できないので、カスタムターゲット apk として、ビルドした.soのコピーとgradleを使ったビルドを行うものを用意した。
# Android packaging set(deploy_dest ${CMAKE_CURRENT_SOURCE_DIR}/pkg/android/src/main/libs/armeabi-v7a/libgrpcore0.so) add_custom_command( OUTPUT ${deploy_dest} COMMAND ${CMAKE_COMMAND} -DIN=$<TARGET_FILE:grpcore0> -DOUT=${deploy_dest} -P ${CMAKE_CURRENT_LIST_DIR}/cmake/deploy_file.cmake ) add_custom_target(grpcore0_deploy DEPENDS ${deploy_dest}) add_dependencies(grpcore0_deploy grpcore0) add_gradle_command(apk ${CMAKE_CURRENT_SOURCE_DIR}/pkg/android build) add_dependencies(apk grpcore0_deploy) add_gradle_command(apk_clean ${CMAKE_CURRENT_SOURCE_DIR}/pkg/android clean)
(add_gradle_commandは適当な独自コマンド: https://github.com/okuoku/grpcore0/blob/b99fd3ba45ba253846b0d3cfa174360e347e2186/cmake/Grpcore0Android.cmake#L4 )
.soを ${CMAKE_CURRENT_SOURCE_DIR}/pkg/android/src/main/libs/armeabi-v7a にコピーしていることから判るように、現状.apkのビルドをソースツリー内で行っている。これは非常にダサいが避ける良い方法が思いあたらなかった。
今回移植層としてはSDL2を使っているので、SDL2のJava側のビルドはGradleで行うようにビルドルールを用意している。https://github.com/okuoku/grpcore0/tree/b99fd3ba45ba253846b0d3cfa174360e347e2186/pkg/android
Android Studio: Unexpected error while executing: am start -n ... で起動しない問題
Android StudioはデフォルトでInstant runを使うように変更されたようだ。というわけで、プロジェクトをロードしたときの指示に従ってビルドツールをアップデートする必要がある。
--- a/pkg/android/build.gradle +++ b/pkg/android/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0+' + classpath 'com.android.tools.build:gradle:2.1.0' } }
http://stackoverflow.com/questions/36530648/session-app-error-launching-activity のように、設定からInstant runを無効にするという対策法も一応存在する。
Visual Studio: ネイティブデバッグできない問題
そもそもPermissionにINTERNET入れてなかった。。
--- a/pkg/android/src/main/AndroidManifest.xml +++ b/pkg/android/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ <!-- Allow writing to external storage --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.INTERNET" /> <!-- Create a Java class extending SDLActivity and place it in a directory under src matching the package, e.g.
PermissionにINTERNETを指定する以外に、gdbserverを手動で配備する必要がある。デフォルトのインストールパスでは"C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r10e\prebuilt\android-arm\gdbserver\gdbserver"にあるので、これを.soと同じディレクトリに置く。
Android studioのLLDBデバッガに比べて、スレッド名が出ないなど諸々微妙な点は有る。
Visual StudioとAndroid Studioを同時に起動すると互いに自分が起動したadbをkill-serverし合うという難易度の高い状態にハマることがある。VS側には(Xamarinの)adb command promptが有るので、これを使ってadb connectなりなんなりをやりなおす必要がある。