1. Flutter Page和Android Activity/Fragment 生命周期同步
這個(gè)類的主要作用就是同步activity 和Flutter的生命周期
@Override
public void onCreate() {
//....
mState = STATE_CREATED;
mContainer.getBoostFlutterView().onResume();
mProxy.create();
}
@Override
public void onAppear() {
//....
mState = STATE_APPEAR;
mManager.pushRecord(this);
mContainer.getBoostFlutterView().onAttach();
mProxy.appear();
}
@Override
public void onDisappear() {
//....
mState = STATE_DISAPPEAR;
mProxy.disappear();
if(getContainer().getContextActivity().isFinishing()) {
mProxy.destroy();
}
mContainer.getBoostFlutterView().onDetach();
mManager.popRecord(this);
}
@Override
public void onDestroy() {
//....
mState = STATE_DESTROYED;
mProxy.destroy();
mContainer.getBoostFlutterView().onDestroy();
mManager.removeRecord(this);
mManager.setContainerResult(this,-1,-1,null);
if (!mManager.hasContainerAppear()) {
mContainer.getBoostFlutterView().onPause();
mContainer.getBoostFlutterView().onStop();
}
}
//....其他的生命周期
同步的生命周期主要有onAppear/onDisappear/onDestroy 等
還有一個(gè)就是methodProxy 通信代理類帚稠,告知flutter頁(yè)面的生命周期的回調(diào)
private class MethodChannelProxy {
private int mState = STATE_UNKNOW;
private void create() {
if (mState == STATE_UNKNOW) {
invokeChannelUnsafe("didInitPageContainer",
mContainer.getContainerUrl(),
mContainer.getContainerUrlParams(),
mUniqueId
);
mState = STATE_CREATED;
}
}
public void invokeChannelUnsafe(String method, String url, Map params, String uniqueId) {
HashMap<String, Object> args = new HashMap<>();
args.put("pageName", url);
args.put("params", params);
args.put("uniqueId", uniqueId);
FlutterBoost.singleton().channel().invokeMethodUnsafe(method, args);
}
}
//其他頁(yè)面生命周期的回調(diào)......
public static String genUniqueId(Object obj) {
return System.currentTimeMillis() + "-" + obj.hashCode();
}
之后總體會(huì)調(diào)用到BoostChannel類中的invokeMethodUnsafe/invokeMethod方法中
public void invokeMethodUnsafe(final String name,Serializable args){
invokeMethod(name, args, new MethodChannel.Result() {
@Override
public void success(@Nullable Object o) {
//every thing ok...
}
@Override
public void error(String s, @Nullable String s1, @Nullable Object o) {
Debuger.log("invoke method "+name+" error:"+s+" | "+s1);
}
@Override
public void notImplemented() {
Debuger.log("invoke method "+name+" notImplemented");
}
});
}
對(duì)應(yīng)的APP整體的聲明周期回調(diào)是通過Application.ActivityLifecycleCallbacks 這個(gè)回調(diào)函數(shù)來確認(rèn)的
FlutterBoost構(gòu)造函數(shù)注冊(cè)了這個(gè)回調(diào)函數(shù)
具體代碼如下
class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentActiveActivity == null) {
if (mEngineProvider.tryGetEngine() != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "foreground");
channel().sendEvent("lifecycle",map);
}
}
mCurrentActiveActivity = activity;
}
//....其他APP生命周期回調(diào)
}
通過上面的invokeMethod會(huì)通過Channel調(diào)用到Flutter對(duì)應(yīng)的boost_channel.dart對(duì)應(yīng)的方法中
typedef Future<dynamic> EventListener(String name, Map arguments);
typedef Future<dynamic> MethodHandler(MethodCall call);
class BoostChannel {
final MethodChannel _methodChannel = MethodChannel("flutter_boost");
final Map<String, List<EventListener>> _eventListeners = Map();
final Set<MethodHandler> _methodHandlers = Set();
BoostChannel() {
_methodChannel.setMethodCallHandler((MethodCall call){
if (call.method == "__event__") {
//取出對(duì)應(yīng)的參數(shù)
String name = call.arguments["name"];
Map arg = call.arguments["arguments"];
List<EventListener> list = _eventListeners[name];
if (list != null) {
for (EventListener l in list) {
//App生命周期 循環(huán)調(diào)用給回調(diào)函數(shù)
l(name, arg);
}
}
}else{
for(MethodHandler handler in _methodHandlers) {
//頁(yè)面Page生命周期 循環(huán)調(diào)用給回調(diào)函數(shù)
handler(call);
}
}
return Future.value();
});
}
}
執(zhí)行回調(diào)是FlutterBoost的構(gòu)造函數(shù)調(diào)用ContainerCoordinator(_boostChannel)之后進(jìn)入到了container_coordinator.dart中
ContainerCoordinator(BoostChannel channel) {
assert(_instance == null);
_instance = this;
channel.addEventListener("lifecycle",
(String name, Map arguments) => _onChannelEvent(arguments));
channel.addMethodHandler((MethodCall call) => _onMethodCall(call));
}
Future<dynamic> _onChannelEvent(dynamic event) {
if (event is Map) {
Map map = event;
final String type = map['type'];
switch (type) {
case 'foreground':
{
FlutterBoost.containerManager?.setForeground();
}
break;
//....其他App生命周期回調(diào)處理
}
}
}
Future<dynamic> _onMethodCall(MethodCall call) {
switch (call.method) {
case "didInitPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerDidInit(pageName, params, uniqueId);
}
break;
//....其他頁(yè)面生命周期回調(diào)處理
}
}
2.Flutter引擎復(fù)用邏輯
主要是體現(xiàn)在XFlutterView 的attachToFlutterEngine和detachFromFlutterEngine方法中
public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
Log.d(TAG, "attachToFlutterEngine()");
if (isAttachedToFlutterEngine()) {
if (flutterEngine == this.flutterEngine) {
// 相同 復(fù)用之前的引擎
return;
}
// 不同 移除之前的引擎
detachFromFlutterEngine();
}
//重新賦值
this.flutterEngine = flutterEngine;
// 設(shè)置渲染層
this.flutterEngine.getRenderer().attachToRenderSurface(renderSurface);
// 重設(shè)輸入輸出
textInputPlugin = new TextInputPlugin(
this,
this.flutterEngine.getDartExecutor()
);
//android 的鍵盤處理
androidKeyProcessor = new AndroidKeyProcessor(
this.flutterEngine.getKeyEventChannel(),
textInputPlugin
);
//觸摸處理
androidTouchProcessor = new AndroidTouchProcessor(this.flutterEngine.getRenderer());
//輔助連接橋
accessibilityBridge = new AccessibilityBridge(
this,
flutterEngine.getAccessibilityChannel(),
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE),
getContext().getContentResolver(),
// TODO(mattcaroll): plumb the platform views controller to the accessibility bridge.
// https://github.com/flutter/flutter/issues/29618
null
);
accessibilityBridge.setOnAccessibilityChangeListener(onAccessibilityChangeListener);
resetWillNotDraw(
accessibilityBridge.isAccessibilityEnabled(),
accessibilityBridge.isTouchExplorationEnabled()
);
//重啟輸入連接
textInputPlugin.getInputMethodManager().restartInput(this);
//一系列初始化
// Push View and Context related information from Android to Flutter.
sendUserSettingsToFlutter();
sendLocalesToFlutter(getResources().getConfiguration());
sendViewportMetricsToFlutter();
}
public void detachFromFlutterEngine() {
if (!isAttachedToFlutterEngine()) {
return;
}
//重啟輸入連接
textInputPlugin.getInputMethodManager().restartInput(this);
// 移除渲染層
flutterEngine.getRenderer().detachFromRenderSurface();
flutterEngine = null;
}
引擎相同則復(fù)用康二,不同detach 之前,重新賦值以及初始化相關(guān)的配置
3.打開Flutter頁(yè)面的主要邏輯
調(diào)用鏈 PageRouter.openPageByUrl -->BoostFlutterEngine.startRun -->BoostFlutterActivity.onCreate -->createFlutterView(mFlutterEngine)
BoostFlutterEngine.startRun
BoostFlutterEngine.startRun這個(gè)方法的啟動(dòng)主要是在Application 配置的啟動(dòng)的方式來決定的
int IMMEDIATELY = 0; //立即啟動(dòng)引擎
int ANY_ACTIVITY_CREATED = 1; //當(dāng)有任何Activity創(chuàng)建時(shí),啟動(dòng)引擎
@Override
public int whenEngineStart() {
return ANY_ACTIVITY_CREATED;
}
默認(rèn)使用這個(gè)ANY_ACTIVITY_CREATED 的時(shí)候,會(huì)在ActivityLifecycleCallbacks回調(diào)函數(shù)中做處理
class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (platform().whenEngineStart() == IPlatform.ANY_ACTIVITY_CREATED) {
sInstance.mEngineProvider
.provideEngine(activity)
.startRun(activity);
}
}
}
BoostFlutterActivity.onCreate
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
configureWindowForTransparency();
//創(chuàng)建同步器
mSyncer = FlutterBoost.singleton().containerManager().generateSyncer(this);
//創(chuàng)建引擎
mFlutterEngine = createFlutterEngine();
//創(chuàng)建FlutterView
mFlutterView = createFlutterView(mFlutterEngine);
setContentView(mFlutterView);
//同步器初始化
mSyncer.onCreate();
//配置狀態(tài)欄
configureStatusBarForFullscreenFlutterExperience();
}
同步器就是前面講的ContainerRecord,主要是同步Flutter和Android的頁(yè)面和APP狀態(tài)
FlutterEngine,這個(gè)是Flutter的核心,flutter_boost對(duì)其做了進(jìn)一步的封裝
FlutterView 主要是展示Flutter中的Widget頁(yè)面
4.FlutterEngine 封裝
主要是修改DartExecutor.DartEntrypoint和 InitRoute 以及對(duì)應(yīng)的插件注冊(cè)
public BoostFlutterEngine(@NonNull Context context, DartExecutor.DartEntrypoint entrypoint, String initRoute) {
super(context);
mContext = context.getApplicationContext();
mBoostPluginRegistry = new BoostPluginRegistry(this, context);
//支持用戶的修改的進(jìn)入點(diǎn) 一般對(duì)應(yīng)的main
if (entrypoint != null) {
mEntrypoint = entrypoint;
} else {
mEntrypoint = defaultDartEntrypoint(context);
}
//初始化路由
if (initRoute != null) {
mInitRoute = initRoute;
} else {
mInitRoute = defaultInitialRoute(context);
}
//獲取FlutterJNI用于引擎通信相關(guān)的
FlutterJNI flutterJNI = null;
try {
Field field = FlutterEngine.class.getDeclaredField("flutterJNI");
field.setAccessible(true);
flutterJNI = (FlutterJNI) field.get(this);
} catch (Throwable t) {
try {
for(Field field:FlutterEngine.class.getDeclaredFields()) {
field.setAccessible(true);
Object o = field.get(this);
if(o instanceof FlutterJNI) {
flutterJNI = (FlutterJNI)o;
}
}
if(flutterJNI == null) {
throw new RuntimeException("FlutterJNI not found");
}
}catch (Throwable it){
Debuger.exception(it);
}
}
mFakeRender = new FakeRender(flutterJNI);
}
BoostRegistrar 插件注冊(cè)主要是獲取Activity,讓Container 和Activity同步
@Override
public Activity activity() {
Activity activity;
IContainerRecord record;
//獲取當(dāng)前的Container
record = FlutterBoost.singleton().containerManager().getCurrentTopRecord();
if (record == null) {
//獲取最后生成Container
record = FlutterBoost.singleton().containerManager().getLastGenerateRecord();
}
if (record == null) {
activity = FlutterBoost.singleton().currentActivity();
} else {
activity = record.getContainer().getContextActivity();
}
if (activity == null && mCurrentActivityRef != null) {
activity = mCurrentActivityRef.get();
}
if (activity == null) {
throw new RuntimeException("current has no valid Activity yet");
}
return activity;
5.BoostFlutterView封裝View
BoostFlutterView主要是封裝各種Flutter需要加載的東西
private void init() {
//創(chuàng)建引擎
if (mFlutterEngine == null) {
mFlutterEngine = createFlutterEngine(getContext());
}
//activity傳遞的參數(shù)
if (mArguments == null) {
mArguments = new Bundle();
}
//FlutterBoost平臺(tái)自身需要的參數(shù)
mPlatformPlugin = new PlatformPlugin((Activity) getContext(), mFlutterEngine.getPlatformChannel());
//封裝的XFlutterView
mFlutterView = new XFlutterView(getContext(), getRenderMode(), getTransparencyMode());
//添加控件
addView(mFlutterView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
//截屏View
mSnapshot = new SnapshotView(getContext());
//Flutter引擎初始化loading
if(mRenderingProgressCoverCreator != null) {
mRenderingProgressCover = mRenderingProgressCoverCreator
.createRenderingProgressCover(getContext());
}else{
mRenderingProgressCover = createRenderingProgressCorver();
}
//添加loading
if(mRenderingProgressCover != null) {
addView(mRenderingProgressCover, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
//監(jiān)聽第一幀繪制回調(diào)函數(shù)
mFlutterView.addOnFirstFrameRenderedListener(mOnFirstFrameRenderedListener);
//啟動(dòng)封裝引擎
mFlutterEngine.startRun((Activity)getContext());
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if(stateListener != null) {
stateListener.onFlutterViewInited(mFlutterEngine,this);
}
checkAssert();
}
默認(rèn)的createRenderingProgressCorver返回的是一個(gè)ProgressBar 用戶可以根據(jù)重寫這個(gè)方法自己修改loading界面
結(jié)語(yǔ)
還有一些相關(guān)的類 XAndroidKeyProcessor(按鍵處理)/XInputConnectionAdaptor(輸入輸出適配)/XTextInputPlugin(輸入插件)莱革【撸總體來講,flutter_boost的Android版本插件難度不是很大盅视,F(xiàn)lutter Page/App生命周期同步以及引擎封裝思路還是不錯(cuò)的捐名,可以像WebView一樣的使用是該插件的初衷。以后有時(shí)間還有進(jìn)一步的解讀源碼闹击。