ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

egui Android 开发入门:从环境搭建到 hello_android 示例的完整构建运行指南

egui Android 开发入门:从环境搭建到 hello_android 示例的完整构建运行指南 egui Android 开发入门从环境搭建到 hello_android 示例的完整构建运行指南【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/egui导读本文以 egui 仓库中的官方 hello_android 示例 为骨架完整讲解如何把基于 eframe 的 Rust 即时模式 GUI 应用编译成 Android APK 并在真机/模拟器上运行。你将掌握 Android 交叉编译工具链的搭建、环境变量的配置、cargo-apk的安装与使用以及桌面端与 Android 端共用同一套代码的工程结构读完即可把现有 egui 应用移植到 Android 平台。示例概览一个应用两个平台hello_android是 eframe 官方提供的 Android 最小可运行示例。它的独特之处在于同一个 crate 同时面向桌面native与 Android移动端两个目标平台编译而应用逻辑本身完全复用。从 examples/hello_android/Cargo.toml 可以看到其关键设计[lib] # cdylib is required for Android, lib is required for desktop crate-type [cdylib, lib]cdylibAndroid 需要以动态库.so形式打包进 APK由系统 Java 层通过 JNI 加载lib桌面端Linux/macOS/Windows以常规 Rust 库形式链接进可执行文件。两者共存保证了cargo apk runAndroid与cargo run桌面都能直接使用同一个工程。平台相关的两个入口示例的源码分为两个文件examples/hello_android/src/main.rs桌面入口调用eframe::run_native创建原生窗口examples/hello_android/src/lib.rs同时包含桌面入口与 Android 入口其中 Android 入口通过#[cfg(target_os android)]条件编译隔离#[cfg(target_os android)] #[unsafe(no_mangle)] fn android_main(app: winit::platform::android::activity::AndroidApp) { // Log to android output android_logger::init_once( android_logger::Config::default().with_max_level(log::LevelFilter::Info), ); let options eframe::NativeOptions { android_app: Some(app), ..Default::default() }; eframe::run_native( My egui App, options, Box::new(|cc| Ok(Box::new(MyApp::new(cc)))), ) .unwrap() }要点解析android_main是android-activity通过 winit 暴露约定的入口函数必须#[unsafe(no_mangle)]导出符号供 Android 原生层调用通过android_logger把 Rust 的log输出桥接到 Androidlogcat级别设为Info便于调试NativeOptions中的android_app字段见 crates/eframe/src/epi.rs 中#[cfg(target_os android)]的声明是 Android 平台下eframe::run_native必需的运行时上下文缺失会直接报错。Android 特性开关hello_android在依赖声明中启用了两个关键特性见 examples/hello_android/Cargo.tomleframe { workspace true, default-features false, features [ default_fonts, glow, android-native-activity, ] }glow选用 OpenGL ES 渲染后端Android 移动 GPU 兼容性最好android-native-activity选择android-activity的native-activity后端。这两个特性从eframe一路透传到egui-winit与winitcrates/eframe/Cargo.toml 中android-native-activity [egui-winit/android-native-activity]crates/egui-winit/Cargo.toml 中android-native-activity [winit/android-native-activity]。eframe还提供另一个备选后端android-game-activity对应egui-winit/android-game-activity。从 crates/eframe/src/lib.rs 的编译期约束可以看出若同时开启accesskit辅助功能特性则必须使用android-game-activity后端否则编译会直接失败compile_error!。因此选型时需要注意需要无障碍支持的应用应选择android-game-activity。桌面端前置条件交叉编译工具链Android 应用需要 Rust 交叉编译目标与 Android SDK/NDK。以下按官方 README 的顺序展开并补充必要说明。1. 添加 Rust Android 编译目标rustup target add armv7-linux-androideabi aarch64-linux-androidaarch64-linux-android64 位 ARM 目标覆盖当今绝大多数主流手机arm64-v8aarmv7-linux-androideabi32 位 ARM 目标覆盖较老的 32 位设备armeabi-v7a。这两个目标与 examples/hello_android/Cargo.toml 中[package.metadata.android]声明的build_targets一一对应[package.metadata.android] build_targets [armv7-linux-androideabi, aarch64-linux-android]若机器上只有 64 位设备也可以只添加aarch64-linux-android并相应调整build_targets以缩短构建时间。2. 设置环境变量每次构建前必须执行export ANDROID_HOME$HOME/tools/android export ANDROID_NDK_ROOT${ANDROID_HOME}/ndk/29.0.14206865 export PATH$PATH:${ANDROID_NDK_ROOT}:${ANDROID_HOME}/build-tools/${BUILDTOOLS_VERSION}:${ANDROID_HOME}/cmdline-tools/bin官方特别强调这些变量是cargo apk每次运行都需要的。其中ANDROID_HOMEAndroid SDK 根目录本例为$HOME/tools/androidANDROID_NDK_ROOT指向具体版本的 NDK 目录ndk/29.0.14206865PATH追加 NDK、SDK build-tools版本号用${BUILDTOOLS_VERSION}占位与第 4 步安装的版本保持一致以及 cmdline-tools 的bin目录。建议把这些export写入~/.bashrc或~/.profile避免每次开新终端重复配置。若你安装了 Android Studio其 SDK 默认位于$HOME/Android/Sdk将ANDROID_HOME指向该目录同样可行关键是 SDK、NDK、build-tools 版本要与下面的安装步骤一致。3. 安装 Android 命令行工具mkdir -p ${ANDROID_HOME}/cmdline-tools curl -sLo /tmp/clt.zip https://dl.google.com/android/repository/commandlinetools-linux-14742923_latest.zip unzip -d ${ANDROID_HOME} /tmp/clt.zip将 Google 官方的 commandline-tools 压缩包下载并解压到ANDROID_HOME随后即可使用其中的sdkmanager安装 SDK 组件。cmdline-tools的bin目录已在第 2 步加入PATH。4. 安装 SDK 组件sdkmanager --sdk_root${ANDROID_HOME} --install build-tools;36.0.0 ndk;29.0.14206865 platforms;android-35安装内容build-tools;36.0.0打包 APK 所需的构建工具aapt2、zipalign 等对应PATH中的${BUILDTOOLS_VERSION}ndk;29.0.14206865NDK 29提供交叉编译所需的 C 工具链与头文件目录结构为$ANDROID_HOME/ndk/29.0.14206865与ANDROID_NDK_ROOT一致platforms;android-35Android 35Android 15平台库。注意官方在文档中特别提示“You may need to change SDK versions”——以上版本号是编写该示例时的推荐组合请根据你本机可用的 SDK/NDK 版本与目标设备系统版本灵活调整并保持ANDROID_NDK_ROOT、PATH中的 build-tools 版本、sdkmanager安装版本三者一致。SDK 版本信息在工程中也有一处对应Cargo.toml的[package.metadata.android.sdk]声明了min_sdk_version 23最低支持 Android 6.0、target_sdk_version 35目标 Android 15。5. 安装 cargo-apk 构建工具cargo install --git https://github.com/parasyte/cargo-apk.git --rev 282639508eeed7d73f2e1eaeea042da2716436d5 cargo-apkcargo-apk是cargo的子命令扩展负责把 Rust crate 打包为可安装的 APK。官方 README 特别注明上游存在一个 bug对应 issue 链接见 examples/hello_android/README.md因此必须安装指定--rev提交哈希282639508eeed7d73f2e1eaeea042da2716436d5的修复版本直接cargo install cargo-apk装到最新版可能无法正常工作。安装完成后可通过cargo apk --help验证是否成功注册为 cargo 子命令。构建与运行一行命令双平台官方 README 给出的两条命令# Android交叉编译并打包安装到连接的设备/模拟器 cargo apk run -p hello_android --lib # 桌面直接作为原生应用运行 cargo run -p hello_androidcargo apk run -p hello_android --lib-p指定包名--lib告诉 cargo-apk 打包库目标即上文的cdylib编译产物.so会被封装进 APK安装后由 Android 系统拉起。运行前提是已有设备通过 adb 连接adb devices可确认首次运行也可加上--release获得优化后的性能cargo run -p hello_android走的是 examples/hello_android/src/main.rs 的桌面入口与普通 eframe 应用无异可用于在开发 Android 功能前快速验证 UI 逻辑无需等待交叉编译。应用代码解读MyApp是桌面与 Android 共享的应用主体examples/hello_android/src/lib.rspub struct MyApp { demo: egui_demo_lib::DemoWindows, } impl MyApp { pub fn new(cc: CreationContext) - Self { egui_extras::install_image_loaders(cc.egui_ctx); Self { demo: egui_demo_lib::DemoWindows::default(), } } } impl eframe::App for MyApp { fn ui(mut self, ui: mut egui::Ui, _frame: mut eframe::Frame) { // Reserve some space at the top so the demo ui isnt hidden behind the android status bar egui::Panel::top(status_bar_space).show(ui, |ui| { ui.set_height(32.0); }); egui::CentralPanel::default().show(ui, |ui| { self.demo.ui(ui); }); } }三个值得注意的细节复用官方演示集egui_demo_lib::DemoWindows是仓库自带的演示窗口集合让示例开箱即用地展示大量控件图片加载egui_extras::install_image_loaders注册图片加载器依赖中启用了egui_extras的image特性为演示里的图片控件提供支持状态栏避让Panel::top(status_bar_space)在顶部预留 32 像素高度避免 UI 被 Android 系统状态栏遮挡。源码注释同时指出这是一个临时 hack待 winit 在 Android 上实现 safe_area 后应替换为正式方案——如果你要移植自己的应用这个处理思路可以直接复用。Android 渲染生命周期可选深入底层对想了解底层机制的读者eframe 的 glow 集成在 Android 上有一个特殊生命周期处理见 crates/eframe/src/native/glow_integration.rsAndroid 应用会收到Resumed/Suspended事件与桌面平台不同桌面只在启动时进入一次在 Android 上Suspended时会销毁 GL surface 与窗口并让 OpenGL 上下文失活Resumed时则重新创建glow 集成注释明确写道Suspended: on android, we drop window surface这也是为什么示例在桌面与 Android 上都要走eframe::run_native——eframe 已经帮你封装好了这套平台差异。入口侧eframe在 crates/eframe/src/native/run.rs 中通过winit::platform::android::EventLoopBuilderExtAndroid的with_android_app把NativeOptions.android_app注入事件循环从而衔接android_main与 winit 事件循环。常见问题与排查建议cargo apk报找不到 SDK/NDK确认ANDROID_HOME、ANDROID_NDK_ROOT已 export且ANDROID_NDK_ROOT指向真实存在的 NDK 版本目录版本不匹配时参考官方提示调整 SDK 版本。构建目标缺失rustup target add的目标必须与build_targets一致缺哪个补哪个。UI 被状态栏遮挡参考示例的顶部Panel预留方案或等待 winit safe_area 支持落地后改用正式 API。android_main未找到 / 链接失败确认eframe启用了android-native-activity或android-game-activity特性且入口函数保持了#[unsafe(no_mangle)]符号导出。启用accesskit后编译失败按 crates/eframe/src/lib.rs 中的compile_error!提示将后端切换到android-game-activity。相关资源hello_android 示例文档本文的原始依据hello_android 工程配置特性开关、build_targets、SDK 版本声明hello_android 共享应用代码双平台入口与MyApp实现eframe Android 入口与事件循环集成android_app注入 winit 事件循环的实现eframe glow 集成中的 Android 生命周期处理Resumed/Suspended时 surface 与窗口的创建销毁逻辑eframe NativeOptions 的 android_app 字段Android 平台特有配置项eframe 特性声明android-native-activity/android-game-activity两个后端的特性透传。【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/egui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进