Flutter与Android工程的混合开发
需求
Flutter与现有Android工程融合后的要求:
- Flutter工程与Android工程解耦
- 扩展能力通过Flutter Plugin实现
- Flutter工程能独立运行
- 包大小要求:只保留armeabi下的so
add to app
细节参考官网文档:Add Flutter to existing apps
Last updated August 23, 2019.
The “add-to-app” support is in preview, and is so far only available on the master channel.
注意点:要使用Flutter的master分支的代码
创建Flutter Module
在Android项目的同级目录下,创建Flutter Module:
1 | flutter create -t module --org com.example wuba_flutter |
创建后的项目结构:
主要结构与正常的Flutter项目一致,主要的区别是:
- android目录,改为了.android
- 多了一个Flutter module,同时app module依赖Flutter module
- 具体的内容:
- 提供用于创建自定Flutter Activity的Api
- 注册所有的插件
- 注意:引Flutter module是通过Flutter tooling自动生成的
- 具体的内容:
- include_flutter.groovy的作用:
- 设置对外暴露的项目名称::flutter
- 关联Flutter Plugin:通过解析flutter项目的.flutter-plugins文件,获取所有的依赖插件
- pubspec.yaml比独立的Flutter项目,多出了如下配置:具体作用可以直接读其注释
以module的方式融合到Android工程
第一步:修改Android工程的settings.gradle文件,添加如下配置:
1 | // 引入Flutter项目 |
第二步:依赖flutter,创建Flutter Activity:
- 依赖flutter
1
implementation project(':flutter')
- 利用Flutter Api,创建Flutter Activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.wuba.flutter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import io.flutter.facade.Flutter;
public class WubaFlutterActivity extends FragmentActivity {
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(android.R.id.content, Flutter.createFragment("/"));
tx.commit();
}
} - 配置Manifest文件
1
2
3
4
5
6
7
8
9
10<activity android:name="com.wuba.flutter.WubaFlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Flutter的加载过程:
- 初始化,加载flutter engine
1
2FlutterMain.startInitialization(activity.getApplicationContext());
FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null); - 为当前的Activity,创建FlutterView
1
2
3
4final FlutterNativeView nativeView = new FlutterNativeView(activity);
final FlutterView flutterView = new FlutterView(activity, null, nativeView) {
...
};
注意点:
- FlutterApplication,FlutterActivity是配套使用的,一个做初始化,一个用于创建FlutterView
- 通过Flutter.createFragment(),创建多个自定义的Activity,会不会造成多次初始化?答案是不会,原因如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public static void startInitialization( { Context applicationContext, FlutterMain.Settings settings)
if (!isRunningInRobolectricTest) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
} else if (sSettings == null) { // 通过静态变量sSettings来保证不会重复初始化
sSettings = settings;
long initStartTimestampMillis = SystemClock.uptimeMillis();
initConfig(applicationContext);
initResources(applicationContext);
System.loadLibrary("flutter");
VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService("window")).init();
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}
}
}
如果使用稳定版本的Flutter SDK编译,编译也会成功,但运行时会报错?
原因:isolate_snapshot_data默认情况下,只在build/intermediates/flutter/debug/android-arm/flutter_assets/生成,不在build/intermediates/library_assets/目录下生成,但多个lib库之间的assets合并,只合并library_assets目录下的文件
以aar的方式融合到Android工程
请参考Add Flutter to existing apps
包大小要求:只保留armeabi下的so
Flutter通过JIT编译后,apk里的存在形式:
主要是两个文件:
- flutter engine:libflutter.so
- dart代码编译后的snapshot:存在assets/flutter_assets目录下
Flutter Engine(libflutter.so):
- 包含哪些模块:
- 编译过程:通过flutter engine的源码编译:https://github.com/flutter/engine
- 开发期间生成过程:使用的是Flutter SDK里已经生成好的,路径地址:flutter sdk/bin/cache/artifacts/engine
- 包括arm,arm64,x86,x64:
- 每个目录下都含有flutter.jar文件
- 包括arm,arm64,x86,x64:
问题:Flutter SDK里携带的flutter engine没有armeabi下的so,只有armeabi-v7a的so,如何实现只保留armeabi的so?
解决方案:
- 把armeabi-v7a下的libflutter.so复制到armeabi目录下 — 现在使用的方案
- 通过flutter engine的源码整体编译一次,产出armeabi的so,编译方法