前言

在前面的章节学习中我们已经掌握了从最基本的 hello flutter到各种基本Widget、各种布局的使用再到多页面切换路由的使用还有各种炫酷的提示跟dialog,还有关于网络请求库Dio的使用,至此我们完全可以使用flutter去开发一款独立可运行的app了,但是基于现阶段flutter技术栈还不是太成熟,纯flutter项目上线风险还是比较大,所以跨平台的混合开发模式自然还是现阶段尝试flutter的主流方式,今天的分享我就跟大家一块把我们写好的flutter项目打包成aar文件嵌入到现有的Android项目中去。

课程目标

  • 掌握flutter打包成aar的整体流程
  • 利用fat-aar把flutter项目中的三方依赖打入aar资源包中

项目准备:

flutter端项目我采用的是本专栏的实例代码项目:https://github.com/xiedong11/flutter_app,Android端原生项目为新建的一个hello world项目,flutter端的相关配置我会上传到github仓库中,原生Android项目比较简单,我只在本博客中贴出部分关键代码

1.flutter项目打包成aar

flutter端项目工程目录
18  Flutter项目打包 - 图1
上面截图的flutter工程需要经过我们的改造才能作为一个aar的形式存在,要被打包成aar的flutter端的项目是作为一个独立的module运行在宿主app(原生Android)中,所以我们需要修改两个地方,让我们打包出来的产物变成aar而不是独立运行的apk。

1.1修改Android下的 build.gradle
  1. // 1. 生成aar产物,需要把`application`改为`library`
  2. apply plugin: 'com.android.library'
  3. apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
  4. android {
  5. compileSdkVersion 28
  6. lintOptions {
  7. disable 'InvalidPackage'
  8. }
  9. defaultConfig {
  10. // 2. flutter 作为寄存于其他app中的产物,所以不应该存在applicationId,所以注释掉该行.
  11. //applicationId "com.zhuandian.flutterapp"
  12. minSdkVersion 16
  13. targetSdkVersion 28
  14. versionCode flutterVersionCode.toInteger()
  15. versionName flutterVersionName
  16. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  17. }
  18. buildTypes {
  19. release {
  20. // TODO: Add your own signing config for the release build.
  21. // Signing with the debug keys for now, so `flutter run --release` works.
  22. signingConfig signingConfigs.debug
  23. }
  24. }
  25. }

1. 2 修改Androidmanifest.xml文件
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.zhuandian.flutterapp">
  4. <uses-permission android:name="android.permission.INTERNET" />
  5. <!--1.项目作为子项目寄存于原生app中,不需要icon、label等属性,这里直接省去各种配置即可-->
  6. <application>
  7. <!--android:name="io.flutter.app.FlutterApplication"-->
  8. <!--android:icon="@mipmap/ic_launcher"-->
  9. <!--android:label="flutter_app">-->
  10. <activity
  11. android:name=".MainActivity"
  12. android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
  13. android:hardwareAccelerated="true"
  14. android:launchMode="singleTop"
  15. android:theme="@style/LaunchTheme"
  16. android:windowSoftInputMode="adjustResize">
  17. <!--2.项目作为子项目寄存于原生app中,入口acitvity不需要配置LAUNCHER,不然应用集成到宿主app中,启动会在桌面上生成两个应用图标-->
  18. <!--<meta-data-->
  19. <!--android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"-->
  20. <!--android:value="true" />-->
  21. <!--<intent-filter>-->
  22. <!--<action android:name="android.intent.action.MAIN" />-->
  23. <!--<category android:name="android.intent.category.LAUNCHER" />-->
  24. <!--</intent-filter>-->
  25. </activity>
  26. <activity android:name=".SecondActivity"></activity>
  27. </application>
  28. </manifest>

需要修改的地方,我都在源码里留注释了,这里就不展开赘述了,下面我们来通过gradle获得编译好的 aar产物

因为在build.gradle 中,我们把 apply plugin: 'com.android.application'修改成了, apply plugin: 'com.android.library'
所以,现在通过Terminal中我执行 gradlew assembleRelease编译出的产物会有原来的apk变成aar文件,文件输出目录为项目根目录下的 /bulid/app/outputs/aar
如下图所示:
18  Flutter项目打包 - 图2

1.3 Android端项目配置接入aar依赖

1.3.1 新建原生Android项目,我上述打包产出的aar文件作为依赖放入libs文件夹
18  Flutter项目打包 - 图3

1.3.2 修改 dependencies节点下的 fileTree依赖配置,支持引入aar依赖支持

  1. implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
  1. dependencies {
  2. implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
  3. ...
  4. }

