Flutter Android 端 Activity/Fragment 流程原始碼分析

工匠若水發表於2021-08-08

這是我參與8月更文挑戰的第2天,活動詳情檢視: 8月更文挑戰

Flutter 系列文章連載~

背景

前面文章我們分析了 flutter 在 android 端編譯命令相關流程,我們接下來需要先分析一下 Flutter Android 端 framework 平臺實現程式碼(非 native engine 引擎部分),下面以一個純 Flutter App 為例展開分析。

工程結構及 API 變更

對於一個純 flutter app 來說,當我們在 yaml 依賴中新增兩個 flutter plugin 依賴,然後銅過 Android Studio 匯入安卓工程後可以看到如下結構: 在這裡插入圖片描述 gradle sync 後對應的安卓依賴如下: 在這裡插入圖片描述 可以看到,上面依賴就是我們《Flutter Android 工程結構及應用層編譯原始碼深入分析》一文中分析 Flutter Android App 編譯流程中提到過的動態追加依賴。

對於 Android 平臺來說,Flutter 依賴其實蠻簡單的,我們以啟用 androidx 為例展示 release 模式下的依賴關係,如下:

releaseRuntimeClasspath - Resolved configuration for runtime for variant: release
+--- io.flutter:flutter_embedding_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
|    +--- androidx.lifecycle:lifecycle-common:2.2.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-common-java8:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-runtime:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    +--- androidx.arch.core:core-common:2.1.0
|    |    |    \--- androidx.annotation:annotation:1.1.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.fragment:fragment:1.1.0
|    |    +--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.core:core:1.1.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.2.0 (*)
|    |    |    +--- androidx.versionedparcelable:versionedparcelable:1.1.0
|    |    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0
|    |    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.collection:collection:1.1.0 (*)
|    |    +--- androidx.viewpager:viewpager:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    \--- androidx.customview:customview:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |         \--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.loader:loader:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-livedata:2.0.0
|    |    |    |    +--- androidx.arch.core:core-runtime:2.0.0
|    |    |    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0
|    |    |    |    |    +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    |    |    |    +--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    |    \--- androidx.arch.core:core-runtime:2.0.0 (*)
|    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0
|    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.activity:activity:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.core:core:1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.1.0 -> 2.2.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-viewmodel:2.1.0 (*)
|    |    |    \--- androidx.savedstate:savedstate:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.1.0
|    |    |         +--- androidx.arch.core:core-common:2.0.1 -> 2.1.0 (*)
|    |    |         \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 (*)
|    \--- androidx.annotation:annotation:1.1.0
+--- io.flutter:armeabi_v7a_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
+--- io.flutter:arm64_v8a_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
\--- io.flutter:x86_64_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
複製程式碼

可以看到依賴主要都是 androidx,還是蠻香的。

原始碼分析

Flutter Android 端原始碼主要依賴於 gradle maven 下載,也就是上圖中的io.flutter:flutter_embedding_XXX程式碼,另一個 ABI 依賴是libflutter.so引擎依賴。

本文以 Flutter 2.2.3 版本為例分析,由於新舊版本的 Android 入口存在差異,譬如新版本不再預設使用FlutterApplication配合io.flutter.app.FlutterActivity模式,而是直接使用io.flutter.embedding.android.FlutterActivty,所以我們的入口要從新的看起(注意新舊同類名不同包名的區別)。相關新舊版本遷移變更可以參考官方說明的Upgrading-pre-1.12-Android-projects

FlutterActivity 相關分析

Android App 中預設 Flutter UI 介面呈現在平臺層的實現都繼承自io.flutter.embedding.android.FlutterActivity,主題預設也是一個全屏無 ActionBar 形式,原始碼如下:

public class FlutterActivity extends Activity
    implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
  ......
}
複製程式碼

