把 Flutter 工程打包成 aar,引入到现有的 Android 项目(附源代码)

我们在尝试Flutter的时候,其实可以在我们现成的项目中加入Flutter,然后改造我们部分不是特别重要的的功能,避免引发较大的风险,也可以把新技术引入进来。在React Native的时候,我们也尝试做过类似的方案,后来基于稳定性和维护成本,最终换回了原生开发。

谁在用Flutter混合开发?

闲鱼APP就是典型的原生&Flutter开发方案,通过Android的“显示布局边界”工具,可以看到,闲鱼APP的商品详情页、游戏交易区、短租交易区都已经是使用Flutter改造。

更多使用Flutter的应用:https://itsallwidgets.com

分析增加包体积的成本分析(增加5.1MB)

通过分析生成的正式apk包,我们可以看到,Flutter的实现主要是C++实现,这里会增加3.5MB大小,另外就是assets文件夹,这里会增加1.6 MB,由于Flutter增加的jar代码很少,可以忽略不计。从中分析,项目中如果加入Flutter,会增加5.1MB的大小左右,这个大小还是非常可观,不算大。

  • isolate_snapshot_data 应用程序数据段
  • isolate_snapshot_instr 应用程序指令段
  • vm_snapshot_data VM虚拟机数据段
  • vm_snapshot_instr VM虚拟机指令段
Flutter依赖原理分析

我们通过默认生成的android项目的build.gradle文件可以看到,其实在我们现成的项目中加入flutter的支持是非常简单的,核心就是flutter.gradle,在flutter的安装包中flutter/packages/flutter_tools/gradle可以看到这个文件。

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

packages/flutter_tools/gradle/flutter.gradle
这个文件的作用主要是:

  1. 增加 flutter.jar和so依赖。
  2. Flutter Plugin编译依赖插件。
  3. 插入工程编译产物,就是assets目录下的内容,isolate_snapshot_data和vm_snapshot_data。
在现成项目引入Flutter,基础版本教程

由于开发Flutter是需要配置Flutter的环境,在实际的团队当中,并不是所有成员都必须参与到Flutter开发中,非Flutter开发人员也不应该需要配置Flutter开发环境,所以我们只需要将需要的代码引入进来,非Flutter开发人员就不需要配置环境,所以我们只需要复制flutter.jar和libflutter.so和assets文件到我们项目即可。

public final class GeneratedPluginRegistrant {
  public static void registerWith(PluginRegistry registry) {
    if (alreadyRegisteredWith(registry)) {
      return;
    }
  }

  private static boolean alreadyRegisteredWith(PluginRegistry registry) {
    final String key = GeneratedPluginRegistrant.class.getCanonicalName();
    if (registry.hasPlugin(key)) {
      return true;
    }
    registry.registrarFor(key);
    return false;
  }
}

创建一个Activity承载Flutter

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
  }
}

在现成项目引入Flutter,升级版本教程

从上面的基础教程,我们其实就已经可以实现在现有的项目中使用Flutter,但是每次都需要复制文件到指定目录,其实我们可以换个方式来实现,就是通过依赖管理实现,我们将flutter.jar和libflutter.so文件,还有assets里面的编译产物一起打包生成aar,然后上传到maven仓库,我们主工程就可以非常简单地通过依赖方式引入,丝毫不会污染原来的工程代码,Flutter开发和原生开发就可以进行了隔离,后续会补充这部分的教程。

dependencies {
    implementation 'com.taoweiji.flutter:aboutme:1.0.0'
}

创建一个Activity承载Flutter

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
  }
}

教程

创建android module

在android目录下的app是flutter默认的运行宿主,如果我们需要打包成一个aar,那么我们需要创建一个module来承载,这个module最重要的地方是build.gradle,这个文件的内容复制android/app/build.gradle目录下的文件,把 apply plugin: 'com.android.application' 改成apply plugin: 'com.android.library',并增加groupversion的定义。

//build.gradle
apply plugin: 'com.android.library'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
...略去几十行代码
group = 'com.taoweiji.flutter'
version = '1.0.0-SNAPSHOT'
配置Maven上传

发布aar有两种,一个是本地发布,一个是搭建Maven服务器来实现,我们需要修改android/build.gradle文件

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.1'
        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
    }
}
...
subprojects {
    apply plugin: 'maven'
    uploadArchives {
        repositories {
            mavenDeployer {
                repository(url: uri('/Users/Wiki/repo'))// 填写本地的仓库地址
                //repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                //    authentication(userName: ossrhUsername, password: ossrhPassword)
                //}
            }
        }
    }
}
编写打包发布脚本

在flutter的项目根目录创建一个脚本文件 publish_android_aar.sh

#!/usr/bin/env bash
# publish_android_aar.sh

# 我们用于打包aar的module名称
myFlutterModule="myflutter"


echo "Clean old build"
find . -d -name "build" | xargs rm -rf
flutter clean

echo "Get packages"
flutter packages get

# 复制插件生成的GeneratedPluginRegistrant.java到我们需要打包的module
echo 'Copy GeneratedPluginRegistrant.java to module'
mkdir -p android/${myFlutterModule}/src/main/java/io/flutter/plugins && cp android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java "$_"

# 将依赖的插件打包发布到本地或者远程的maven仓库,需要修改android/build.gradle
echo 'Build and publish module to repo'
cd android
gradlewScript=""
file="../.flutter-plugins"
while read line
do
    array=(${line//=/ })
    moduleName=${array[0]}
    gradlewScript="$gradlewScript:${moduleName}:clean :${moduleName}:uploadArchives "
done < ${file}
gradlewScript=${gradlewScript}":${myFlutterModule}:clean :${myFlutterModule}:uploadArchives "
echo "./gradlew ${gradlewScript}"
./gradlew ${gradlewScript}
指定打包命令

在命令行中执行命令,即可发布aar

sh publish_android_aar.sh

在现成的项目中使用

引入本地仓库

修改项目根目录的build.gradle

buildscript {
    repositories {
        maven {
            url uri('/Users/Wiki/repo')//填写本地的仓库地址
        }
    }
}
在现成项目中使用

修改app目录的build.gradle

dependencies {
    implementation "com.taoweiji.flutter:myflutter:1.0.1-SNAPSHOT"
}
创建一个Activity

我们需要创建一个Activity来承载Flutter的入口,记得在AndroidManifest.xml配置哦

public class MyFlutterActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 初始化Flutter
        FlutterMain.startInitialization(getApplicationContext());
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
    }
}

到这里就大功告成了,Flutter开发和原生开发分割开,通过maven方式引入。

完整源代码

https://github.com/taoweiji/FlutterDemo

附加

Flutter 与 Android 相互调用、传递参数

Flutter 初尝试:入门教程

Flutter 安装教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容