4、原生工程集成Flutter Module:Android原生工程配置、settings.gradle与app/build.gradle修改、同步与构建
好,咱们接着往下走。上一节我们把Flutter Module创建好了,那它现在还是个「孤岛」,得把它请进Android原生工程里才行。这一步说白了就是「搭桥」——让Gradle知道Flutter的存在,并且能正确地把Flutter代码编译进来。
我个人习惯先把原生工程的结构理清楚。你打开Android Studio,看到的那个项目,其实核心就两个文件:settings.gradle和app/build.gradle。嗯,咱们要改的也就是这两个。
4.1 原生工程结构回顾
先看一眼典型的Android工程长什么样:
MyAndroidApp/
├── app/
│ ├── build.gradle // 模块级构建配置
│ └── src/
├── settings.gradle // 项目级模块声明
├── build.gradle // 项目级构建配置
└── gradle.properties // Gradle属性
你想想看,Flutter Module本质上也是一个Gradle子模块。我们要做的,就是把它「注册」到settings.gradle里,然后在app/build.gradle里把它作为依赖引用进来。
核心思路:Flutter Module不是APK,它是一个AAR(Android Archive)或者源码依赖。Gradle会在编译时把它打包进主工程。
4.2 修改settings.gradle
这是第一步,也是最容易踩坑的一步。打开你的settings.gradle,默认内容大概是这样:
include ':app'
rootProject.name = "MyAndroidApp"
现在我们要把Flutter Module加进来。假设你的Flutter Module放在与Android工程同级的目录下,目录名叫flutter_module:
// settings.gradle
include ':app'
rootProject.name = "MyAndroidApp"
// 添加Flutter Module
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'flutter_module/.android/include_flutter.groovy'
))
这里我解释一下这段代码在干什么。它调用了Flutter自动生成的include_flutter.groovy脚本,这个脚本会帮我们把Flutter Module里的flutter子模块和app子模块都注册进来。说白了就是「一键导入」。
注意:路径别写错了。我见过有人直接把settingsDir.parentFile写成了绝对路径,结果换台电脑就编译不过。一定要用相对路径,这样团队协作时才不会出问题。
我曾经在一个项目里,因为Flutter Module的目录名带了个空格,结果Gradle解析路径时报错,折腾了半天才发现是空格的问题。嗯,所以目录名最好用下划线,别用空格。
4.3 修改app/build.gradle
接下来是重头戏。打开app/build.gradle,在dependencies块里加上Flutter的依赖:
dependencies {
implementation project(':flutter')
// 其他依赖...
}
等等,这里有个细节。为什么是':flutter'而不是':flutter_module'?因为include_flutter.groovy脚本注册的子模块名字就叫flutter。你可以去flutter_module/.android/目录下看一眼,里面有个settings.gradle,它定义了:
include ':flutter'
include ':app'
所以我们在主工程里引用时,就用':flutter'。这个坑我刚开始也踩过,以为要写模块名,结果编译报错说找不到模块。
另外,如果你的Android工程启用了minifyEnabled(混淆),记得在proguard-rules.pro里加上Flutter的混淆规则:
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
为什么要加这个?因为Flutter的很多类是通过反射调用的,混淆之后类名变了,运行时就会崩溃。我有个朋友没加这个规则,结果Release包一打开就闪退,查了半天才发现是混淆的问题。
4.4 同步与构建
改完这两个文件,接下来就是见证奇迹的时刻。点击Android Studio右上角的「Sync Now」,让Gradle重新同步。
同步过程中,Gradle会做几件事:
- 解析
settings.gradle,找到Flutter Module - 执行
include_flutter.groovy,注册子模块 - 下载Flutter的依赖(如果本地没有的话)
- 编译Flutter Module的Dart代码为原生代码
第一次同步会比较慢,因为要下载Flutter的Gradle插件和引擎库。我记得第一次同步等了将近两分钟,别急,喝杯咖啡等一等。
同步成功后,你会看到Build窗口输出类似这样的信息:
BUILD SUCCESSFUL in 1m 32s
这时候,你的Android工程就已经成功集成了Flutter Module。你可以试着在MainActivity里写一段代码来验证:
// MainActivity.java
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_open_flutter).setOnClickListener(v -> {
startActivity(
FlutterActivity.createDefaultIntent(this)
);
});
}
}
这段代码会在点击按钮时打开一个Flutter页面。如果编译通过并且能正常跳转,那就说明集成成功了。
小技巧:如果你用的是Kotlin,代码会更简洁:
startActivity(FlutterActivity.createDefaultIntent(this))
嗯,Kotlin的语法糖确实让代码少了不少样板。
4.5 常见问题与避坑
集成过程中,我遇到过几个比较典型的问题,列出来给大家参考:
| 问题 | 原因 | 解决方案 |
|---|---|---|
找不到include_flutter.groovy |
路径配置错误 | 检查settings.gradle中的路径,确保指向正确的Flutter Module目录 |
编译报错FlutterEngine找不到 |
Flutter SDK版本与Gradle插件不兼容 | 升级Flutter SDK或降级Gradle插件版本 |
同步时卡在Downloading Flutter SDK |
网络问题或代理配置 | 配置Gradle代理,或手动下载Flutter SDK到本地 |
| Release包闪退 | 混淆规则未配置 | 添加Flutter的ProGuard规则 |
我曾经遇到过一个特别诡异的问题:Debug包运行正常,Release包一打开就黑屏。后来发现是flutter.jar没有被正确打包进APK。解决方案是在app/build.gradle里加上:
android {
// ...
packagingOptions {
pickFirst '**/libflutter.so'
}
}
这个配置告诉Gradle,如果多个依赖里都有libflutter.so,就取第一个。嗯,这种问题一般出现在你同时引用了多个Flutter相关库的时候。
4.6 知识体系图
为了让你更直观地理解整个集成流程,我画了一张图:
这张图把整个流程串起来了。从创建Flutter Module开始,到修改两个Gradle文件,再到同步和构建,最后验证集成结果。每一步都有对应的文件或操作,你照着走就不会出错。
4.7 小结
这一节的内容其实不多,但很重要。说白了就是改两个文件:settings.gradle和app/build.gradle。前者告诉Gradle「Flutter Module在这里」,后者告诉Gradle「我要用它」。同步之后,Flutter和Android就正式「联姻」了。
嗯,这里要提醒一句:集成完成后,记得把flutter_module目录也纳入版本控制。不然同事拉代码后,没有Flutter Module,编译会直接报错。
好了,这一节就到这里。下一节我们会讲如何在Android原生代码中启动Flutter页面,以及如何传递参数。到时候见。
公众号:蓝海资料掘金营,微信deep3321