把 Flutter 工程打包成 aar青团,引入到現(xiàn)有的 Android 項(xiàng)目(附源代碼)

我們?cè)趪L試Flutter的時(shí)候,其實(shí)可以在我們現(xiàn)成的項(xiàng)目中加入Flutter咖楣,然后改造我們部分不是特別重要的的功能督笆,避免引發(fā)較大的風(fēng)險(xiǎn),也可以把新技術(shù)引入進(jìn)來(lái)诱贿。在React Native的時(shí)候娃肿,我們也嘗試做過(guò)類似的方案,后來(lái)基于穩(wěn)定性和維護(hù)成本珠十,最終換回了原生開(kāi)發(fā)料扰。

誰(shuí)在用Flutter混合開(kāi)發(fā)?

閑魚(yú)APP就是典型的原生&Flutter開(kāi)發(fā)方案宵睦,通過(guò)Android的“顯示布局邊界”工具记罚,可以看到墅诡,閑魚(yú)APP的商品詳情頁(yè)壳嚎、游戲交易區(qū)、短租交易區(qū)都已經(jīng)是使用Flutter改造末早。

更多使用Flutter的應(yīng)用:https://itsallwidgets.com

分析增加包體積的成本分析(增加5.1MB)

通過(guò)分析生成的正式apk包烟馅,我們可以看到,F(xiàn)lutter的實(shí)現(xiàn)主要是C++實(shí)現(xiàn)然磷,這里會(huì)增加3.5MB大小郑趁,另外就是assets文件夾,這里會(huì)增加1.6 MB姿搜,由于Flutter增加的jar代碼很少寡润,可以忽略不計(jì)。從中分析舅柜,項(xiàng)目中如果加入Flutter梭纹,會(huì)增加5.1MB的大小左右,這個(gè)大小還是非持路荩可觀变抽,不算大。

  • isolate_snapshot_data 應(yīng)用程序數(shù)據(jù)段
  • isolate_snapshot_instr 應(yīng)用程序指令段
  • vm_snapshot_data VM虛擬機(jī)數(shù)據(jù)段
  • vm_snapshot_instr VM虛擬機(jī)指令段
Flutter依賴原理分析

我們通過(guò)默認(rèn)生成的android項(xiàng)目的build.gradle文件可以看到,其實(shí)在我們現(xiàn)成的項(xiàng)目中加入flutter的支持是非常簡(jiǎn)單的绍载,核心就是flutter.gradle诡宗,在flutter的安裝包中flutter/packages/flutter_tools/gradle可以看到這個(gè)文件。

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

packages/flutter_tools/gradle/flutter.gradle
這個(gè)文件的作用主要是:

  1. 增加 flutter.jar和so依賴击儡。
  2. Flutter Plugin編譯依賴插件塔沃。
  3. 插入工程編譯產(chǎn)物,就是assets目錄下的內(nèi)容阳谍,isolate_snapshot_data和vm_snapshot_data芳悲。
在現(xiàn)成項(xiàng)目引入Flutter,基礎(chǔ)版本教程

由于開(kāi)發(fā)Flutter是需要配置Flutter的環(huán)境边坤,在實(shí)際的團(tuán)隊(duì)當(dāng)中名扛,并不是所有成員都必須參與到Flutter開(kāi)發(fā)中,非Flutter開(kāi)發(fā)人員也不應(yīng)該需要配置Flutter開(kāi)發(fā)環(huán)境茧痒,所以我們只需要將需要的代碼引入進(jìn)來(lái)肮韧,非Flutter開(kāi)發(fā)人員就不需要配置環(huán)境,所以我們只需要復(fù)制flutter.jar和libflutter.so和assets文件到我們項(xiàng)目即可旺订。

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;
  }
}

創(chuàng)建一個(gè)Activity承載Flutter

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

在現(xiàn)成項(xiàng)目引入Flutter弄企,升級(jí)版本教程

從上面的基礎(chǔ)教程,我們其實(shí)就已經(jīng)可以實(shí)現(xiàn)在現(xiàn)有的項(xiàng)目中使用Flutter区拳,但是每次都需要復(fù)制文件到指定目錄拘领,其實(shí)我們可以換個(gè)方式來(lái)實(shí)現(xiàn),就是通過(guò)依賴管理實(shí)現(xiàn)樱调,我們將flutter.jar和libflutter.so文件约素,還有assets里面的編譯產(chǎn)物一起打包生成aar,然后上傳到maven倉(cāng)庫(kù)笆凌,我們主工程就可以非常簡(jiǎn)單地通過(guò)依賴方式引入圣猎,絲毫不會(huì)污染原來(lái)的工程代碼,F(xiàn)lutter開(kāi)發(fā)和原生開(kāi)發(fā)就可以進(jìn)行了隔離乞而,后續(xù)會(huì)補(bǔ)充這部分的教程送悔。

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