1.3.3 在原生Android项目中写一个简单的按钮测试flutter项目

  1. class MainActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_main)
  5. FlutterMain.startInitialization(this)
  6. tv_test_aar.setOnClickListener {
  7. startActivity(Intent(this, com.zhuandian.flutterapp.MainActivity::class.java))
  8. }
  9. }
  10. }

至此,把flutter项目打包成aar导入到原生Android项目中的所有工程配置已经结束了,读者可以测试上上述整个过程;但有时候我们的flutter项目并不是单纯的flutter官方代码,开发过程中少不了引入一些三方依赖,像上节课我们讲到的Dio网络请求库,或者是通过 pubspec.yaml引入的其他开源工具类,这种情况下,通过上边的配置方式,你会发现第三方的依赖代码是打不进aar包里的,下面我们就讲解一下借助 fat-aar的形式把三方依赖代码打入aar包中去

2.flutter项目中存在三方依赖

通过上边的配置,我们只能把纯flutter项目打包成aar文件,换句话说,如果我们的flutter项目存在三方依赖是不能正常打包进flutter产物里的,这个时候我们就需要通过在Android原生项目中引入 fat-aar配置,确保把flutter项目中的三方依赖正常打包进去flutter产物中去。

2.1修改项目工程目录的build.gradle文件,引入fat-aar支持

  1. buildscript {
  2. repositories {
  3. google()
  4. jcenter()
  5. }
  6. dependencies {
  7. classpath 'com.android.tools.build:gradle:3.4.1'
  8. classpath 'com.kezong:fat-aar:1.1.7'
  9. }
  10. }

2.2 在上边第一部分配置app文件下build.gradle基础上,增加fat-aar相关配置,这里为了切换aar library运行环境,我引入isAarLibrary标志位作为切换环境开关,方便工程配置,具体代码如下:

  1. //是否作为依赖
  2. boolean isAarLibrary = true
  3. if (isAarLibrary) {
  4. apply plugin: 'com.android.library'
  5. } else {
  6. apply plugin: 'com.android.application'
  7. }
  8. apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
  9. if (isAarLibrary) {
  10. //引入fat-aar
  11. apply plugin: 'com.kezong.fat-aar'
  12. }
  13. android {
  14. compileSdkVersion 28
  15. lintOptions {
  16. disable 'InvalidPackage'
  17. }
  18. defaultConfig {
  19. // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
  20. if (!isAarLibrary) {
  21. applicationId "com.zhuandian.flutterapp"
  22. }
  23. minSdkVersion 16
  24. targetSdkVersion 28
  25. versionCode flutterVersionCode.toInteger()
  26. versionName flutterVersionName
  27. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  28. }
  29. buildTypes {
  30. release {
  31. // TODO: Add your own signing config for the release build.
  32. // Signing with the debug keys for now, so `flutter run --release` works.
  33. signingConfig signingConfigs.debug
  34. }
  35. }
  36. }
  37. flutter {
  38. source '../..'
  39. }
  40. dependencies {
  41. implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
  42. testImplementation 'junit:junit:4.12'
  43. androidTestImplementation 'androidx.test:runner:1.1.0'
  44. androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
  45. implementation 'androidx.appcompat:appcompat:1.0.0'
  46. if (isAarLibrary) {
  47. //TODO 添加fat-aar处理flutter打包成aar中三方依赖
  48. def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
  49. def plugins = new Properties()
  50. def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
  51. if (pluginsFile.exists()) {
  52. pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
  53. }
  54. plugins.each { name, _ ->
  55. println name
  56. embed project(path: ":$name", configuration: 'default')
  57. }
  58. }
  59. }

2.3AndroidManifest.xml清单文件中不需要增加额外配置,原生Android端唤起flutter项目aar包的方式也不需要修改,整个引入fat-aar的过程只是为了确保能把flutter项目中的三方依赖代码打入到flutter产物中去,所以关于flutter打包成aar的操作跟第一步保持一致就行,第二步的配置,只是为了确保flutter项目中的三方依赖能正常打包进flutter产物中去

效果图是我把本专栏的相关代码作为一个aar集成到一个新建的原生Android项目中,效果图如下:
18  Flutter项目打包 - 图4

项目的完整代码配置在https://github.com/xiedong11/flutter_app 中,读者可以参考具体配置细节,笔者在写本篇博文打包aar时的flutter 环境stable版本为 flutter v1.9.1,读者尽量用官方稳定版的代码做测试。

下一篇:Flutter入门进阶之旅(十九)Flutter与原生平台交互