1. 为什么是 Flutter Module 而不是一个新的 Flutter 工程
1.1 很多团队一开始就走错了方向
我见过不少原生 Android 项目,想引入 Flutter,第一反应是 flutter create 创建一个完整的 Flutter App 工程,然后把 Android 原生代码塞进它的 android/ 目录里。这条路不是不能走,但它默认了一个前提:从这一刻起,Flutter 才是主角。目录、Gradle 工程、构建流程、依赖管理全部以 Flutter 为圆心,原生代码变成了“壳工程”里的客人。如果你正在主导一个已经跑了两三年的原生项目,团队主力还是 Android 工程师,这个前提大概率不成立。
Flutter Module 的思路正好反过来:原生工程还是原来的主人,Flutter 只是一个被请进来的“组件”。它不是一个独立 App,而是一个可以被 Android Gradle 工程直接依赖的 library。原生代码继续用之前的节奏迭代,某个二级页面、某个商品详情页、某个扫码结果页,想用 Flutter 重构,就单独把这一块做成 Flutter 页面,从原生 Activity 里跳进去。
1.2 判断标准:谁先启动,谁持有路由
选哪种方案,不要看技术热度,要看你的工程现状。我建议先用一个问题做判断:未来谁会先打开这个 App?
如果启动入口在 Android 原生,后续页面也大部分由原生控制,只是希望在某些页面用 Flutter 渲染,那不用犹豫,选 Module。如果你们的规划是整包演进,最终所有页面切到 Flutter,那也可以先用 Module 做过渡,把原生页面逐步迁成 Flutter 页面,而不是一上来就推倒重来。
还有一个隐含成本很多人没算:Flutter App 工程一旦建立,它的 android/ 目录会生成一套完整的 Gradle 构建配置,包括 applicationId、签名、渠道包逻辑。而原生工程往往有自己的多渠道、埋点、推送 SDK、第三方聚合,把两套体系强行合并,每次发版都会在 Gradle 配置上撕扯。用 Module 方式,Flutter 侧只需要关心 lib/ 下的业务代码,构建产物交给原生壳工程统一打包,配置冲突的范围会小很多。
1.3 Flutter Module 和 Flutter App 的边界对比
| 对比维度 | Flutter App 工程 | Flutter Module |
|---|---|---|
| 工程主导权 | Flutter | 原生 |
| 构建入口 | flutter run | 原生 Gradle assembly |
| 页面跳转 | Navigator 为主 | 原生 Intent/路由为主 |
| 团队要求 | Dart/Flutter 强依赖 | 原生团队 + 少量 Dart |
| 适合场景 | 新项目、全量重构 | 存量原生项目渐进迭代 |
| 发版流程 | flutter 打包为主 | 原生打包为主,Flutter 只是依赖 |
如果你的团队现状是“Android 为主、Flutter 逐步掌握”,Module 是最平滑的切入方式。当然,这也不是没有代价——混合工程在调试、依赖管理、引擎生命周期上会多出不少操作成本,后面几章我会逐个拆开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 源码依赖与 AAR 分发:两种集成姿势如何选
2.1 源码依赖是日常开发的默认选项
源码依赖,就是把 Flutter Module 的源码目录直接关联到原生工程的 Gradle 构建里。在 settings.gradle 里把 flutter_module 加进来,然后在 app 模块的依赖里写上 implementation project(":flutter")。之后的构建会直接编译 Flutter Module 里的 Dart 代码,所有改动即时生效,热重载也能用。
这种方式的优点是链路短、直观,改完 Dart 代码,重新构建 APK 就是最新效果。缺点是它强依赖 Flutter SDK 在开发机上存在,而且 Gradle 配置和 Flutter 版本绑定得比较紧。如果你只是在一台电脑上的单体工程里开发,这个缺点基本可以忽略。
2.2 AAR 分发适合跨团队交付
另一种方式是先用 flutter build aar 把 Flutter Module 打成多个 AAR 包,再放到私有 Maven 仓库或本地目录,原生工程通过 implementation "com.example:flutter_module_release:1.0.0" 依赖。这个时候,原生团队完全不感知 Flutter SDK、Dart 代码、插件这些概念,拿到手的就是一堆普通的 Android 依赖。
这个模式适合什么样的团队?我遇到过两种典型情况:一种是 App 分多个业务线,支付组、商城组、内容组各自维护代码,Flutter Module 由独立的客户端中台团队统一打包;另一种是两家公司合作,A 公司提供 Flutter 能力,B 公司只负责接入,A 公司显然不能把自己的 Flutter 源码全部暴露给 B 公司。
| 对比维度 | 源码依赖 | AAR 分发 |
|---|---|---|
| 调试热重载 | 支持 | 不支持 |
| 构建速度 | 每次全量编译 | 预编译,接入方构建快 |
| 源码可见性 | 可见 | 不可见 |
| 版本管理 | Git 分支 | Maven 版本 |
| CI/CD 依赖 | 需要 Flutter SDK | 只需要标准 Android 环境 |
| 适合团队 | 单体仓库 / 小团队 | 跨团队 / 多 App 复用 |
2.3 我的选择建议
如果你还在前期验证,只用源码依赖。等接入稳定后,如果出现“两个 App 都要用同一套 Flutter 页面”的需求,再花半天时间把 flutter build aar 的 CI 流程搭起来。不要一开始就上 AAR,因为 AAR 方式的调试体验真的很憋屈,改一行 Dart 代码都要重新 build aar、上传、同步,原型期会被这个循环拖垮。
下面正文基于源码依赖展开,这也是我实际项目里最常用的路子。
3. 目录、版本与镜像准备:集成前最容易翻车的地方
3.1 推荐目录结构
先把工程目录理顺。常见做法是让原生 Android 工程和 Flutter Module 平级:
code复制projectRoot/
androidApp/
app/
settings.gradle
build.gradle
gradle.properties
gradlew
flutter_module/
lib/
android/
pubspec.yaml
.metadata
原生工程命名为 androidApp,Flutter Module 目录用下划线命名 flutter_module。这个结构的好处是两者彼此独立,Flutter 侧可以单独用 Android Studio 打开,也可以和原生工程一起用同一个 IDE 窗口管理。
创建 Flutter Module 的命令是:
bash复制flutter create -t module --org com.example --project-name flutter_module flutter_module
--project-name 一定要和目录名一致,否则后面 Gradle 引用时会多出很多莫名其妙的路径问题。--org 会作为 Android 包名前缀,其实 Module 方式下 Flutter 的 applicationId 不会被真正当作 APK 包名,但保持规范总没错。
3.2 Flutter 与 Gradle/AGP 版本怎么配对
这是新手最容易踩的坑。Flutter Module 集成后的构建,本质是让 Flutter Gradle 插件跑在原生 Gradle 工程里,所以