創(chuàng)建一個(gè)Activity承載Flutter

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

教程

創(chuàng)建android module

在android目錄下的app是flutter默認(rèn)的運(yùn)行宿主,如果我們需要打包成一個(gè)aar爪模,那么我們需要?jiǎng)?chuàng)建一個(gè)module來(lái)承載欠啤,這個(gè)module最重要的地方是build.gradle,這個(gè)文件的內(nèi)容復(fù)制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上傳

發(fā)布aar有兩種声滥,一個(gè)是本地發(fā)布眉撵,一個(gè)是搭建Maven服務(wù)器來(lái)實(shí)現(xiàn)侦香,我們需要修改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'))// 填寫(xiě)本地的倉(cāng)庫(kù)地址
                //repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                //    authentication(userName: ossrhUsername, password: ossrhPassword)
                //}
            }
        }
    }
}
編寫(xiě)打包發(fā)布腳本

在flutter的項(xiàng)目根目錄創(chuàng)建一個(gè)腳本文件 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

# 復(fù)制插件生成的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 "$_"

# 將依賴的插件打包發(fā)布到本地或者遠(yuǎn)程的maven倉(cāng)庫(kù),需要修改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}
指定打包命令

在命令行中執(zhí)行命令纽疟,即可發(fā)布aar

sh publish_android_aar.sh

在現(xiàn)成的項(xiàng)目中使用

引入本地倉(cāng)庫(kù)

修改項(xiàng)目根目錄的build.gradle

buildscript {
    repositories {
        maven {
            url uri('/Users/Wiki/repo')//填寫(xiě)本地的倉(cāng)庫(kù)地址
        }
    }
}
在現(xiàn)成項(xiàng)目中使用

修改app目錄的build.gradle

dependencies {
    implementation "com.taoweiji.flutter:myflutter:1.0.1-SNAPSHOT"
}
創(chuàng)建一個(gè)Activity

我們需要?jiǎng)?chuàng)建一個(gè)Activity來(lái)承載Flutter的入口罐韩,記得在AndroidManifest.xml配置哦

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

到這里就大功告成了,F(xiàn)lutter開(kāi)發(fā)和原生開(kāi)發(fā)分割開(kāi)污朽,通過(guò)maven方式引入散吵。

完整源代碼

https://github.com/taoweiji/FlutterDemo

附加

Flutter 與 Android 相互調(diào)用、傳遞參數(shù)

Flutter 初嘗試:入門教程

Flutter 安裝教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蟆肆,一起剝皮案震驚了整個(gè)濱河市矾睦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炎功,老刑警劉巖枚冗,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蛇损,居然都是意外死亡赁温,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門淤齐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)股囊,“玉大人,你說(shuō)我怎么就攤上這事更啄≈烧睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵祭务,是天一觀的道長(zhǎng)内狗。 經(jīng)常有香客問(wèn)我,道長(zhǎng)待牵,這世上最難降的妖魔是什么其屏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任喇勋,我火速辦了婚禮缨该,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘川背。我一直安慰自己贰拿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布熄云。 她就那樣靜靜地躺著膨更,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缴允。 梳的紋絲不亂的頭發(fā)上荚守,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天珍德,我揣著相機(jī)與錄音,去河邊找鬼矗漾。 笑死锈候,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敞贡。 我是一名探鬼主播泵琳,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼誊役!你這毒婦竟也來(lái)了获列?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛔垢,失蹤者是張志新(化名)和其女友劉穎击孩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鹏漆,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溯壶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甫男。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片且改。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖板驳,靈堂內(nèi)的尸體忽然破棺而出又跛,到底是詐尸還是另有隱情,我是刑警寧澤若治,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布慨蓝,位于F島的核電站,受9級(jí)特大地震影響端幼,放射性物質(zhì)發(fā)生泄漏礼烈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一婆跑、第九天 我趴在偏房一處隱蔽的房頂上張望此熬。 院中可真熱鬧,春花似錦滑进、人聲如沸犀忱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)阴汇。三九已至,卻和暖如春节槐,著一層夾襖步出監(jiān)牢的瞬間搀庶,已是汗流浹背拐纱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哥倔,地道東北人戳玫。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像未斑,于是被迫代替她去往敵國(guó)和親咕宿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容