Vincent's Essays

博客园 首页 新随笔 联系 订阅 管理

Memoria 开发记录 23:跨平台不是“编译通过”——Flutter 端侧 AI 的边界治理

前言

Flutter 能复用 UI 和大量业务逻辑,但端侧 AI 相册涉及照片权限、后台任务、原生推理库、文件访问、通知和数据库目录,这些能力在 Android、iOS、macOS 上都有不同约束。

因此,跨平台适配不能只以“项目成功编译”为标准。真正的目标是让同一项产品能力在不同平台上拥有一致语义,并在平台不支持时明确降级。

编译问题只是最表层的问题

早期提交 0b31c0bf0249c18d070be 多次修复 macOS、iOS 与 Darwin 构建,涉及 Podfile、部署目标、entitlements、Xcode scheme 和 ObjectBox 初始化。

这些问题说明 Flutter 项目仍然依赖完整原生构建链:

  • CocoaPods 决定 iOS/macOS 原生依赖;
  • entitlements 决定沙盒和文件能力;
  • Xcode scheme 决定构建前脚本与环境;
  • Android Gradle 和 Kotlin 版本决定插件兼容;
  • 原生动态库必须包含正确架构。

只在 Android 调试机运行成功,无法证明 iOS 或 macOS 能正确使用同一功能。

平台能力需要显式建模

提交 cdf082a 增加平台兼容性检查和权限配置。比起在页面中散落 Platform.isAndroid,更可靠的方法是把平台能力抽象成明确状态:

支持系统相册读取
支持受限照片授权
支持前台服务
支持后台处理
支持某推理 delegate
支持某文件导出方式

业务层根据能力决定展示和降级,而不是假设每个平台都存在相同 API。

例如 Android 有前台服务通知,iOS 的后台执行则受到更严格时间限制;macOS 有桌面文件系统,但沙盒和 entitlement 仍会限制访问。产品语义可以一致,但实现路径不能强行相同。

构建前准备应自动化

提交 67c06b8 新增 iOS profile 准备脚本并接入 Xcode scheme。构建依赖手工步骤时,开发者本机可能成功,CI 或其他成员环境却失败。

可重复构建要求:

  • 自动生成或检查必要配置;
  • 明确模型和大文件来源;
  • 检查代码生成产物;
  • 固定依赖版本;
  • 对缺失环境给出可操作错误;
  • 不依赖某个人本机已有的隐藏状态。

提交 35d90229131511 分别增加 Shell 与 PowerShell 启动脚本,也是在统一不同开发环境的入口。

原生代码应保持最小边界

端侧 AI 很容易不断向 MainActivity、AppDelegate 和 C++ Bridge 中加入逻辑。短期看能快速打通能力,长期却会让 Flutter 与原生状态机重复。

当前更合理的边界是:

  • 原生层只实现 Flutter 插件无法提供的系统动作;
  • 媒体业务和任务编排尽量留在 Dart;
  • 推理运行时通过稳定插件或明确 FFI 接口接入;
  • 平台不支持时返回结构化 capability,而不是抛出模糊异常。

提交 3467cb5 将 Android 构建迁移到内置 Kotlin,也是减少额外工具链差异的一部分。

跨平台验证应该验证什么

编译成功只覆盖依赖和语法。端侧相册至少还需要验证:

  • 权限首次申请、拒绝、limited 和重新选择;
  • 读取缩略图、原图、视频和动态照片;
  • 后台任务暂停、恢复与系统终止;
  • 数据库初始化和升级;
  • 模型加载、实际后端和向量一致性;
  • 导出、分享和文件可见性;
  • 应用重启后的状态恢复。

同一功能在平台上无法满足完整语义时,应明确标记实验或不可用,不应用空实现伪装成功。

总结

Flutter 提供了跨平台代码复用,但不会自动消除平台差异。真正稳定的跨平台工程,需要把系统差异变成显式能力,并建立可重复构建和验证流程。

关键经验包括:

  • 编译通过只是跨平台适配的第一步;
  • 平台能力应显式建模,不要散落条件判断;
  • 构建前准备和启动入口必须自动化;
  • 原生层保持最小系统边界;
  • 不支持的能力要明确降级;
  • 验证应覆盖权限、后台、媒体、模型和恢复,而不只是构建。

对应提交:0b31c0bcdf082a35d90229131511f0249c13653cc367c06b88d070be3467cb5

posted on 2026-06-14 23:22  Vincentson  阅读(7)  评论(0)    收藏  举报