Browse Source

doc: document the new android_create_apk() macro.

pull/297/head
Vladimír Vondruš 8 years ago
parent
commit
cab8f2be64
  1. 2
      doc/changelog.dox
  2. 232
      doc/platforms-android.dox

2
doc/changelog.dox

@ -88,6 +88,8 @@ r<Player<T, K>>>)
@subsection changelog-latest-buildsystem Build system
- Experimental support for creating Android APKs directly using CMake without
Gradle involved. See @ref platforms-android-apps for more information.
- The `Magnum::AndroidApplication` target was missing a few dependency
libraries when Magnum was used as a CMake subproject

232
doc/platforms-android.dox

@ -39,10 +39,13 @@ command-line tools, without Android Studio involved.
At the very least you need to have Android SDK and Android NDK installed.
Running console utilities and tests on the device don't need much more, in case
you want to develop actual applications, you need also Gradle and SDK platform +
SDK platform build tools for version of your choice. Gradle is able to download
all the dependencies on its own, however it's also possible to install system
packages for a cleaner setup.
you want to develop actual applications, you need also the SDK and a platform +
SDK platform build tools for version of your choice.
For APK building it's possible to use either an experimental support in CMake
or the official way with Gradle. Gradle is able to download all the
dependencies on its own, however it's also possible to install system packages
for a cleaner setup.
@note On ArchLinux it's the `gradle` package and the following AUR packages,
adapt the version numbers as necessary:
@ -95,14 +98,6 @@ information about OpenGL testing.
@section platforms-android-apps Building and installing graphics apps
Building of graphics applications is managed fully using Gradle, which also
builds your CMake project internally. It's possible to use other means such as
`ndk-build`, but CMake is the officially preferred way. The following guide
assumes you have Gradle installed in a system-wide location available in
@cb{.sh} $PATH @ce. See the [Gradle installation docs](https://docs.gradle.org/current/userguide/installation.html)
for more information, @ref platforms-android-gradlew "see below" if you want to
use the `gradlew` wrappers instead.
In case you don't have an OpenGL ES build set up yet, you need to copy
`FindEGL.cmake` and `FindOpenGLES2.cmake` (or `FindOpenGLES3.cmake`) from the
[modules/](https://github.com/mosra/magnum/tree/master/modules) directory in
@ -139,9 +134,134 @@ else()
endif()
@endcode
Then you need to create a `build.gradle` file that references your root
`CMakeLists.txt`. Assuming it's saved right next to your root `CMakeLists.txt`,
the most minimal version might look like this:
@subsection platforms-android-apps-manifest Android manifest file
For Android you additionally need an `AndroidManifest.xml` file, which
describes various properties of the Android package. A minimal stripped-down
version is:
@code{.xml-jinja}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="{{ package }}" android:versionCode="1" android:versionName="1.0">
<uses-feature android:glEsVersion="0x00020000" />
<application android:label="{{ app_name }}" android:hasCode="false">
<activity android:name="android.app.NativeActivity" android:label="{{ app_name }}">
<meta-data android:name="android.app.lib_name" android:value="{{ lib_name }}" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@endcode
Replace @cb{.jinja} {{ package }} @ce with Java-like package name for your app
(in this case it could be e.g. @cpp "cz.mosra.magnum.my_application" @ce, for
example), @cb{.jinja} {{ app_name }} @ce with human-readable app name that's
displayed in the system (so e.g. @cpp "My Application" @ce) and finally the
@cb{.jinja} {{ lib_name }} @ce is name of the library that you compiled with
CMake, which in this case would be @cpp "my-application" @ce.
The @cb{.xml} <uses-feature android:glEsVersion="0x00020000" /> @ce says that
the minimal OpenGL ES version is 2.0, change it in case you require a different
version. Consult [the Android developer documentation](https://developer.android.com/guide/topics/manifest/manifest-intro.html)
for further information about the manifest file.
With this set up, you have two options how to build the final APK, either using
plain CMake or using Gradle.
@subsection platforms-android-apps-cmake Using CMake
The `toolchains` repository contains an `UseAndroid.cmake` module that allows
you to create an APK in a significantly faster and simpler way than when using
Gradle.
@attention This feature is in an experimental stage and at this time it doesn't
support compilation of any resources (such as icons) or Java sources. It
also builds only the ABI and configuration that corresponds to the
particular CMake build directory. It's thus recommended to employ this
approach for fast iteration during development alongside the classic Gradle
build @ref platforms-android-apps-gradle "described below" that will get
used for the final release builds.
Download contents of the toolchains repository from https://github.com/mosra/toolchains
or add it as a Git submodule, add its module path to `CMAKE_MODULE_PATH` and
include the `UseAndroid` module. Wrapping it in a check for presence of
`CMAKE_ANDROID_NDK` will make it possible to have the pure CMake and a Gradle
build coexist --- because Gradle internally uses CMake 3.6 which doesn't know
about `CMAKE_ANDROID_NDK` yet.
@code{.cmake}
if(CORRADE_TARGET_ANDROID AND CMAKE_ANDROID_NDK)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/toolchains/modules/")
include(UseAndroid)
endif()
@endcode
On the first run, the macro will attempt to detect SDK location, Android Build
Tools version and Android Platfrom version and it prints them to the output
like this:
@code{.shell-session}
$ cmake .
-- ANDROID_SDK not set, detected /opt/android-sdk
-- ANDROID_BUILD_TOOLS_VERSION not set, detected 27.0.3
-- ANDROID_PLATFORM_VERSION not set, detected 27
@endcode
If you don't like what it detected (or the detection failed), edit these values
in CMake cache. After that, pass your library target name and location of the
`AndroidManifest.xml` file to @cmake android_create_apk() @ce. Continuing from
the above:
@code{.cmake}
add_library(my-application SHARED MyApplication.cpp)
android_create_apk(my-application AndroidManifest.xml)
@endcode
Note that even thought it doesn't make any sense, the `aapt` tool *demands* the
manifest file to be called exactly `AndroidManifest.xml`. It can be, however,
in any location. This will create an APK named `my-application.apk` and
additionally also provide a new target, `my-application-deploy`, that will use
`adb install -r` to install the built APK on the device. Building and uploading
the application can be then done in a single step:
@code{.shell-session}
$ ninja my-application-deploy
[5/5] Installing my-application.apk
Success
@endcode
(Or e.g. `cmake --build . --target my-application-deploy` if you don't use
Ninja.)
For full compatibility with the Gradle build wrap the call again in a check for
`CMAKE_ANDROID_NDK` and put the manifest in the `src/main` subdirectory, where
Gradle expects it:
@code{.cmake}
add_library(my-application SHARED MyApplication.cpp)
if(CMAKE_ANDROID_NDK)
android_create_apk(my-application src/main/AndroidManifest.xml)
endif()
@endcode
@subsection platforms-android-apps-gradle Using Gradle
Besides plain CMake and Gradle it's also possible to use the classic
`ndk-build`. but that's the least recommended way and it might not be supported
in newer NDK builds. The following guide assumes you have Gradle installed in a
system-wide location available in @cb{.sh} $PATH @ce. See the
[Gradle installation docs](https://docs.gradle.org/current/userguide/installation.html)
for more information, @ref platforms-android-gradlew "see below" if you want to
use the `gradlew` wrappers instead.
Create a `build.gradle` file that references your root `CMakeLists.txt`.
Assuming it's saved right next to your root `CMakeLists.txt`, the most minimal
version might look like this:
@code{.gradle}
buildscript {
@ -207,38 +327,8 @@ android {
The [official documentation](https://developer.android.com/studio/projects/gradle-external-native-builds.html#configure-gradle)
contains a more complete overview of all possibilities.
Another important file is `src/main/AndroidManifest.xml`, which says some
properties about the Android package. The location is also important, it has to
be placed inside `src/main` subdirectory, *not* straight besides the
`build.gradle` file. A minimal stripped-down version is:
@code{.xml-jinja}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="{{ package }}" android:versionCode="1" android:versionName="1.0">
<uses-feature android:glEsVersion="0x00020000" />
<application android:label="{{ app_name }}" android:hasCode="false">
<activity android:name="android.app.NativeActivity" android:label="{{ app_name }}">
<meta-data android:name="android.app.lib_name" android:value="{{ lib_name }}" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@endcode
Replace @cb{.jinja} {{ package }} @ce with Java-like package name for your app
(in this case it could be e.g. @cpp "cz.mosra.magnum.my_application" @ce, for
example), @cb{.jinja} {{ app_name }} @ce with human-readable app name that's
displayed in the system (so e.g. @cpp "My Application" @ce) and finally the
@cb{.jinja} {{ lib_name }} @ce is name of the library that you compiled with
CMake, which in this case would be @cpp "my-application" @ce.
The @cb{.xml} <uses-feature android:glEsVersion="0x00020000" /> @ce says that
the minimal OpenGL ES version is 2.0, change it in case you require a different
version. Consult [the Android developer documentation](https://developer.android.com/guide/topics/manifest/manifest-intro.html)
for further information about the manifest file.
For the `AndroidManifest.xml` file, Gradle expects it to be placed inside the
`src/main` subdirectory, *not* straight besides the `build.gradle` file.
With everything set up, you are now ready to build the project by simply
executing the following from the directory with your `build.gradle`. During the
@ -310,7 +400,10 @@ cmake .. \
cmake --build . --target install
@endcode
And the `build.gradle` for your app then looks like this:
The `build.gradle` for your app then looks like below.
@attention Building multiple ABIs is currently not supported with the CMake
@cmake android_create_apk() @ce macro, using Gradle is the only way.
@code{.gradle}
buildscript {
@ -618,6 +711,49 @@ gradle build
@section platforms-android-troubleshooting Troubleshooting
@subsection platforms-android-troubleshooting-signing-failed Signing the APK using CMake fails
At the moment the location and passphrase for the Android signing keystore is
implicitly set to @cb{.sh} $HOME/.android/debug.keystore @ce with `android` as
a password, since that's the location (and password) that Gradle uses. If you
see output similar to this:
@code{.shell-session}
[1/2] Signing my-application.apk
FAILED: my-application.apk
Failed to load signer "signer #1"
java.io.FileNotFoundException: <home>/.android/debug.keystore
@endcode
then you either don't have the keystore generated yet or it's in some other
location. Similar error can happen if the password is incrrect, in which case
it will say the following instead:
@code{.shell-session}
Failed to load signer "signer #1"
java.io.IOException: Keystore was tampered with, or password was incorrect
@endcode
Generating a debug keystore can be done by running through the Gradle build at
least once. It's also possible to create a keystore
[using Android Studio](https://developer.android.com/studio/publish/app-signing#generate-key)
or using the `keytool` utility that's bundled with Java SDK.
The location and password is controlled via the `ANDROID_APKSIGNER_KEY`
variable, edit your CMake cache to point it to a different location or
password. Note that the command parameters have to be delimited by `;` instead
of a space. For example, setting the location to `/etc/android.keystore` with a
password `secret` can be done like this:
@code{.sh}
cmake . -DANDROID_APKSIGNER_KEY="--ks;/etc/android.keystore;--ks-pass;pass:secret"
@endcode
You can also add further arguments to `apksigner` here. See the
[official documentaton for apksigner](https://developer.android.com/studio/command-line/apksigner)
for details.
@subsection platforms-android-troubleshooting-cant-find Gradle CMake can't find dependencies
Gradle by default searches only in the NDK install path. If you have your

Loading…
Cancel
Save