2 个版本
0.5.1 | 2020 年 1 月 8 日 |
---|---|
0.5.0 | 2020 年 1 月 7 日 |
#15 in #apk
在 cargo-flutter 中使用
80KB
1.5K SLoC
已被 https://github.com/rust-windowing/android-ndk-rs 废弃,该库与 winit master 兼容
Android 粘合剂
用法
使用 Docker
编译 Android 的最简单方法是使用 Docker 和 philipalldredge/cargo-apk 镜像。
为了构建 APK,只需这样做
docker run --rm -v <path-to-local-directory-with-Cargo.toml>:/root/src philipalldredge/cargo-apk cargo apk build
例如,如果您在 Linux 上,并且想在当前工作目录中编译项目。
docker run --rm -v "$(pwd):/root/src" -w /root/src philipalldredge/cargo-apk cargo apk build
不要在 /root
上挂载卷,否则会删除 Cargo 的本地安装。
构建完成后,您应该在 target/android-artifacts/debug/apk
中获得一个 Android 包。
手动使用
设置您的环境
在您可以为 Android 编译之前,您需要设置您的环境。这需要在每个系统上只做一次。
- 安装
rustup
。 - 运行
rustup target add <target>
为您想要编译的所有受支持的 target。构建将尝试为所有受支持的 target 进行构建,除非通过Cargo.toml
调整构建目标。rustuptarget add armv7-linux-androideabi
rustuptarget add aarch64-linux-android
rustuptarget add i686-linux-android
rustuptarget add x86_64-linux-android
- 安装 Java JRE 或 JDK(在 Ubuntu 上,
sudo apt-get install openjdk-8-jdk
)。 - 下载并解压 Android NDK。
- 下载并解压 Android SDK。
- 在SDK中安装一些组件:
./android-sdk/tools/bin/sdkmanager "platform-tools" "platforms;android-29" "build-tools;29.0.0"
。 - 使用
cargo install cargo-apk
安装cargo-apk
。 - 设置环境变量
NDK_HOME
为NDK的路径,将ANDROID_HOME
设置为SDK的路径。
编译
在Android crate的根目录中运行cargo apk build
。您可以使用与常规cargo build
相同的选项。
这将在target/android-artifacts/<debug|release>/apk
中构建Android包。
编译多个二进制文件
cargo apk build
支持使用与cargo build
相同的参数构建多个二进制文件和示例。它将为每个二进制文件生成一个APK。
bin目标的Android包位于target/android-artifacts/<debug|release>/apk
。
example目标的Android包位于target/android-artifacts/<debug|release>/apk/examples
。
在Android模拟器上测试
启动模拟器,然后运行
cargo apk run
这将安装您的应用程序到模拟器,然后运行它。
如果您只想安装,请使用cargo apk install
。
要显示日志,请运行:cargo apk logcat | grep RustAndroidGlueStdouterr
与Android接口
如果应用程序没有访问屏幕、用户输入等,那么它就不是很有用。
android_glue
crate提供FFI与Android环境的接口,用于那些不在stdlib中的功能。
工作原理
构建过程
构建过程通过以下方式工作:
- 使用rustc始终将您的crate编译为共享库,方法是
- 创建一个自定义CMake工具链文件并设置环境变量,这些变量暴露了NDK提供的适当的构建工具,以便与
cc
和cmake
crate一起使用。 - 在crate根目录相同的目录中创建一个临时文件。这个临时文件作为静态库的crate根。它包含原始crate根的内容以及一个
android_main
实现。 - 编译
android_native_app_glue
的分支版本。android_native_app_glue
由 NDK 提供。它提供了 Android 的NativeActivity
所使用的入口点,该入口点调用android_main
。 - 使用 NDK 提供的链接器进行链接。
- 创建一个自定义CMake工具链文件并设置环境变量,这些变量暴露了NDK提供的适当的构建工具,以便与
此第一步输出一个共享库,并且针对每个目标架构运行一次。
然后,命令使用共享库、生成的清单文件和 Android SDK 的工具构建 APK。如果使用 C++ 标准库,则将相应的共享库添加到 APK 中。它使用 Android 开发工具默认的调试密钥库对 APK 进行签名。如果密钥库不存在,它将使用 JRE 或 JDK 的 keytool 创建它。
支持的 [package.metadata.android]
条目
# The target Android API level.
# "android_version" is the compile SDK version. It defaults to 29.
# (target_sdk_version defaults to the value of "android_version")
# (min_sdk_version defaults to 18) It defaults to 18 because this is the minimum supported by rustc.
android_version = 29
target_sdk_version = 29
min_sdk_version = 26
# Specifies the array of targets to build for.
# Defaults to "armv7-linux-androideabi", "aarch64-linux-android", "i686-linux-android".
build_targets = [ "armv7-linux-androideabi", "aarch64-linux-android", "i686-linux-android", "x86_64-linux-android" ]
# The following values can be customized on a per bin/example basis. See multiple_targets example
# If a value is not specified for a secondary target, it will inherit the value defined in the `package.metadata.android`
# section unless otherwise noted.
#
# The Java package name for your application.
# Hyphens are converted to underscores.
# Defaults to rust.<target_name> for binaries.
# Defaults to rust.<package_name>.example.<target_name> for examples.
# For example: for a binary "my_app", the default package name will be "rust.my_app"
# Secondary targets will not inherit the value defined in the root android configuration.
package_name = "rust.cargo.apk.advanced"
# The user-friendly name for your app, as displayed in the applications menu.
# Defaults to the target name
# Secondary targets will not inherit the value defined in the root android configuration.
label = "My Android App"
# Internal version number used to determine whether one version is more recent than another. Must be an integer.
# Defaults to 1
# See https://developer.android.com.cn/guide/topics/manifest/manifest-element
version_code = 2
# The version number shown to users.
# Defaults to the cargo package version number
# See https://developer.android.com.cn/guide/topics/manifest/manifest-element
version_name = "2.0"
# Path to your application's resources folder.
# If not specified, resources will not be included in the APK
res = "path/to/res_folder"
# Virtual path your application's icon for any mipmap level.
# If not specified, an icon will not be included in the APK.
icon = "@mipmap/ic_launcher"
# Path to the folder containing your application's assets.
# If not specified, assets will not be included in the APK
assets = "path/to/assets_folder"
# If set to true, makes the app run in full-screen, by adding the following line
# as an XML attribute to the manifest's <application> tag :
# android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen
# Defaults to false.
fullscreen = false
# The maximum supported OpenGL ES version , as claimed by the manifest.
# Defaults to 2.0.
# See https://developer.android.com.cn/guide/topics/graphics/opengl.html#manifest
opengles_version_major = 3
opengles_version_minor = 2
# Adds extra arbitrary XML attributes to the <application> tag in the manifest.
# See https://developer.android.com.cn/guide/topics/manifest/application-element.html
[package.metadata.android.application_attributes]
"android:debuggable" = "true"
"android:hardwareAccelerated" = "true"
# Adds extra arbitrary XML attributes to the <activity> tag in the manifest.
# See https://developer.android.com.cn/guide/topics/manifest/activity-element.html
[package.metadata.android.activity_attributes]
"android:screenOrientation" = "unspecified"
"android:uiOptions" = "none"
# Adds a uses-feature element to the manifest
# Supported keys: name, required, version
# The glEsVersion attribute is not supported using this section.
# It can be specified using the opengles_version_major and opengles_version_minor values
# See https://developer.android.com.cn/guide/topics/manifest/uses-feature-element
[[package.metadata.android.feature]]
name = "android.hardware.camera"
[[package.metadata.android.feature]]
name = "android.hardware.vulkan.level"
version = "1"
required = false
# Adds a uses-permission element to the manifest.
# Note that android_version 23 and higher, Android requires the application to request permissions at runtime.
# There is currently no way to do this using a pure NDK based application.
# See https://developer.android.com.cn/guide/topics/manifest/uses-permission-element
[[package.metadata.android.permission]]
name = "android.permission.WRITE_EXTERNAL_STORAGE"
max_sdk_version = 18
[[package.metadata.android.permission]]
name = "android.permission.CAMERA"
环境变量
Cargo-apk 设置环境变量,这些变量用于将适当的 C 和 C++ 构建工具暴露给构建脚本。主要目的是支持构建具有使用 cc
和 cmake
克隆的构建脚本的 crate。
- CC:NDK 提供的针对适当目标和 android 平台的
clang
包装器的路径。 - CXX:NDK 提供的针对适当目标和 android 平台的
clang++
包装器的路径。 - AR:NDK 提供的
ar
的路径。 - CXXSTDLIB:使用 NDK 提供的完整功能的 C++ 标准库。
- CMAKE_TOOLCHAIN_FILE:生成 CMake 工具链的路径。此工具链设置 ABI,覆盖任何指定的目标,并包括 NDK 提供的工具链。
- CMAKE_GENERATOR:默认为
Unix Makefiles
,而不是使用 CMake 的默认设置,这可能不适合某些平台。 - CMAKE_MAKE_PROGRAM:NDK 提供的 make 的路径。
C++ 标准库兼容性问题
当 crate 链接到 C++ 标准库时,使用 NDK 提供的共享库版本。不幸的是,依赖项加载问题会导致应用程序在较旧的 Android 版本上崩溃。一旦所有平台上的 lld
链接器问题得到解决,cargo apk 将更新为链接到静态 C++ 库。这应该解决兼容性问题。
依赖项
~35–48MB
~1M SLoC