#android #cargo-build #apk #target #package #root #compile

lib-cargo-apk

允许您构建 Android 包的 Cargo 子命令

2 个版本

0.5.1 2020 年 1 月 8 日
0.5.0 2020 年 1 月 7 日

#15 in #apk


cargo-flutter 中使用

MIT 许可证

80KB
1.5K SLoC

Rust 1.5K SLoC // 0.1% comments C 389 SLoC // 0.1% comments

已被 https://github.com/rust-windowing/android-ndk-rs 废弃,该库与 winit master 兼容

Android 粘合剂

Crates.io Crates.io CircleCI

用法

使用 Docker

编译 Android 的最简单方法是使用 Dockerphilipalldredge/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提供的适当的构建工具,以便与cccmake crate一起使用。
    • 在crate根目录相同的目录中创建一个临时文件。这个临时文件作为静态库的crate根。它包含原始crate根的内容以及一个android_main实现。
    • 编译 android_native_app_glue 的分支版本。 android_native_app_glue 由 NDK 提供。它提供了 Android 的 NativeActivity 所使用的入口点,该入口点调用 android_main
    • 使用 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++ 构建工具暴露给构建脚本。主要目的是支持构建具有使用 cccmake 克隆的构建脚本的 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