依據這個繼承關係可以看到,FlutterActivity 直接繼承自 Activity,而不是相容包的 AppCompatActivity,這對於有歷史包袱的 App 來說是一件好事,也秉承了一個優質 SDK 去依賴的優質特點。同時其實現了兩個介面,LifecycleOwner 為標準 AAC 框架成員,我們不再解釋;重點看下FlutterActivityAndFragmentDelegate.Host,原始碼如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  //這裡的一堆extends介面不多解釋,註釋都很明確
  interface Host
      extends SplashScreenProvider,
          FlutterEngineProvider,
          FlutterEngineConfigurator,
          PlatformPlugin.PlatformPluginDelegate {
    //1、獲取宿主Activity或Fragment的context。
    //對應上面FlutterActivity實現此介面就是返回他自己的context,也就是this。
    @NonNull
    Context getContext();
    //2、是否可以通過deeplink調起initial route路由。
    //主要是在AndroidManifest.xml中Activity配置flutter_deeplinking_enabled meta值。
    //參見官方文件 https://flutter.dev/docs/development/ui/navigation/deep-linking
    @Nullable
    boolean shouldHandleDeeplinking();
	//3、獲取宿主Activity或Fragment的attached Activity。
    //對應上面FlutterActivity實現此介面就是返回他自己,也就是this。
    @Nullable
    Activity getActivity();
	//4、獲取宿主Activity或Fragment的Lifecycle。
    @NonNull
    Lifecycle getLifecycle();
	//5、獲取宿主啟動Flutter攜帶的引數,通過intent解析,譬如enable-dart-profiling等。
    @NonNull
    FlutterShellArgs getFlutterShellArgs();
	//6、獲取靜態快取的EngineId,如果沒有就返回空,通過intent的cached_engine_id引數傳遞。
    @Nullable
    String getCachedEngineId();
    //7、當FlutterActivity destory後是否銷燬引擎例項,預設要銷燬。
    //當FlutterEngine屬於Activity自己則需要銷燬返回true,當FlutterEngine屬於靜態快取的,則不用銷燬,這裡應該返回false。
    boolean shouldDestroyEngineWithHost();
    //8、當FlutterEngine已經attach到另一個Activity時這個Activity就需要與FlutterEngine斷開。
    void detachFromFlutterEngine();
    //9、獲取dart主入口,預設時main。
    //可以在AndroidManifest.xml中給Activity設定io.flutter.Entrypoint的meta自定義。
    @NonNull
    String getDartEntrypointFunctionName();
    //10、返回app bundle dart程式碼存在的路徑。
    @NonNull
    String getAppBundlePath();
    //11、獲取初始路由地址。
    //預設先從intent中解析route的值,沒有就去meta-data解析io.flutter.InitialRoute的值,沒有就返回null。
    @Nullable
    String getInitialRoute();
    //12、獲取渲染模式,用在FlutterView呈現FlutterEngine引擎渲染效果。
    @NonNull
    RenderMode getRenderMode();
    //13、獲取Transparency模式,用在FlutterView呈現FlutterEngine引擎渲染效果。
    @NonNull
    TransparencyMode getTransparencyMode();
	//14、提供一個Flutter開屏圖片,預設有配置。
	//通過meta-data配置io.flutter.embedding.android.SplashScreenDrawable可生效。
    @Nullable
    SplashScreen provideSplashScreen();
    //15、返回一個用來渲染FlutterView的FlutterEngine引擎。
    //如果返回null則框架會自動新建一個FlutterEngine引擎例項,預設就是自動新建,我們可以重寫複用等。
    @Nullable
    FlutterEngine provideFlutterEngine(@NonNull Context context);
    //16、建立和配置platform plugin。
    @Nullable
    PlatformPlugin providePlatformPlugin(
        @Nullable Activity activity, @NonNull FlutterEngine flutterEngine);
    void configureFlutterEngine(@NonNull FlutterEngine flutterEngine);
    void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine);
    boolean shouldAttachEngineToActivity();
    void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView);
    void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView);
    void onFlutterUiDisplayed();
    void onFlutterUiNoLongerDisplayed();
    boolean shouldRestoreAndSaveState();
  }
}
複製程式碼

可以看到FlutterActivityAndFragmentDelegate.Host是 Flutter Android 平臺層實現與標準 Activity/Fragment 之間的一個介面約定層,FlutterActivity 實現了這個介面的一系列方法,這些介面的含義上面也列舉了,所以我們下面重心回到標準 Android Activity 生命週期線,如下:

