本文描述把 Qt 应用程序部署到 Android 设备所需的技术步骤。
Android 上的应用程序有 2 种打包方式:APK (应用程序包) 或 AAB (Android 应用绑定)。两者是遵循预定义目录结构的 ZIP 文件。两者的区别是 APK 文件可以在设备上部署和执行,而 AAB 旨在由 Google Play 商店解释,并被用于为不同设备体系结构生成 APK 文件。
对于本地测试应用程序,APK 格式最合适,因为可以直接将其上传到设备并运行。为分发到 Google Play 商店,推荐使用有相似布局的 AAB 代替。AAB 的附加便利是可以把所有目标 ABI 包括在同一捆绑中,而不增加用户实际下载包大小。当使用 AAB 时,Google Play 商店会为发出下载请求的设备生成优化的 APK 包,并采用发布者密钥自动对其进行签名。
有关 AAB 格式的更多信息,见 Android 应用捆绑 .
在任何情况下,应用程序捆绑都是从特定目录结构生成的,包含
.so
代码文件,及应用程序所需的所有 Qt 依赖。此外,任何
.jar
文件、Java 代码、资产、资源及
.xml
文件也包括在内。
It is recommended to use Qt Creator or the Makefile created by qmake or CMake to create the application bundle.
All the steps described here are automatically handled by the build script and the androiddeployqt 部署工具 , which are run by Qt Creator by default.
注意: If you prefer building Android packages from the command line, see 构建 Android 应用程序 .
The default templates used by Qt are found in
$Qt_install_dir/src/android/templates
. The first step of making a custom package is to copy these files into an empty directory, for example
android
, under your project. Then, you need to define that path in your project's
.pro
file, using the variable
ANDROID_PACKAGE_SOURCE_DIR
:
android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android DISTFILES += \ android/AndroidManifest.xml \ android/build.gradle \ android/res/values/libs.xml }
Or with CMake use:
set(ANDROID_PACKAGE_SOURCE_DIR "${PROJECT_SOURCE_DIR}/android" CACHE INTERNAL "")
Qt Creator copies the package templates to your Android build directory (
$ANDROID_BUILD_DIR=$BUILD_DIR/android-build
) into your project build directory (
$BUILD_DIR
). If you want to build from the command line, use the following after running
qmake
or
CMake
:
make -j$(nproc) apk_install_target
The previous command copies the application's binaries and resources into the $ANDROID_BUILD_DIR. The build directory acts now as the packaging directory, which the application bundle is created from. The main parts of the package templates are described in the following sections.
The
AndroidManifest.xml
file gives detailed meta-information about your application. This information is used to customize your application bundle and by the target device to decide which features to enable, the default orientation of the application, and so on. In addition, it's used by the Google Play Store for information on the version code, device support, package name, and lots more.
更多信息有关
AndroidManifest.xml
,见
Android Manifest documentation
.
The default manifest contains some special parameters used by Qt to set up the application and load all the necessary libraries for Qt. When you are customizing your own Android manifest, make sure that it contains these parameters. For that reason, it's recommended to start with the default templates, then customize on top of that. The
androiddeployqt
tool replaces content in the templates with the correct values. The parts that are filled by
androiddeployqt
have the value as
"--
%%INSERT_VALUE%% --", as in:
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/> <meta-data android:name="android.app.repository" android:value="default"/> <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/> <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/> <!-- Deploy Qt libs as part of package --> <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/> <!-- Run with local libs --> <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/> <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/> <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/> <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
The Android Manifest is also used to define Android 服务 , and custom Android Activities .
Under
$Qt_install_dir/src/android/java/src/org/qtproject/qt5/android/bindings/
are the files comprising the Java code of the Android application. This Java code is compiled under $ANDROID_BUILD_DIR and added to the application bundle. The regular Android application launcher is a Java process, so Qt applications have a Java-based entry point. The code in here will load the required Qt libraries, based on the meta-information given in Manifest file.
After loading the libraries, the Java code will call into the application's native
main()
function on a new thread and the application will launch. At this point, the Java code in the templates is used to delegate events from Android into Qt.
One thing to note about the files in this directory is that they can contain code specific to certain Android versions. Based on the minimum required Android API level of your application it might be necessary to remove some of this code. This is done automatically by
androiddeployqt
and Qt Creator during packaging.
If your minimum Android API level is 20 or lower, the code below is removed before building, since it's not a supported API on Android API level 20. However, if your minimum API level is 21 or higher, it is left in:
//@ANDROID-21 @Override public void onActivityReenter(int resultCode, Intent data) { // Do something return super.onActivityReenter(resultCode, data); } //@ANDROID-21
Under the
$Qt_instal_dir/src/android/templates/res/
folder are Android resources that can be accessed from the
AndroidManifest.xml
and Java code used by all Qt applications.
This file can be found at
$Qt_instal_dir/src/android/templates/res/values/libs.xml
. One of the files containing meta information about the deployment of the application is
libs.xml
. It consists of the following values:
bundled_libs
: Libraries in the package's library folder which should be loaded on start-up. Library names should be specified without the
lib
prefix and
.so
suffix.
qt_libs
: Qt libraries which should be loaded on start-up. When bundled deployment is used, these are expected to be found inside the
APK
's library folder.
注意: Ministro is no longer maintained.
This file can be found at
$Qt_instal_dir/src/android/java/res/values/strings.xml
。
strings.xml
file contains strings used by the
AndroidManifest.xml
and by the deployment mechanisms.
In particular, the application name and the name of the application binary can be specified here. There are also strings that contain additional libraries that should be loaded and
JAR
files which should be included in the class path.
The main Gradle build file can be found at
$Qt_instal_dir/src/android/templates/build.gradle
. This file is required by the Gradle build system used by Android to generate the application's APK. For more information, see
Android Build Configuration Files
.
Put any resources used by your application under
$ANDROID_PACKAGE_SOURCE_DIR/res/
. A typical example of resources customization which should be placed here are the icons used by the application launcher to show your application.
Place any Java code under the path
$ANDROID_PACKAGE_SOURCE_DIR/src/
. Any code here can be used with your application, for example you can call Java methods from within Qt code. For more information, see
Qt JNI Messenger Example
.
When using Qt Creator, add the Java files to your project using DISTFILES , so they are visible under the project files.
You can place any assets that are intended to be accessed by Java code under
$ANDROID_PACKAGE_SOURCE_DIR/assets/
. For more information on using assets with Qt, see
移植到 Android
.
注意:
使用
Qt 资源系统
entails having
.qrc
files bundled in the
.so
files which must be unpacked first to be loaded by the linker, while the Android assets are compressed in the
.apk
and can be directly used in your application. That means using the Android assets can take up less space, but it's not a cross-platform solution with Qt.
Under
$ANDROID_PACKAGE_SOURCE_DIR/libs
in your custom package directory, it's possible to place libraries that should be included in the application bundle.
JAR
libraries should be placed directly under
$ANDROID_PACKAGE_SOURCE_DIR/libs/
, while shared libraries should be put in a subdirectory named after the target ABI of the libraries. The supported ABIs are: armeabi-v7a, arm64-v8a, x86, x86_64.
For more information, see also 第 3 方 Android 库 .
Starting from Qt 5.14.0, you may use the "aab" or "apk" build targets from the Makefile directly to build the application bundle. Use the following command to generate an AAB:
make -j$(nproc) aab
Or to generate the APK:
make -j$(nproc) apk
Under the hood, your Qt code is built and copied to the $ANDROID_BUILD_DIR, then
Gradle
is used to build the Java code and package the application. If an APK intended for release is built, then it should be signed with
jarsigner
and aligned with
zipalign
. For more information on signing the package with Qt Creator, see
Signing Android packages
.
Building an application package is complex, so Qt comes with a tool which handles the work for you. The steps described in this document so far are handled automatically by this tool. This section describes some of the steps that this tool facilitates.
Before running the tool manually, you need to run
qmake
or
CMake
on your project to generate
Makefiles
和
JSON
file (i.e.
android-project-deployment-settings.json
) containing important settings used by
androiddeployqt
.
注意: It is not recommended to modify the androiddeployqt JSON file.
To prepare the build for androiddeployqt, it is recommended to build your project in a separate directory. Run the following commands:
mkdir build-project cd build-project ~/Qt/5.15.0/android/bin/qmake ../project/project.pro make -j$(nproc) make -j$(nproc) apk_install_target
The only required command line argument when running the tool is
--output
. Other command line arguments are optional but useful. Here's a quick overview. More information is available by passing the
--help
argument to androiddeployqt.
自变量 | 简要描述 |
---|---|
--output <destination>
|
Specifies the destination of the final package. Set this to
$ANDROID_BUILD_DIR
, that is the build directory where you installed your application binaries.
|
--input <file name>
|
This allows you to specify the generated
JSON
settings file.
androiddeployqt
will try to guess the file name based on the current working directory.
|
--aab
|
Generate an Android Application Bundle, rather than an APK. Note that this invalidates some of the other arguments, such as
--install
.
|
--deployment <mechanism>
|
Specify this to pick a different deployment mechanism than the default. |
--install
|
Specify this to install the finished package on the target device or emulator. Note that if a previous version of the package is already installed, it will be uninstalled first, removing any data it might have stored locally. |
--device <ID>
|
Specify the ID of the target device or emulator as reported by the
adb
tool. If an ID is specified, it will be passed to all calls to
adb
. If it is unspecified, no particular device or emulator will be requested by
adb
, causing it to pick a default instead.
|
--android-platform <platform>
|
The SDK platform used for building the Java code of the application. By default, the latest available platform is used. |
--release
|
Specify this to create a release package instead of a debug package. With no other arguments, release packages are unsigned and cannot be installed to any device before they have been signed by a private key. |
--sign <url> <alias>
|
Sign the resulting package. Specifying this also implies
--release
. The URL of the keystore file and the alias of the key have to be specified. In addition, there are a number of options that can be specified which are passed through to the
jarsigner
tool. Pass
--help
to
androiddeployqt
了解更多信息。
|
--jdk <path>
|
Specify the path to the Java Development Kit. This is only required for signing packages, as it is only used for finding the
jarsigner
tool. If it is unspecified, then
androiddeployqt
will attempt to detect
jarsigner
, either using the
JAVA_HOME
environment variable, or on the
PATH
.
|
--verbose
|
Specify this to output more information about what
androiddeployqt
is doing.
|
--help
|
Prints the help for the tool. |
With a project named
project
, to directly build the application package with androiddeployqt without deploying it the device, run the following:
~/Qt/5.15.0/android/bin/androiddeployqt --input $BUILD_DIR/android-project-deployment-settings.json --output $ANDROID_BUILD_DIR --android-platform android-29 --jdk /usr/lib/jvm/java-8-openjdk-amd64 --gradle
To deploy the built package to the device:
~/Qt/5.15.0/android/bin/androiddeployqt --verbose --output $ANDROID_BUILD_DIR --no-build --input $BUILD_DIR/android-project-deployment-settings.json --gradle --reinstall --device <adb_device_id>
Qt comes with a number of plugins which are loaded at run-time when they are needed. These can handle anything from connecting to SQL databases to loading specific image formats. Detecting plugin dependencies is impossible as the plugins are loaded at run-time, but androiddeployqt tries to guess such dependencies based on the Qt dependencies of your application. If the plugin has any Qt dependencies which are not also dependencies of your application, it will not be included by default. For instance, in order to ensure that the SVG image format plugin is included, you will need to add Qt SVG module to your project for it to become a dependency of your application:
QT += svg
If you are wondering why a particular plugin is not included automatically, you can run androiddeployqt with the
--verbose
option to get the list of missing dependencies for each excluded plugin. You can achieve the same in Qt Creator by ticking the
Verbose output
check box in the
Projects
>
Build Steps
>
Build Android APK
>
Advanced Actions
.
It's also possible to manually specify the dependencies of your application. For more information, see ANDROID_DEPLOYMENT_DEPENDENCIES qmake variable.
Unless the project has special requirements such as third party libraries, it should be possible to run androiddeployqt on it with no modifications and get a working Qt for Android application.
There are two important environment variables used by Qt:
ANDROID_SDK_ROOT
: specifies the path to the Android SDK used for building the application. The Android SDK contains the build-tools, Android NDK, and Android toolchains.
ANDROID_NDK_ROOT
: specifies the path to the Android NDK used to build the application. It is not recommended to hard-code this path, since different Qt for Android versions can depend on different Android NDK versions.
注意: Qt Creator sets these variables by default.
There are a set of
qmake
variables that can be used to tailor your package. At some point during development, you will most likely want to look into these variables to customize your application.
Here is a list of some variables that are particularly interesting when making Android applications:
Also, the following
qmake
variables are primarily useful when writing a Qt module, and not normal applications:
注意: This list of variables can also be used with CMake, however see the section above about using CMake.
Qt Creator runs the androiddeployqt tool by default, and provides easy and intuitive user interfaces to specify many of the options. For more information, see Qt Creator:把应用程序部署到 Android 设备 .