把Flutter作为一个模块接入到现有的Android工程,Flutter有官方推荐方案 Add Flutter to existing apps,通过这样的工程配置,可以在debug支持HotReload,也可以输出Release包供发布。不过在使用过程中有一些需要调整的地方,特此记录希望对大家能有借鉴意义。

工程目录调整

flutter create -t module

命令会创建一个支持Flutter的Android Library,其中Android Library的目录位于Flutter工程的隐藏目录 .android/flutter 中, 一般情况下,我们会把Flutter代码和Android代码放在两个git仓库,通过submodule的方式进行依赖,可以把这个Library的代码copy到你的工程目录下,同时修改flutter的资源目录到你自己的相对路径下:

flutter { source ' your own flutter project directory ' }

另外需要Copy include_flutter.groovy 这个文件到你的工程目录下,修改相应的目录添加对于Library的依赖。

armeabi支持

Flutter官方只提供了四种CPU架构的SO库:armeabi-v7a、arm64-v8a、x86和x86-64。但是目前我们对接的两个项目组分别是只支持armeabi和只支持armeabi-v7a,所以需要对官方的jar包进行改造。官方SDK提供的jar包路径在 $flutterRoot/bin/cache/artifacts/engine中,复制这几个目录下的armeabi-v7a中的so到armeabi路径下:

  • android-arm
  • android-arm-dynamic-profile
  • android-arm-dynamic-release
  • android-arm-profile
  • android-arm-release

可以通过如下脚本实现:

unzip flutter.jar lib/armeabi-v7a/libflutter.so
mkdir lib/armeabi
cp lib/armeabi-v7a/libflutter.so lib/armeabi/libflutter.so
zip flutter.jar lib/armeabi-v7a/libflutter.so lib/armeabi/libflutter.so
复制代码

Library中的build.gradle中有一段是通过本地的一个gradle文件添加flutter.jar的依赖:

apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
复制代码

我们把flutter.gradle文件以及我们刚才处理的flutter.jar文件Copy到自己的工程路径下,我自己的工程路径配置如下:

project
│   app
└───flutter
│   │   build.gradle
│   │   flutter.gradle
│   │   include_flutter.groovy
│   └───flutter-jars
│       └───android-arm
|              |   flutter.jar
│       └───android-arm-dynamic-profile
|              |   flutter.jar
│       └───android-arm-dynamic-release
|              |   flutter.jar
|       └───android-arm-profile
|              |   flutter.jar
|       └───aandroid-arm-release
|              |   flutter.jar
│   settings.gradle
复制代码

将flutter.gradle 中jar文件的路径改为本地工程:

debugFlutterJar = new File('flutter-jars/debug/flutter.jar')
profileFlutterJar = new File('flutter-jars/profile/flutter.jar')
releaseFlutterJar = new File('flutter-jars/release/flutter.jar')
dynamicProfileFlutterJar = new File('flutter-jars/dynamicProfile/flutter.jar')
dynamicReleaseFlutterJar = new File('flutter-jars/dynamicRelease/flutter.jar')
复制代码

这样打出的AAR就能同时支持两种架构。

打包AAR问题

按照上面的配置,可以在工程中打出支持Debug HotReload和Release的包,不过在输出AAR给别的业务模块使用时会报一个崩溃:

must be able to initialize the ICU context.

这是Android Gradle Plugin 3.+ 版本的一个bug,它会丢弃flutter.jar 中的 /assets/flutter_shared/icudtl.dat文件到AAR中,导致运行时找不到这个文件崩溃,在2.+版本中发现没有这个问题,所以需要使用Android Gradle Plugin 2.+版本,我这边测试2.2.3版本是ok的。但是Android Gradle 2的版本有一个由来已久的问题就是Library不能获取project一致 的BuildType,Library默认只发布Release的AAR。这是因为Android中默认指定了发布type:

private String defaultPublishConfig = "release";
private boolean publishNonDefault = false;
复制代码

默认Release,而flutter.gradle中通过buildtype来确定flutter的buildmode,在Android Gradle Plugin 3.+版本中,这个buildtype的问题已经得到解决,这也可能是flutter选用3.+版本的一个原因。

如果避免2.+的buildtype问题呢,网上是有一些获取project的buildtype配置给Library的方案,比如如何让library的buildType类型跟app的buildType类型一致(自由定义library的buildType) ??。 我的实现方案是摈弃通过buildtype确定flutter的buildmode的方案,通过直接读取本地local.properties中的参数来决定,这样需要自己在本地手动的进行mode的切换,尤其是要注意上线的时候修改为Release模式。不过debug模式下页面有明显的debug标识,所以一般也不会出错。将flutter.gradle 中原有的buildmodefor方法:

private static String buildModeFor(buildType) {
       if (buildType.name == "profile") {
           return "profile"
       } else if (buildType.name == "dynamicProfile") {
           return "dynamicProfile"
       } else if (buildType.name == "dynamicRelease") {
           return "dynamicRelease"
       } else if (buildType.debuggable) {
           return "debug"
       }
       return "release"
   }
复制代码

修改为:

private String buildModeFor(Project project) {
        return resolveProperty(project, 'flutter.buildMode', 'release')
    }
复制代码

这样在local.properties 中就可以进行debug和Release的切换:

flutter.buildMode=release

flutter.buildMode=debug

切换mode的崩溃问题

在第一次配置好工程或者切换mode的过程中,可能会遇到以下的崩溃问题:

Check failed: vm. Must be able to initialize the VM.

主要是由于不同模式下的产物没有清理使用了缓存,解决办法是删除掉所有build文件的内容再全量编译一次就可以了。

总结

这是我在做flutter工程配置中遇到的一些坑,文风偏流水账,请大家见谅,只希望能对大家有一些借鉴意义。另外,我们已经在项目的两个模块中使用了flutter,开发效率确实能有很大提高,毕竟两端只需要一个人开发就ok,而且UI小姐姐要求的页面效果都能不折不扣的完成,上线之后目前还没发现什么问题。下一步需要做的是建立一个有效的监控体系,毕竟靠用户反馈还是不可靠也是滞后的。相信Flutter的未来一定是光明的!