public class FlutterActivity extends Activity
    implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
  ......
  //步驟1、重點!關聯Activity、Fragment與Flutter的介面橋樑委託實現
  protected FlutterActivityAndFragmentDelegate delegate;
  ......
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
  	//步驟2、將清單檔案中標準配置的主題切換回普通主題。很巧妙的讓launch app和initialized後activity主題發生變化。
  	//普通主題通過io.flutter.embedding.android.NormalTheme的meta-data配置。
  	//清單標準配置的是一個圖示、啟動後執行到這裡被換成標準純背景色,兩個主題不要對窗體size進行差異配置,不然會抖動。
    switchLaunchThemeForNormalTheme();

    super.onCreate(savedInstanceState);
	//步驟3、建立一個委託代理類例項,然後呼叫他的一系列方法。
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onRestoreInstanceState(savedInstanceState);
	//步驟4、標準AAC操作,不解釋。
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
	//步驟5、從Activity的Intent中解析background_mode欄位看是transparent還是opaque。
	//透明則通過getWindow().setBackgroundDrawable設定為透明,否則保持NormalTheme的暗黑適配純色背景。
    configureWindowForTransparency();
    //步驟6、建立一個View讓Activity顯示,這就是Flutter的View容器。
    setContentView(createFlutterView());
    //步驟7、官方對全屏狀態列的相容配置。。。
    configureStatusBarForFullscreenFlutterExperience();
  }
  ......

  //步驟8、建立並返回一個View用來給Activity顯示。
  @NonNull
  private View createFlutterView() {
    return delegate.onCreateView(
        null /* inflater */, null /* container */, null /* savedInstanceState */);
  }

  //步驟9、官方對全屏狀態列的相容配置。
  //這些flag不用解釋了吧,標準安卓操作。
  //記住這個坑即可,我們如果想修改FlutterActivity的這玩意就在他之後覆蓋即可。
  private void configureStatusBarForFullscreenFlutterExperience() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      Window window = getWindow();
      window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
      window.setStatusBarColor(0x40000000);
      window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
    }
  }
  
  //步驟10、生命週期回撥處理,AAC呼叫、delegate對應方法觸發等
  @Override
  protected void onStart() {
    super.onStart();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
    //判斷delegate是否不為null
    if (stillAttachedForEvent("onStart")) {
      delegate.onStart();
    }
  }
	
  //步驟11、同步驟10的一堆回撥類似觸發,省略實現。。。
  @Override
  protected void onResume() {......}
  @Override
  public void onPostResume() {......}
  @Override
  protected void onPause() {......}
  @Override
  protected void onStop() {......}
  @Override
  protected void onSaveInstanceState(Bundle outState) {......}
  @Override
  protected void onDestroy() {......}
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {......}
  @Override
  protected void onNewIntent(@NonNull Intent intent) {......}
  @Override
  public void onBackPressed() {......}
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {......}
  @Override
  public void onUserLeaveHint() {......}
  @Override
  public void onTrimMemory(int level) {......}
  ......
  //步驟12、一堆前面介紹的FlutterActivityAndFragmentDelegate.Host介面實現方法。
  ......
}
複製程式碼

FlutterActivityAndFragmentDelegate 相關分析

上一小節我們看到 FlutterActivity 中的核心就是與 FlutterActivityAndFragmentDelegate 例項進行互動,那我們就繼續看看這個例項對應的原始碼,重點先放到 FlutterActivity 中呼叫的例項化、onAttach、onRestoreInstanceState 上。如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  private static final String TAG = "FlutterActivityAndFragmentDelegate";
  private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework";
  private static final String PLUGINS_RESTORATION_BUNDLE_KEY = "plugins";

  //步驟1、host例項就是FlutterActivity或FlutterFragment
  @NonNull private Host host;
  @Nullable private FlutterEngine flutterEngine;
  @Nullable private FlutterSplashView flutterSplashView;
  @Nullable private FlutterView flutterView;
  @Nullable private PlatformPlugin platformPlugin;
  private boolean isFlutterEngineFromHost;
	
  //步驟2、前面小節FlutterActivity的onCreate中例項化,host為FlutterActivity自己的this。
  FlutterActivityAndFragmentDelegate(@NonNull Host host) {
    this.host = host;
  }
  
  //步驟3、前面小節FlutterActivity的onCreate中呼叫
  void onAttach(@NonNull Context context) {
    //確保host不為空,否則丟擲異常。
    ensureAlive();

    //步驟4、flutterEngine為空就建立。
    if (flutterEngine == null) {
      setupFlutterEngine();
    }
	//步驟5、前面小節FlutterActivity中介面實現,預設為true。
    if (host.shouldAttachEngineToActivity()) {
      //步驟6、flutterEngine與FlutterActivity進行attach關聯。
      Log.v(TAG, "Attaching FlutterEngine to the Activity that owns this delegate.");
      flutterEngine.getActivityControlSurface().attachToActivity(this, host.getLifecycle());
    }

    //步驟7、通過host獲取PlatformPlugin例項。
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
	//步驟8、給host配置flutterEngine。
    host.configureFlutterEngine(flutterEngine);
  }

  //步驟9、前面小節FlutterActivity的onCreate中呼叫
  void onRestoreInstanceState(@Nullable Bundle bundle) {
    Log.v(
        TAG,
        "onRestoreInstanceState. Giving framework and plugins an opportunity to restore state.");
    ensureAlive();
	//步驟10、這兩個變數都是在Activity的onSaveInstanceState方法進行set操作賦值的。
    Bundle pluginState = null;
    byte[] frameworkState = null;
    if (bundle != null) {
      //說明來自異常終止恢復Activity
      pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
      frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
    }
	//步驟11、存放時也是這個規則,優先判斷intent中的enable_state_restoration配置。
	//不存在就看getCachedEngineId是不是不為null,是就不會要恢復,即此條件false,反之恢復。
    if (host.shouldRestoreAndSaveState()) {
      flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
    }
	//步驟12、FlutterActivity預設實現是true。
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
    }
  }
  ......
}
複製程式碼

