将 Rust 编译为可在 Android 上使用的二进制文件
Rust 语言已经成为了越来越受欢迎的一种系统级编程语言。它被广泛使用来开发高性能的系统软件,模块化的库,以及并发和并行计算应用程序。不仅如此,它还可以为其他平台和设备生成二进制代码,包括 Android 操作系统。如果你也想在 Android 上利用 Rust 开发应用程序
创建 Rust 项目
首先创建 Rust 项目
cargo new rustDemo为了跟前文 (使用 GoMobile 创建 Android、iOS 跨平台 WebSocket Library) 呼应,我们这里也使用 Rust 借助 tokio 写一个 WebSocket Server。 main.rs
use async_trait::async_trait;
use ezsockets::Error;
use ezsockets::Server;
use ezsockets::Socket;
use std::net::SocketAddr;
type SessionID = u16;
type Session = ezsockets::Session<SessionID, ()>;
struct EchoServer {}
#[async_trait]
impl ezsockets::ServerExt for EchoServer {
type Session = EchoSession;
type Call = ();
async fn on_connect(
&mut self,
socket: Socket,
address: SocketAddr,
_args: (),
) -> Result<Session, Error> {
let id = address.port();
let session = Session::create(|handle| EchoSession { id, handle }, id, socket);
Ok(session)
}
async fn on_disconnect(
&mut self,
_id: <Self::Session as ezsockets::SessionExt>::ID,
) -> Result<(), Error> {
Ok(())
}
async fn on_call(&mut self, call: Self::Call) -> Result<(), Error> {
let () = call;
Ok(())
}
}
struct EchoSession {
handle: Session,
id: SessionID,
}
#[async_trait]
impl ezsockets::SessionExt for EchoSession {
type ID = SessionID;
type Args = ();
type Call = ();
fn id(&self) -> &Self::ID {
&self.id
}
async fn on_text(&mut self, text: String) -> Result<(), Error> {
self.handle.text(text);
Ok(())
}
async fn on_binary(&mut self, _bytes: Vec<u8>) -> Result<(), Error> {
unimplemented!()
}
async fn on_call(&mut self, call: Self::Call) -> Result<(), Error> {
let () = call;
Ok(())
}
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let (server, _) = Server::create(|_server| EchoServer {});
ezsockets::tungstenite::run(server, "127.0.0.1:9091", |_| async move { Ok(()) })
.await
.unwrap();
}dependencies:
[dependencies]
async-trait = "0.1.67"
ezsockets = "0.5.1"
tokio = { version = "1.26.0", features = ["full"] }
tracing = "0.1.37"
tracing-subscriber = "0.3.16"添加 targets
> rustup target add aarch64-linux-android \
armv7-linux-androideabi \
i686-linux-android \
x86_64-linux-android指定 linker
Rust 默认调用平台安装的 cc 编译器,所哟我们需要指定 Android 的 CC 和 AR 首先安装 Android NDK
部分教程说需要执行下面的命令:
python ${NDK_HOME}/build/tools/make_standalone_toolchain.py --api 26 > --arch arm64 --install-dir NDK/arm64
其实是不用的。在新的 NDK 中已经自自带了。我们在项目跟目录创建 .cargo/config:
[target.aarch64-linux-android]
linker = '/home/ying/Android/Sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang'
ar = '/home/ying/Android/Sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar'编译 Rust 代码
执行:
cargo build --target aarch64-linux-android --release会在 target/aarch64-linux-android/release 目录下生成产物
如果你使用 r23c 及以上版本,那么 cargo build 可能会出现以下错误,原因是 libgcc.a 已经被 libunwind.a 替代:
ld: error: unable to find library -lgcc可以把把 libunwind.a 复制一份重命名为 libgcc.a,它的路径为:/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.7/lib/linux/aarch64/
在 Android 中运行
可以参考上篇文章 使用 GoMobile 创建 Android、iOS 跨平台 WebSocket Library 稍微修改即可:
....
MainScope().launch(Dispatchers.IO) {
Runtime.getRuntime().exec("so 的路径")
}
...总结
要在 Android 设备运行 Rust 可执行我呢间需要:
- 使用 rustup 添加 android 设备相关的 target
- 项目中配置 linker ar
- 编译 rust 代码
- android 项目中执行 rust 文件