Tauri 2.x 开始正式支持移动端(iOS 和 Android),但移动平台与桌面环境有本质区别,直接照搬桌面逻辑往往会出问题。窗口、权限和生命周期这三块,是移动适配中最容易踩坑的地方。
窗口:从“多窗口自由”到“单 Activity/ViewController”
桌面端可以随意创建多个独立窗口、设置位置和大小,但移动端完全不同。Android 将界面绑定在 Activity 上,iOS 则是 UIViewController,Tauri 的 WebView 通常只能附着在单个全屏容器内。
- 默认单窗口:移动端应用通常只有一个主窗口,试图用
WebviewWindow::new创建新窗口的行为会被平台限制或直接忽略。应当用前端路由和组件切换来模拟多视图。 - 无法自定义位置和尺寸:窗口的
x, y, width, height等属性在移动端无效,系统强制全屏(或分屏时由系统动态分配)。不要在代码里硬编码窗口大小。 - 状态栏、导航栏和凹口适配:前端需要自行处理 safe area,不能用桌面那套固定的 CSS 边距。可通过 Tauri 的
window插件获取系统 insets 并传递给前端。
实际操作建议:
- 在
tauri.conf.json中将窗口配置简化,移除所有与桌面位置相关的字段。 - 前端增加
env()判断平台,移动端隐藏拖拽区域、菜单栏等桌面专属 UI。
权限:双重沙箱下的严格管控
移动操作系统的权限模型远比桌面严格。你的 Tauri 应用既要遵守 Tauri 自身的权限白名单(命令、文件系统访问等),还要遵守 iOS/Android 的运行时权限授权。
- Tauri 权限层:所有调用 Rust 后端的命令必须在
permissions中显式声明,比如fs:allow-read、shell:allow-execute。移动端默认集成了更保守的权限配置,许多桌面端看似无害的操作(如访问任意路径)会被平台阻断。 - 系统权限:相机、麦克风、地理位置等敏感功能需要提前在
Info.plist(iOS)或AndroidManifest.xml(Android)中添加使用描述,否则直接调用会崩溃。Tauri 插件(如tauri-plugin-geolocation)通常会封装好这部分,但仍需开发者手动填写隐私提示语。 - 文件系统限制:iOS 严格沙箱化,App 只能访问自己的 Documents 目录和临时目录,无法随意遍历用户文件。不要试图用绝对路径访问桌面文档或系统文件夹。
实用建议:
- 尽早通过真机测试各项权限请求,模拟器常会跳过系统弹窗。
- 在应用启动时主动检查权限状态,给用户明确的引导,而不是等到功能调用失败再提示。
生命周期:前后台切换不是“最小化”
移动端应用随时可能被系统杀死以释放内存,并不存在桌面“最小化到托盘”的优雅状态。Tauri 通过事件暴露了应用状态变化,你需要妥善处理。
- 前后台切换事件:用
app.on_window_event或 Tauri 的tauri://focus、tauri://blur事件监听窗口焦点变化。在 iOS 上当应用进入后台(applicationDidEnterBackground),你应该暂停音视频播放、停止网络轮询、保存关键数据。 - 状态保存与恢复:系统可能在后台随时终止应用,下次冷启动时必须能恢复用户离开时的状态。Tauri 的
tauri-plugin-store可以帮助持久化小型数据,iOS 甚至支持快速的“状态编码”恢复,但需要手动适配。 - 跨平台差异:Android 的 Activity 可能因配置变更(如旋转屏幕)被重建,Tauri 的 WebView 会重新加载,但 Rust 状态保持。务必在前端处理好页面刷新时的数据持久化,避免表单丢失。
最佳实践:
- 监听
tauri://resume和tauri://pause事件,不要依赖beforeunload这种 Web 概念,移动端后台行为不触发它。 - 对于需要后台持续工作的应用(如播放器),必须正确实现系统服务(iOS 的 Background Modes、Android 的 Foreground Service),Tauri 自身不提供原生后台任务能力,需用 Rust 写对应平台的接口。
适配移动端时,心态要从“我把桌面应用缩小就是移动版”转变为“我在构建一个原生移动应用,恰好前端用了 Web 技术”。把握好窗口单例、权限双重限制、生命周期突变这三个要点,整体迁移成本就会可控许多。