看完上面這段,接下來我們繼續把目光挪到 FlutterActivityAndFragmentDelegate 的 onCreateView 方法上,這個方法的返回值在前面 FlutterActivity 的 onCreate 中被 setContent 設定為 Activity 的 View。如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  //步驟13、FlutterActivity中呼叫時引數均為null,返回一個androd view例項。
  @NonNull
  View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.v(TAG, "Creating FlutterView.");
    //確保host屬性不為null。
    ensureAlive();
	//步驟14、依據前面FlutterActivity的intent引數background_mode決定模式,預設surface模式。
	//FlutterActivity預設背景是opaque、可以設定為transparent。
	//當FlutterActivity的window背景不透明則RenderMode為surface模式、反之texture模式。
    if (host.getRenderMode() == RenderMode.surface) {
      //步驟15、建立一個FlutterSurfaceView。
      //然後通過host介面呼叫FlutterActivity的onFlutterSurfaceViewCreated方法,預設空實現。
      //getTransparencyMode模式和FlutterActivity的window背景模式完全一樣邏輯。
      FlutterSurfaceView flutterSurfaceView =
          new FlutterSurfaceView(
              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
      host.onFlutterSurfaceViewCreated(flutterSurfaceView);

      //步驟15、建立一個FlutterView包含FlutterSurfaceView。
      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    } else {
      //步驟16、建立一個FlutterTextureView。
      //然後通過host介面呼叫FlutterActivity的onFlutterSurfaceViewCreated方法,預設空實現。
      FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
      host.onFlutterTextureViewCreated(flutterTextureView);

      //步驟17、建立一個FlutterView包含FlutterTextureView。
      flutterView = new FlutterView(host.getActivity(), flutterTextureView);
    }

    //步驟18、新增監聽,當flutter渲染首幀時回撥。
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
	//步驟19、建立一個FlutterSplashView開屏view
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      //這裡不得不吐槽官方,不過確實沒好的辦法,直接寫死了一個隨機id,有可能衝突,且一個view樹只能有一個FlutterSplashView了。
      flutterSplashView.setId(486947586);
    }
    //步驟20、顯示開屏圖示,即io.flutter.embedding.android.SplashScreenDrawable配置的drawable圖。
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
	//步驟21、FlutterView與flutterEngine關聯attach。
    Log.v(TAG, "Attaching FlutterEngine to FlutterView.");
    flutterView.attachToFlutterEngine(flutterEngine);
	//返回被開屏view包裹的FlutterView。
    return flutterSplashView;
  }

  //步驟22、一組回撥監聽定義,回撥中本質是觸發呼叫對應FlutterActivity或FlutterFragment的FlutterActivityAndFragmentDelegate.Host實現方法。
  @NonNull
  private final FlutterUiDisplayListener flutterUiDisplayListener =
      new FlutterUiDisplayListener() {
        @Override
        public void onFlutterUiDisplayed() {
          //本質在FlutterActivity中呼叫Activity 5.0以上的reportFullyDrawn()安卓官方方法。
          host.onFlutterUiDisplayed();
        }

        @Override
        public void onFlutterUiNoLongerDisplayed() {
          //本質在FlutterActivity中呼叫,預設空實現。
          host.onFlutterUiNoLongerDisplayed();
        }
      };
  ......
}
複製程式碼

