一、前言
Flutter現在已經很火了,但是如果我們要想使用Flutter開發,在新的Flutter項目上集成以前的所有代碼肯定是不現實的,同時又不想將Flutter直接侵入到我們的項目結構中去,於是最優解就是將開發的Flutter項目單獨編譯成aar,然後以組件的形式被主工程依賴。
這樣做的好處是顯而易見的:對Flutter進行探索開發的同學可以在自己的Flutter工程內編寫dart代碼,獨立運行調試,完成的時候打包成aar集成到主工程中供寫native代碼的同學接入,兩方協同工作,不會產生衝突。
二、打包apk並分析
首先創建flutter工程,會得到如下目錄
在命令行輸入打包命令 flutter build apk
會編譯生成apk文件 位於 build/app/outputs/apk/release/app-release.apk
打開apk可以看到,裏面目錄爲
可以看到多出來很多東西,這些產物都來自於flutter的構建代碼,
在android/app/build.gradle
中依賴了了flutter.gradle
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
通過閱讀flutter.gradle的構建源碼,可以發現在構建apk的過程中,會將需要的文件構建到apk中。
1、assets文件夾
assets文件夾下面有flutter_assets文件夾、flutter_shared文件夾、isolate_snapshot_data、isolate_snapshot_instr、vm_snapshot_data、vm_snapshot_instr文件
- flutter_assets裏是flutter工程產生的assets文件
- flutter_shared裏是封裝在flutter.jar裏面的處理字符編碼的ICU庫
- isolate_snapshot_data、isolate_snapshot_instr、vm_snapshot_data、vm_snapshot_instr爲特定平臺的數據和指令
2、lib文件夾
lib文件夾下是特定平臺(arm或者x86)的so文件,flutter在Android平臺下會默認生成arm-v7架構的的so庫。
三、打包aar
上面通過編譯命令得到了apk,如果要想打包aar,理論上只需要把app/build.gradle中的apply plugin: 'com.android.application
改爲apply plugin: 'com.android.library
,同時註釋掉applicationId "com.flutterappfirst"
,並且將清單文件修改爲:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flutterappfirst"/>
然後執行以下命令,就能得到app-release.aar
文件
#!/bin/bash
flutter clean
cd android
./gradlew assembleRelease
但是,我們將aar解壓然後看其目錄結構,如下圖:
我們發現在aar文件夾下的assets裏面缺少了flutter_shared文件夾,icudtl.dat文件正是在該文件夾裏面,也就是說flutter.gradle在編譯流程中並沒有將icudtl.dat文件打進aar包裏面,那麼我們的解決辦法是將該文件夾手動拷貝到flutter工程中,如下圖
然後再次執行上述打包aar的命令,得到app-release.aar
文件,正確的結構如下圖:
可以看到flutter_shared文件夾已經放到assets目錄裏面了。
四、集成到現有Android項目
上述打包成功的aar就可以作爲普通的aar集成到Android項目中了
1、拷貝aar到現有android項目中,拷貝到libs目錄下
2、配置build.gradle
repositories {
flatDir { dirs 'libs' }
}
dependencies {
compile(name: 'app-release', ext: 'aar')
}
當然也可以將aar發佈到jcenter之類的遠程倉庫中,這個流程就跟之前發佈aar流程一樣了,然後在build.gradle中進行遠程導入就OK
3、拷貝Flutter提供的集成類到項目中
因爲集成aar後需要將Flutter寫的界面在Android項目中進行展示,那麼就需要有個橋去調用,那麼具體的橋Flutter sdk已經提供了代碼,具體目錄爲${flutter_sdk}/packages/flutter_tools/templates/module/android/library/Flutter.tmpl/src/main/java/io/flutter/facade
,將facade包直接拷到你現在的Android項目中,或者打包成jar再拷貝集成到現有項目中。
我這邊已經打好jar包,可以直接下載,然後導入到工程中
flutter-facade.jar
4、展示Flutter界面
在某個新建的activity中調用如下代碼:
/**
* @author xueshanshan
* @date 2018/12/28
*/
public class FlutterMainActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FlutterView flutterView = Flutter.createView(this, getLifecycle(), "");
setContentView(flutterView);
}
}
然後就能展示Flutter void main() => runApp(new MyApp());
這句話對應的界面了。
但是,一般情況下我們是根據原生工程調用讓Flutter生成不同的組件作爲View來供原生工程調用,那麼我們就可以從這個main函數入手
void main() => runApp(_widgetForRoute(window.defaultRouteName));
Widget _widgetForRoute(String route) {
switch (route) {
case 'route1':
return SomeWidget(...);
case 'route2':
return SomeOtherWidget(...);
default:
return Center(
child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
);
}
}
這樣,我們就可以在不同的界面加載不同的flutter組件了。