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

我們在嘗試Flutter的時候,其實可以在我們現成的項目中加入Flutter,然后改造我們部分不是特別重要的的功能,避免引發(fā)較大的風險,也可以把新技術引入進來。在React Native的時候,我們也嘗試做過類似的方案,后來基于穩(wěn)定性和維護成本,最終換回了原生開發(fā)。

誰在用Flutter混合開發(fā)?

閑魚APP就是典型的原生&Flutter開發(fā)方案,通過Android的“顯示布局邊界”工具,可以看到,閑魚APP的商品詳情頁、游戲交易區(qū)、短租交易區(qū)都已經是使用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,基礎版本教程

由于開發(fā)Flutter是需要配置Flutter的環(huán)境,在實際的團隊當中,并不是所有成員都必須參與到Flutter開發(fā)中,非Flutter開發(fā)人員也不應該需要配置Flutter開發(fā)環(huán)境,所以我們只需要將需要的代碼引入進來,非Flutter開發(fā)人員就不需要配置環(huán)境,所以我們只需要復制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;
  }
}

創(chuàng)建一個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開發(fā)和原生開發(fā)就可以進行了隔離,后續(xù)會補充這部分的教程。

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

創(chuàng)建一個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默認的運行宿主,如果我們需要打包成一個aar,那么我們需要創(chuàng)建一個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上傳

發(fā)布aar有兩種,一個是本地發(fā)布,一個是搭建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)
                //}
            }
        }
    }
}
編寫打包發(fā)布腳本

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

# 將依賴的插件打包發(fā)布到本地或者遠程的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}
指定打包命令

在命令行中執(zhí)行命令,即可發(fā)布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"
}
創(chuàng)建一個Activity

我們需要創(chuàng)建一個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開發(fā)和原生開發(fā)分割開,通過maven方式引入。

完整源代碼

https://github.com/taoweiji/FlutterDemo

附加

Flutter 與 Android 相互調用、傳遞參數

Flutter 初嘗試:入門教程

Flutter 安裝教程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容