接著繼續看 FlutterActivity 生命週期及事件相關方法對 FlutterActivityAndFragmentDelegate 相關方法的呼叫,如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  void onStart() {
    ......
    doInitialFlutterViewRun();
  }

  //步驟23、開始在FlutterView中執行dart程式。
  private void doInitialFlutterViewRun() {
    ......
	//步驟24、判斷是否dart已經執行中。
	//這個情況只會發生在config change後我們沒有保留Fragment例項的場景,儘量不要這樣。
    if (flutterEngine.getDartExecutor().isExecutingDart()) {
      return;
    }
    //步驟25、各種優先順序獲取初始跳轉dart的路由地址。
    String initialRoute = host.getInitialRoute();
    if (initialRoute == null) {
      initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
      if (initialRoute == null) {
        initialRoute = DEFAULT_INITIAL_ROUTE; //值為 /
      }
    }
    //過濾這個tag可以除錯flutter初始路由跳轉資訊。
    Log.v(
        TAG,
        "Executing Dart entrypoint: "
            + host.getDartEntrypointFunctionName()
            + ", and sending initial route: "
            + initialRoute);

    //步驟26、通過引擎的NavigationChannel設定初始路由資訊。
    flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
	//步驟27、按照優先順序獲取appBundlePath,預設從host獲取,無則從FlutterLoader獲取。
    String appBundlePathOverride = host.getAppBundlePath();
    if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
      appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
    }

    //步驟28、配置dart的entrypoint並且執行,預設入口函式名為main,可通過meta-data的io.flutter.Entrypoint修改。
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            appBundlePathOverride, host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }
  ......
  //步驟29、FlutterActivity的onResume呼叫它。
  void onResume() {
	......
	//呼叫引擎的LifecycleChannel觸發方法。
    flutterEngine.getLifecycleChannel().appIsResumed();
  }

  //步驟30、雷同onResume不做說明,都是呼叫flutterEngine.getLifecycleChannel()的對應方法。
  void onPause() {......}
  void onStop() {......}
  void onUserLeaveHint() {......}
  ......
  void onPostResume() {
    ......
    if (flutterEngine != null) {
      if (platformPlugin != null) {
        //步驟31、即FlutterActivity中providePlatformPlugin方法返回的PlatformPlugin例項。
        platformPlugin.updateSystemUiOverlays();
      }
    } else {
      Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity.");
    }
  }
  ......
  //步驟32、返回按鈕觸發,通過NavigationChannel通道退棧route。
  void onBackPressed() {
    ensureAlive();
    if (flutterEngine != null) {
      Log.v(TAG, "Forwarding onBackPressed() to FlutterEngine.");
      flutterEngine.getNavigationChannel().popRoute();
    } else {
      Log.w(TAG, "Invoked onBackPressed() before FlutterFragment was attached to an Activity.");
    }
  }

  //步驟33、動態許可權申請返回處理,轉發到感興趣的Flutter Plugin去。
  void onRequestPermissionsResult(
      int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    ensureAlive();
    if (flutterEngine != null) {
      ......
      flutterEngine
          .getActivityControlSurface()
          .onRequestPermissionsResult(requestCode, permissions, grantResults);
    } else {
      Log.w(
          TAG,
          "onRequestPermissionResult() invoked before FlutterFragment was attached to an Activity.");
    }
  }

  //步驟34、activity result返回處理,轉發到感興趣的Flutter Plugin去。
  void onActivityResult(int requestCode, int resultCode, Intent data) {
    ensureAlive();
    if (flutterEngine != null) {
      ......
      flutterEngine.getActivityControlSurface().onActivityResult(requestCode, resultCode, data);
    } else {
      Log.w(TAG, "onActivityResult() invoked before FlutterFragment was attached to an Activity.");
    }
  }

  //步驟35、通過SystemChannel傳送低記憶體訊息。
  void onLowMemory() {
    Log.v(TAG, "Forwarding onLowMemory() to FlutterEngine.");
    ensureAlive();
    flutterEngine.getDartExecutor().notifyLowMemoryWarning();
    flutterEngine.getSystemChannel().sendMemoryPressureWarning();
  }
  ......
}
複製程式碼

