crates\nfarms-mobile\src\lib.rs¶
源码路径:
crates\nfarms-mobile\src\lib.rs· 61 行
//! NFarms HUB 安卓版入口。
//!
//! 这一层很薄 —— 逻辑全在下面两层里复用:
//!
//! * `nfarms-core` 纯逻辑(路径 / 日志 / 设置 / 天气 / 拓扑 / libs 检测)
//! * `nfarms-gui` egui 界面(侧栏 / 主题 / 图标 / 背景图 / logo / 天气页 …)
//!
//! 桌面版的入口是 `nfarms-app`(Windows 双模 exe:命令行诊断 + 界面);
//! 这边是 **cdylib**,由 Android 的 NativeActivity 通过 `android_main` 拉起来。
//!
//! ## 安卓和桌面版的差别,只有两处
//!
//! 1. **「程序根」从哪来**。桌面版按 exe 位置推(exe 在 `bin\` 下就上溯一层);
//! 安卓上 exe 在 APK 里、不可写,所以改用**应用私有数据目录**
//! (`/data/data/<包名>/files`)。`Paths::from_exe_dir` 只在目录名恰好是
//! `bin` 时才上溯,把数据目录传进去正好得到「数据目录 = 程序根」。
//! 2. **eframe 必须拿到 `AndroidApp`**(NativeActivity 的句柄),
//! 否则 `run_native` 会直接报 `NativeOptions is missing required android_app`。
//!
//! ## 哪些页面在安卓上有意义
//!
//! 能搬的:**天气**(wttr.in)、**拓扑验证器**(纯网络探测)、**设置**。
//! 搬不了的:Environment(winget / npm)、NF-Printer(Windows 打印 API)、
//! Harness(要拉桌面可执行文件)、Browser(WebView2)、NF-VPN(nfztna.exe)、
//! Pet(全局键鼠钩子 + 分层窗口)—— 这些页在安卓上仍是占位。
// 非安卓目标下这个 crate 是**空的**:它只是安卓的入口壳子。
// 这样 workspace 级的 `cargo build`(Windows)不会因为多了一个成员而失败。
#[cfg(target_os = "android")]
mod imp {
use std::path::PathBuf;
use nfarms_core::{settings, Log, Paths};
/// 安卓入口。NativeActivity 会 dlopen 这个 .so 并调用它。
///
/// 注意:这个签名要和 `android-activity` 的约定一致(它内部是按
/// `extern "C" fn(*mut c_void)` 去 `dlsym` 的)。
///
/// edition 2024 起 `no_mangle` 属于「不安全属性」,必须写成 `unsafe(no_mangle)`。
#[unsafe(no_mangle)]
pub fn android_main(app: winit::platform::android::activity::AndroidApp) {
// 安卓上的「程序根」= 应用私有数据目录
let root: PathBuf = app
.internal_data_path()
.unwrap_or_else(|| PathBuf::from("."));
let paths = Paths::from_exe_dir(&root);
let log = Log::detect(&paths);
log.write(
"gui",
&format!("安卓版启动,程序根={}", paths.root().display()),
);
let settings_path = settings::default_path(&paths);
if let Err(e) = nfarms_gui::run_android(app, &paths, &log, &settings_path) {
log.write("gui", &format!("界面启动失败: {e}"));
}
}
}