Qt5.3文档翻译:将应用程序部署到安卓系统中,Deploying an Application on Android
此文章,在技术层面说明了,将一个Qt 应用程序部署到安卓设备(或市场)上所需的步骤。
建议 妳使用 androiddeployqt部署工具 或 Qt Creator 来自动进行这些动作,而不是手动进行。 以下信息会帮助 妳在一个技术层面来了解 所产生的安卓应用程序的结构, 这些信息对于编写应用程序并不是必要的。
安卓系统 中的应用程序是以特殊格式的ZIP 文件打包起来的, 这种格式 叫做 APK 。 当妳使用 qmake 和 make 来编译一个Qt 应用程序时, 所产生的是一个以正确的编译器及标志位来构建的二进制文件,适合 于在具有目标架构的安卓设备上运行。
为了让该二进制文件成为一个可运行的应用程序,需要将它放置到一个特殊的目录结构中,并且与其它的一些文件一起打包到一个APK 包中。
在 $QTDIR/src/android/java 目录中,包含着APK 包所需要的其它文件的模板。创建APK 的第一步,就是,将这些文件复制到一个空目录中。 在这篇指南中,我们将这个构建目录称为 $BUILD_TARGET 。
我们还需要确保应用程序本身的二进制文件被复制到了这个包中。对于这一点,可以在针对妳的应用程序项目文件运行了qmake 之后,再运行以下命令来实现:
make install INSTALL_ROOT=$BUILD_TARGET
它会将应用程序的二进制文件和其它需要安装起来的文件复制到打包目录中。
此刻,打包目录中会包含以下内容:
AndroidManifest.xml 文件 中包含着关于妳的应用程序的元数据。 这些信息会用到多个事物上。目标设备 会利用这个信息来决定要启用哪些特性、应用程序的默认朝向、等等。另外 ,安卓市场 也会利用这个信息来得知应用程序的版本号、对于设备的支持情况、软件包名字及一系列别的东西。
欲知更多关于 AndroidManifest.xml 文件 的信息,则阅读 安卓文档 中关于此主题的页面 。
还有一些特殊变量,当妳将它们放置到清单文件中去的时候,会被Qt识别到:
•. android.app.use_local_qt_libs : 如果 被设置为 1 ,则会预期到目标设备上找到 Qt 库。
•. android.app.bundle_local_qt_libs : 如果 被 设置 为 1 , 则 会预期 Qt 库被打包为 APK 的一部分。如果 被设置为 0 , 则会预期在目标设备的 /data/local/tmp/qt 目录中找到这些库文件。
注意 : 如果 use_local_qt_libs 被设置为 0 ,则本变量无效。
清单文件 中的其它变量用来引用各种资源, 可在下面的 资源文档 小节中找到关于这些资源文件的详细说明。
$BUILD_TARGET/src 目录 中是该安卓应用程序的Java 代码。常规 的安卓应用程序启动器就是一个 Java进程 ,所以, Qt应用程序拥有 一个基于Java 的入口。此处 的代码会根据模板中其它文件所提供的元数据来载入必需的 Qt 库。 这段代码允许使用Qt Creator 和 androiddeployqt 所支持的所有部署机制: Bundled (打包到一起) 和 Debug (调试)。
在载入了那些库之后, Java代码 会在一个新的线程上调用该应用程序的原生 main() 函数 ,此时 该应用程序就会被启动。 到这个时刻,模板 中的 Java代码 的作用就是, 将安卓系统的各种事件传递给 Qt 。
关于 这个目录中的那些文件,有一点要注意,就是,其中可能包含 着一些针对着特定安卓版本的代码。根据 妳的应用程序的最低安卓API 级别要求,可能需要删除其中 的某些代码。 androiddeployqt 和 Qt Creator 会在打包过程中自动进行这个动作。
例如,假设代码中包含以下内容:
//@ANDROID-12
@Override
public boolean dispatchGenericMotionEvent(MotionEvent ev)
{
if ( QtApplication . m_delegateObject != null && QtApplication . dispatchGenericMotionEvent != null)
return (Boolean) QtApplication . invokeDelegateMethod( QtApplication . dispatchGenericMotionEvent , ev);
else
return super . dispatchGenericMotionEvent(ev);
}
//@ANDROID-12
如果妳的最低安卓API级别是11或更低的,则,在构建之前应当删除这段代码,因为在安卓API 级别11 中不支持这个API。然而,如果妳的最低安卓API 级别是12 或更高版本,则应当留下这段代码。
$BUILD_TARGET 的 res/ 目录中,是一些安卓资源文件,可从 AndroidManifest.xml 和妳的应用程序的Java 代码中访问到它们。 一个典型的例子就是,图标文件,应当放置 在这里,安卓系统的应用程序启动器会 使用该图标来代表妳的应用程序。
在包含着访应用程序的部署相关的元数据的那些文件中,有一个是 libs.xml 。 它包含着以下值:
•. bundled_libs : 在该APK 的库目录中,需要在启动时载入的那些库。 库名字中应当不带 lib 前缀和 .so 后缀。
•. qt_libs : 应当 在启动时载入的那些 Qt 库。如果 是采用打包到一起的方式来部署的话,则 这些文件会被预期在 APK 的库目录中找到。如果采用 的是调试形式的部署方式的话, 则会从目标设备的 /data/local/tmp/qt 目录中载入它们。
•. bundled_in_lib : 要打包到 APK 的库目录中去的插件列表。 仅当采用打包到一起的部署方式的情况下,才会使用这个值。 Qt 的插件系统要求各个插件处于一个特殊的目录结构中,这个结构本身包含着插件 的分类信息。APK 的库目录中不支持这种特殊目录结构,所以, 在目录结构变平的过程中所丢失的那些信息,就要靠 bundled_in_lib 这个数组来补充。其中每个条目 都是一对路径,它们 以冒号分隔。路径 对中的第一个路径是被打包到 APK 的库目录中去的那个文件的文件名 。路径 对中的第二个, 是该文件相对于Qt 安装目录的原始路径。
•. bundled_in_assets : 被打包到 APK 的资产(asset)目录中去的其它类型的Qt 文件的列表。 仅当采用打包到一起的部署方式的情况下,才会使用这个值。其中 的各个条目的格式与 bundled_in_lib 数组 中的格式是一样的。区别 就是,路径 对中的第一个值,表示 的是应用程序的 assets 目录中的某个文件,而不是库目录中的某个文件。 这个数组,一般用于将导入的QML 文件打包起来, 在Qt 中 也要求它们具有 一个特殊的目录结构。
strings.xml 文件 中包含着 AndroidManifest.xml 及部署系统 所使用的某些字符串 。
尤其 是,可在这里指定应用程序 的名字及应用程序的二进制文件名。 还有一些字符串 ,其中包含 着需要载入 的额外的库,以及一些应当包含到类路径中去的 JAR 文件。
可在打包目录的 libs 目录中放置那些应当 被包含到应用程序包中的库。 JAR 库应当直接放置到 libs/ 目录 中, 而共享库不太一样,应当放置 到一个按照目标架构命名的子目录中。
对于那种 将Qt 打包到 APK 中去的部署方式,那些 带有 "bundled" 后缀的Qt JAR 文件应当被放置到libs 目录中。另外 ,必 要的共享库和插件也需要放置到libs 中对应的子目录下。
当妳将所有相关文件都放置到正确的位置之后, 再做几个步骤就可以打包出妳的应用程序包了。首先 ,应当生成一个构建脚本。 这可以使用谷歌的安卓软件开发工具包 中的 android 工具 来实现。
示例:
% android update project -- path $BUILD_TARGET -- target android - 9 -- name QtApp
这个命令, 会在 $BUILD_TARGET 目录中生成一个构建脚本,用于构建一个名为 QtApp 的 APK 。对应 的 Java代码 会针对 android-9 平台进行编译。
然后 ,可使用ant 工具来构建这个项目。如果 要打包一个用于发布的安装包的话,则可以分别使用 jarsigner 和 zipalign 来进行签名和对齐。
构建出一个应用程序包,是一件狠复杂的事情,所以,Qt 自带了一个工具,用来帮助妳处理这件事件。在此文档中,到目前为止所讲的步骤,都是由该工具自动处理的。
在运行这个工具之前,妳需要在项目中运行 qmake 和 make 。运行 qmake ,就会创建一个 Makefile , 还会生成一个 JSON 文件,其中包含 着 将要被 androiddeployqt 使用的重要设置信息。
然后 ,妳应当将应用程序的二进制文件( 以及任意其它必要的文件 )安装到 APK 的库目录中。如果 $BUILD_TARGET 就是妳的构建目录(如果 妳是第一次做这件事,那么,这个目录在此刻应当是空的 )的话,那么 ,妳可以使用以下命令将二进制文件安装进去:
% make install INSTALL_ROOT = $BUILD_TARGET
运行 该工具时,唯一必须提供的命令行参数就是 --output 。 这个参数应当被指定为 $BUILD_TARGET , 也就是说: 妳安装了自己的应用程序二进制文件的那个构建目录。
其它 的命令行参数都是可选的,但是都狠有用。 以下是一个快速说明。欲知更多信息, 则在运行 androiddeployqt 时指定 --help 参数。
•. --input <file name> : 可以指定由 qmake 生成的 JSON 文件。默认情况 下, androiddeployqt 会按照当前 的工作目录来猜测 该文件名。
•. --deployment <mechanism> : 使用 这个参数来选择一个不同的部署机制,而不是默认的部署机制。
•. --install : 用这个参数来将已经打包 的软件包安装到目标设备或模拟器中。注意 ,如果 该软件包的旧版本已经被安装了,则,会首先 被 卸载, 这样的话, 它在本地储存的任何数据都会被删除。
•. --device <ID> : 指定 由 adb 工具报告的目标设备或模拟器的编号。如果指定 了编号,则, 它会被传递给所有被调用的 adb 命令。如果 未指定这个参数的话,则 adb 不会指定使用哪个特定设备或模拟器,于是 就会使用某个默认目标。
•. --android-platform <platform> : 用来构建 该应用程序的Java 代码的SDK 平台版本。默认情况 下, 会使用可用的最新版平台。
•. --ant <path> : 指定 ant 可执行程序的路径。如果 未指定, 则 androiddeployqt 会尝试利用 PATH 来探测它。
•. --release : 指定 这个参数,以创建一个用于发布的软件包,而不是用于调试的软件包。如果 不带其它参数,则,发布用的软件包不会被签名,因而,在使用一个私钥签名之前,无法安装到任何设备 上去。
•. --sign <url> <alias> : 对创建出来的软件包进行签名。指定 这个参数的话, 会隐式指定 --release 参数。必须 指定密钥存储(keystore)文件 的路径 和密钥的别名(alias)。 另外,还有一些选项,可以被传递给 jarsigner 工具。 在运行 androiddeployqt 的时候指定 --help 参数,以了解更多信息。
•. --jdk <path> : 指定Java 开发工具 包的路径。 只会在对软件包进行签名时使用,因为 它只用于寻找 jarsigner 工具。如果 未指定这个参数的话,则 androiddeployqt 会根据 JAVA_HOME 环境变量或 PATH 环境变量来探测 jarsigner 。
•. --verbose : 指定 这个参数,则 androiddeployqt 会输出详细信息,说明自己在做什么。
Qt 带有一些插件, 会在运行时按照需要来载入。 这些插件狠有用,例如, 可用于连接 SQL数据库 ,可用于载入特定的图片格式。探测插件 的依赖关系是不可能的,因为插件 是在运行时载入的,但是, androiddeployqt 会尝试根据妳的应用程序的Qt 依赖关系来猜测这种依赖关系。如果 该插件还依赖了任何一个不被妳的应用程序依赖的Qt 模块的话,默认情况下不会被包含。例如, 为了确保包含 了SVG 图片格式的插件, 妳需要向妳的 .pro 文件中加入 QT += svg , 这样, Qt SVG 模块 就会成为妳的应用程序的一个依赖项。
如果 妳狠好奇为什么某个插件没被自动包含的话,那么, 妳可以加上 --verbose 参数来运行androiddeployqt, 这样就可以知道,对于每个 被排除的插件,都缺少些什么依赖。 妳可以在 Qt Creator 中实现同样的效果, 只需在 Deployment configurations 中选中 Verbose output 复选框就行了。 这个选项位于 妳的 项目 设置的 运行 标签页中。
也可以手动指定妳的应用程序的依赖关系。参考下面 所说的 ANDROID_DEPLOYMENT_DEPENDENCIES qmake 变量 的文档。
除非 该项目有着特殊的需求,例如第三方库,否则 的话,应当 可以在不做任何修改的情况下运行 androiddeployqt 以产生出一个能够正常工作的用于安卓的Qt 应用程序。
然而 ,有一系列的 qmake 变量 可用于调整妳的软件包。 在开发过程中的某个时间点, 妳可能会想要看看这些变量,因为,它们都有着自己的作用,比如说, 可以用来设置妳的应用程序的名字,这个名字会显示在设备的应用程序菜单中。
以下是一些在创建安卓应用程序包的时候特殊有用的变量:
•. ANDROID_DEPLOYMENT_DEPENDENCIES : 默认情况下, androiddeployqt 会为妳的应用程序探测依赖关系。但是,由于 在运行时对插件的使用是无法探测的,因此,可能存在误报,因为 妳的应用程序可能会 潜在 地 依赖某个插件。如果 妳想减小妳的 APK 的尺寸的话, 可使用 ANDROID_DEPLOYMENT_DEPENDENCIES 变量 来覆盖掉这种自动探测的行为。其中应当包含 着所有需要包含进来的Qt 文件的列表,它们 的路径都是相对于Qt 的安装根目录的。注意 ,只有在这里指定的那些 Qt文件 会被包含。如果没有包含正确 的文件,可能会造成崩溃。
•. ANDROID_PACKAGE_SOURCE_DIR : 这个变量指定的是一个目录, 可在该目录中 对默认的安卓软件包模板文件进行追加和修改。 androiddeployqt 工具 会将应用程序模板文件从 Qt 中复制到打包目录中,然后 将 ANDROID_PACKAGE_SOURCE_DIR 中的文件也复制到打包目录中,覆盖掉任何已有的同名文件。之后 , 妳对其它选项所做的修改,所引发的 源代码自动 更新步骤,会 在合并过后的目录中进行。 举个例子,如果 妳想 为妳的应用程序添加一个自定义的 AndroidManifest.xml ,则,将该文件直接放置到这个变量所指的目录中。 妳还可以向 ANDROID_PACKAGE_SOURCE_DIR/src 目录中添加自定义的 Java文件。
注意 : 当妳向自己 的项目中加入自定义版本的构建文件(例如 strings.xml 、 libs.xml 、 AndroidManifest.xml等等 )时, 要确保最初是从软件包模板中将它们复制出来的, 模板 的路径是 $QT/src/android/java 。 妳不应当从构建目录中将文件复制出去,因为 这些文件已经根据当前的构建设置而修改过了。
•. ANDROID_EXTRA_LIBS : 一个外部库列表,这些库会被复制到妳的应用程序的库目录中,并且在启动时载入。 这些库可用来做狠多事情,例如, 为妳的应用程序提供OpenSSL 支持。只需 将所需要的 libssl.so 和 libcrypto.so 库的路径写在这里,应当 就会自动启用OpenSSL 支持了。
Qt Creator 会为妳运行 androiddeployqt 工具 , 它还提供了简单直观的界面, 让妳可以设置多种选项。欲知更多信息, 则参考 Qt Creator文档 。
Your opinions
HxLauncher: Launch Android applications by voice commands