通過這一小節的程式碼段分析,我們可以看出來 Flutter 在平臺 SDK 層包裝都是 FlutterActivityAndFragmentDelegate 來負責的,FlutterActivityAndFragmentDelegate 和核心是 FlutterView 和 FlutterEngine 的建立關聯與管理排程。

FlutterFragment 相關分析

分析完上面 FlutterActivity 相關流程,我們接著看看 FlutterFragment,繼承自androidx.fragment.app.Fragment,言外之意就是說 Activity 也得最好是用配套的 FlutterFragmentActivity。關於 FlutterFragmentActivity 我們會在下一個小節分析,這裡重點關注 FlutterFragment。

其實官方註釋也明確說明了,他們不是特別優先推薦使用 FlutterFragment,建議儘可能優選 FlutterActivity。因為使用 FlutterFragment 如果配合的 Activity 不是 FlutterFragmentActivity,需要我們自己去關聯一些 Activity 與 FlutterFragment 的方法,這些方法在 FlutterFragment 的原始碼中都以@ActivityCallThrough進行了註釋宣告,讓使用變的沒那麼方便,譬如:

  • onPostResume()
  • onBackPressed()
  • onRequestPermissionsResult(int, String[], int[])} ()
  • onNewIntent(Intent)} ()
  • onUserLeaveHint()

如上 FlutterFragment 中的方法都需要主動與 Acitivty 關聯呼叫(FlutterFragmentActivity 已實現)。下面是 FlutterFragment 的主要原始碼:

//步驟36、FlutterFragment也實現了前面分析的FlutterActivityAndFragmentDelegate.Host介面,含義不解釋。
public class FlutterFragment extends Fragment
    implements FlutterActivityAndFragmentDelegate.Host, ComponentCallbacks2 {
  ......
  @Override
  public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    //步驟37、與FlutterActivity的區別在於FlutterFragment在他自己的onAttach中例項化FlutterActivityAndFragmentDelegate並呼叫onAttach方法。
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(context);
  }

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //步驟38、與FlutterActivity類似,不做過多分析說明。
    delegate.onRestoreInstanceState(savedInstanceState);
  }

  @Nullable
  @Override
  public View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //步驟39、與FlutterActivity類似,只不過是在FlutterFragment對應生命週期回撥。
    return delegate.onCreateView(inflater, container, savedInstanceState);
  }
  ......
  //步驟39、與FlutterActivity類似,只是這個方法不是Fragment自己框架回撥,需要依賴在Activity中呼叫。
  //譬如FlutterFragmentActivity中對應同名方法的實現。
  //注意這裡的@ActivityCallThrough註解就是這個含義。
  @ActivityCallThrough
  public void onPostResume() {
    delegate.onPostResume();
  }
  ......
}
複製程式碼

可以看到,FlutterFragment 和 FlutterActivity 基本沒啥區別,核心都是實現了FlutterActivityAndFragmentDelegate.Host介面,在自己生命週期內先例項化一個 FlutterActivityAndFragmentDelegate,接著呼叫其一系列方法進行互動,前面 FlutterActivity 已經解釋過了,這裡不多解釋。

FlutterFragmentActivity 相關分析

通過上面 FlutterFragment 原始碼我們可以看到,FlutterFragmentActivity 可以說是 FlutterFragment 的一個承載 Activity,這個 Activity 繼承自androidx.fragment.app.FragmentActivity,所以使用 FlutterFragment 及 FlutterFragmentActivity 對你應用的基類 Activity 還是有一點限制的,沒有前面介紹的 FlutterActivity 香。

由於 FlutterFragmentActivity 繼承自androidx.fragment.app.FragmentActivity,所以相比 FlutterActivity 來說,AAC 架構那套就不用自己顯式關聯了,因為androidx.fragment.app.FragmentActivity內部已做好關聯處理。

//步驟40、這裡implements的一堆其實FlutterActivityAndFragmentDelegate.Host都有implements,算是Host的子集吧。
//本質和FlutterActivityAndFragmentDelegate.Host對於實現方乾的一樣的事。
public class FlutterFragmentActivity extends FragmentActivity
    implements SplashScreenProvider, FlutterEngineProvider, FlutterEngineConfigurator {
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    //步驟41、這裡和FlutterActivity完全一樣,只是不用例項化一個FlutterActivityAndFragmentDelegate,因為其內部的FlutterFragment會做這些事。
    switchLaunchThemeForNormalTheme();
    super.onCreate(savedInstanceState);
    configureWindowForTransparency();
    //步驟42、這裡區別是呼叫createFragmentContainer生成了一個View設定給Activity的content。
    setContentView(createFragmentContainer());
    //步驟43、這裡和FlutterActivity完全一樣。
    configureStatusBarForFullscreenFlutterExperience();
    //步驟44、與FlutterActivity不一樣,這裡檢驗的是FlutterFragment是否新增OK。
    ensureFlutterFragmentCreated();
  }

  //步驟45、上面步驟42設定的View,用來放置FlutterFragment的容器View,本質是一個FrameLayout且MATCH_PARENT。
  @NonNull
  private View createFragmentContainer() {
    FrameLayout container = provideRootLayout(this);
    container.setId(FRAGMENT_CONTAINER_ID);
    container.setLayoutParams(
        new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    return container;
  }

  protected FrameLayout provideRootLayout(Context context) {
    return new FrameLayout(context);
  }

  //步驟46、確保給Activity上attach一個FlutterFragment,不存在就建立一個通過FragmentManager新增。
  private void ensureFlutterFragmentCreated() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    flutterFragment = (FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
    if (flutterFragment == null) {
      flutterFragment = createFlutterFragment();
      fragmentManager
          .beginTransaction()
          .add(FRAGMENT_CONTAINER_ID, flutterFragment, TAG_FLUTTER_FRAGMENT)
          .commit();
    }
  }

  //步驟47、建立一個FlutterFragment。
  //如果我們自定義FlutterFragmentActivity子類,可以重寫這個方法實現自己的自定義FlutterFragment。
  @NonNull
  protected FlutterFragment createFlutterFragment() {
    final BackgroundMode backgroundMode = getBackgroundMode();
    final RenderMode renderMode = getRenderMode();
    final TransparencyMode transparencyMode =
        backgroundMode == BackgroundMode.opaque
            ? TransparencyMode.opaque
            : TransparencyMode.transparent;
	//步驟48、依據是否Engine快取決定怎麼建立FlutterFragment。
    if (getCachedEngineId() != null) {
      ......
      return FlutterFragment.withCachedEngine(getCachedEngineId())
          .renderMode(renderMode)
          .transparencyMode(transparencyMode)
          .handleDeeplinking(shouldHandleDeeplinking())
          .shouldAttachEngineToActivity(shouldAttachEngineToActivity())
          .destroyEngineWithFragment(shouldDestroyEngineWithHost())
          .build();
    } else {
      ......
      return FlutterFragment.withNewEngine()
          .dartEntrypoint(getDartEntrypointFunctionName())
          .initialRoute(getInitialRoute())
          .appBundlePath(getAppBundlePath())
          .flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
          .handleDeeplinking(shouldHandleDeeplinking())
          .renderMode(renderMode)
          .transparencyMode(transparencyMode)
          .shouldAttachEngineToActivity(shouldAttachEngineToActivity())
          .build();
    }
  }
  ......
  //步驟49、呼叫flutterFragment對應生命週期回撥。
  //可以看到,使用FlutterFragmentActivity配合FlutterFragment的好處就是這些FlutterFragment的@ActivityCallThrough都幫你呼叫好了。
  @Override
  public void onPostResume() {
    super.onPostResume();
    flutterFragment.onPostResume();
  }
  ......
}
複製程式碼

總結

到此我們其實就知道 FlutterActivity 和 FlutterFragment 的大致實現,相信你通過上面分析對 Flutter App 在安卓端的承載有一定認識,通常一個 engine 的整個 Flutter Dart 無論頁面棧多少級,終歸在安卓端都是一個 Activity 或者 Fragment 承載,抑或 View,端側僅僅算是一個容器而已。

這也就是為什麼我們在 Android 平臺上檢視一個標準 Flutter App 的 Activity 堆疊預設只有繼承自 FlutterActivity 的一個 Activity,其內部 View 層級如下的原因: 在這裡插入圖片描述 關於本文更多樣例可以參見官方文件:

這裡不做過多演示。

相關文章