欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Flutter Android启动源码分析(二)

程序员文章站 2022-04-21 10:20:40
前言上篇文章Flutter Android启动源码分析(一)中主要对FlutterApplicaiton和FlutterActivity进行了分析,在FlutterActivity源码部分中FlutterActivityAndFragmentDelegate这个类一直被提到,这篇文章我们就主要分析一下它做了哪些事情Flutter Android启动源码分析(一)FlutterActivityAndFragmentDelegate作用FlutterActivity和FlutterFragment...

前言

上篇文章Flutter Android启动源码分析(一)中主要对FlutterApplicaiton和FlutterActivity进行了分析,在FlutterActivity源码部分中FlutterActivityAndFragmentDelegate这个类一直被提到,这篇文章我们就主要分析一下它做了哪些事情

Flutter Android启动源码分析(一)

FlutterActivityAndFragmentDelegate

  • 作用
    • FlutterActivity和FlutterFragment之间相同的Flutter逻辑的委托
  • 为什么要用这个类
    • 假设可以在Activity中放置一个 Fragment,那么在FlutterActivity中使用一个FlutterFragment更有意义。Fragment支持库为应用程序增加了100k二进制大小,而全Flutter应用程序不需要二进制命中。因此,得出的结论是,Flutter必须基于AOSP(Android Open Source Project: Android 开源项目)Activity 提供FlutterActivity,并为应用程序添加开发人员提供独立的 FlutterFragment
    • 大概意思就是FlutterActivity和FlutterFragment是相互独立的,所以需要一个代理委托类去处理它们之间相同的逻辑
成员变量
  // Host实现类对象即FlutterActivity
  @NonNull private Host host;
  // Flutter执行环境
  @Nullable private FlutterEngine flutterEngine;
  // 闪屏View,直到FlutterView显示第一帧
  @Nullable private FlutterSplashView flutterSplashView;
  // Flutter UI
  @Nullable private FlutterView flutterView;
  // 安卓平台的插件实现
  @Nullable private PlatformPlugin platformPlugin;
  // 是否是Host实现类提供FlutterEngine
  private boolean isFlutterEngineFromHost;
构造函数
 FlutterActivityAndFragmentDelegate(@NonNull Host host) {
    this.host = host;
  }

在FlutterActivity的onCreate方法里里实例化FlutterActivityAndFragmentDelegate并传递当前FA上下文对象,

然后调用onAttach、onActivityCreated、onCreateView,下面我们对这三个方法进行逐一分析

 // FlutterActivity  删除部分源码
 @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onActivityCreated(savedInstanceState);
    setContentView(createFlutterView());
  }
  
  @NonNull
  private View createFlutterView() {
    return delegate.onCreateView(
        null /* inflater */, null /* container */, null /* savedInstanceState */);
  }
onAttach
 void onAttach(@NonNull Context context) {
    ensureAlive();
    if (flutterEngine == null) {
    	// 1
      setupFlutterEngine();
    }
    // 2
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
    // 3 
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine
          .getActivityControlSurface()
          .attachToActivity(host.getActivity(), host.getLifecycle());
    }
    // 4 
    host.configureFlutterEngine(flutterEngine);
  }
  1. 实例化FlutterEngine

    	void setupFlutterEngine() {
        String cachedEngineId = host.getCachedEngineId();
        if (cachedEngineId != null) {
          flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
          isFlutterEngineFromHost = true;
          if (flutterEngine == null) {
            throw new IllegalStateException(
                "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
                    + cachedEngineId
                    + "'");
          }
          return;
        }
        flutterEngine = host.provideFlutterEngine(host.getContext());
        if (flutterEngine != null) {
          isFlutterEngineFromHost = true;
          return;
        }
        flutterEngine =
            new FlutterEngine(
                host.getContext(),
                host.getFlutterShellArgs().toArray(),
                /*automaticallyRegisterPlugins=*/ false,
                /*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
        isFlutterEngineFromHost = false;
      }
    

    首先会判断是否有缓存的EngineId,如果有,去FlutterEngineCache缓存区去取到并实例化,

    如果没有,会去判断Host实现类(FlutterActivity是否有提供Engine),这个的话目前版本是返回null,

    	// FlutterActivity
    	@Nullable
      @Override
      public FlutterEngine provideFlutterEngine(@NonNull Context context) {
        // No-op. Hook for subclasses.
        return null;
      }
    

    最后就会直接去实例化一个新的Engine,然后设置isFlutterEngineFromHost 为false,说明此Engine非Host实现类提供

    我们大概看下FlutterEngine的构造函数

    public FlutterEngine(
        @NonNull Context context,
        @NonNull FlutterLoader flutterLoader,
        @NonNull FlutterJNI flutterJNI,
        @NonNull PlatformViewsController platformViewsController,
        @Nullable String[] dartVmArgs,
        boolean automaticallyRegisterPlugins,
        boolean waitForRestorationData) {
      this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
      this.dartExecutor.onAttachedToJNI();
    
      accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
      keyEventChannel = new KeyEventChannel(dartExecutor);
      lifecycleChannel = new LifecycleChannel(dartExecutor);
      localizationChannel = new LocalizationChannel(dartExecutor);
      mouseCursorChannel = new MouseCursorChannel(dartExecutor);
      navigationChannel = new NavigationChannel(dartExecutor);
      platformChannel = new PlatformChannel(dartExecutor);
      restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData);
      settingsChannel = new SettingsChannel(dartExecutor);
      systemChannel = new SystemChannel(dartExecutor);
      textInputChannel = new TextInputChannel(dartExecutor);
    
      this.localizationPlugin = new LocalizationPlugin(context, localizationChannel);
    
      this.flutterJNI = flutterJNI;
      flutterLoader.startInitialization(context.getApplicationContext());
      flutterLoader.ensureInitializationComplete(context, dartVmArgs);
    
      flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
      flutterJNI.setPlatformViewsController(platformViewsController);
      flutterJNI.setLocalizationPlugin(localizationPlugin);
      attachToJni();
    
      // TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if
      // possible.
      this.renderer = new FlutterRenderer(flutterJNI);
    
      this.platformViewsController = platformViewsController;
      this.platformViewsController.onAttachedToJNI();
    
      this.pluginRegistry =
          new FlutterEnginePluginRegistry(context.getApplicationContext(), this, flutterLoader);
    
      if (automaticallyRegisterPlugins) {
        registerPlugins();
      }
    }
    
    • dartExecutor实例化
    • 一些系统channel初始化
    • FlutterJNI、PlatformViewsController、FlutterRender、FlutterLoader初始化
    • 实例化FlutterEnginePluginRegistry插件注册表

    FlutterRender 就是与提供的RenderSurface协同工作,将Flutter 像素绘制到Android View层次结构中。FlutterRender管理渲染纹理,并通过JNI将一些Java调用转发到本地 Flutter代码

    FlutterLoader就是在应用程序APK中查找Flutter资源,并加载Flutter的本机库

    这两个大家可以自己去看一下,就不多提及了

  2. 实例化PlatformPlugin

     // FlutterActivity
     @Nullable
      @Override
      public PlatformPlugin providePlatformPlugin(
          @Nullable Activity activity, @NonNull FlutterEngine flutterEngine) {
        if (activity != null) {
          return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel());
        } else {
          return null;
        }
      }
    

    可以看到FlutterActivity重写这个方法并实例化一个新的PlatformPlugin

    这里有一个注意点:如果FlutterFragment 连接到一个新的Activity上的时候,都要重新去创建一个PlatformPlugin

    PlatformPlugin的话大家可以自己去看,就是平台提供的原生插件,如:状态栏操作、剪贴板等Plugin

  3. attachToActivity

     // FlutterActivity
     @Override
      public boolean shouldAttachEngineToActivity() {
        return true;
      }
    

    这里话默认是返回true,建立Activity和Engine的关联关系

    attachToActivity方法的作用就是通知当前连接到FlutterEngine的所有插件,将它们附加到Activity

     //  FlutterEnginePluginRegistry 插件注册表
     @Override
      public void attachToActivity(@NonNull Activity activity, @NonNull Lifecycle lifecycle) {
        detachFromAndroidComponent();
        this.activity = activity;
        this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity, lifecycle);
        flutterEngine
            .getPlatformViewsController()
            .attach(activity, flutterEngine.getRenderer(), flutterEngine.getDartExecutor());
        for (ActivityAware activityAware : activityAwarePlugins.values()) {
          if (isWaitingForActivityReattachment) {
            activityAware.onReattachedToActivityForConfigChanges(activityPluginBinding);
          } else {
            activityAware.onAttachedToActivity(activityPluginBinding);
          }
        }
        isWaitingForActivityReattachment = false;
      }
    

    FlutterEnginePluginRegistry这个类大家有兴趣可以看下,其实就是一个Engine插件注册表,这里不做过多分析

    它是在FlutterEngine的构造函数里进行实例化的

  4. configureFlutterEngine

    // FlutterActivity
    @Override
      public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        registerPlugins(flutterEngine);
      }
    

    注册pubspec.yaml里的原生插件,所以像上篇文章所说,新版本帮我们进行了自动注册。

onActivityCreated
	void onActivityCreated(@Nullable Bundle bundle) {
    Bundle pluginState = null;
    byte[] frameworkState = null;
    if (bundle != null) {
      pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
      frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
    }
    if (host.shouldRestoreAndSaveState()) {
      flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
    }
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
    }
  }

这个我们不做过多分析,就是为插件和Activity提供恢复数据

onCreateView
View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ensureAlive();
    if (host.getRenderMode() == RenderMode.surface) {
      FlutterSurfaceView flutterSurfaceView =
          new FlutterSurfaceView(
              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
      host.onFlutterSurfaceViewCreated(flutterSurfaceView);
      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    } else {
      FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
      host.onFlutterTextureViewCreated(flutterTextureView);
      flutterView = new FlutterView(host.getActivity(), flutterTextureView);
    }
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      flutterSplashView.setId(486947586);
    }
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
    flutterView.attachToFlutterEngine(flutterEngine);
    return flutterSplashView;
  }
  1. 首先会判断渲染模式

    	// FlutterActivity
    	@NonNull
      @Override
      public RenderMode getRenderMode() {
        return getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
      }
      
       @NonNull
      protected BackgroundMode getBackgroundMode() {
        if (getIntent().hasExtra(EXTRA_BACKGROUND_MODE)) {
          return BackgroundMode.valueOf(getIntent().getStringExtra(EXTRA_BACKGROUND_MODE));
        } else {
          return BackgroundMode.opaque;
        }
      }
    

    框架提供了两种渲染模式: RenderMode.surface , RenderMode.texture,Flutter框架默认使用Surface进行渲染

  2. 然后会实例化一个非透明的FlutterSurfaceView,并设置onFlutterSurfaceViewCreated回调

    	public enum BackgroundMode {
        /** Indicates a FlutterActivity with an opaque background. This is the default. */
        opaque,
        /** Indicates a FlutterActivity with a transparent background. */
        transparent
      }
    
  3. 然后接着创建拥有FlutterSurfaceView的FlutterView,上面有提到这个FlutterView就是用来在安卓设备上显示Flutter UI

     flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    

    TextureView也是一样,不去分析

  4. 然后会添加一个绘制第一帧的监听器

     flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
    
  5. 接着会创建一个FlutterSplashView,然后调用displayFlutterViewWithSplash 方法在FlutterView上显示闪屏界面,直到绘制了第一帧

      flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
      
      //FlutterActivity
      @Nullable
      @Override
      public SplashScreen provideSplashScreen() {
        Drawable manifestSplashDrawable = getSplashScreenFromManifest();
        if (manifestSplashDrawable != null) {
          return new DrawableSplashScreen(manifestSplashDrawable);
        } else {
          return null;
        }
      }
    
      @Nullable
      @SuppressWarnings("deprecation")
      private Drawable getSplashScreenFromManifest() {
        try {
          ActivityInfo activityInfo =
              getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
          Bundle metadata = activityInfo.metaData;
          int splashScreenId = metadata != null ? metadata.getInt(SPLASH_SCREEN_META_DATA_KEY) : 0;
          return splashScreenId != 0
              ? Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
                  ? getResources().getDrawable(splashScreenId, getTheme())
                  : getResources().getDrawable(splashScreenId)
              : null;
        } catch (PackageManager.NameNotFoundException e) {
          // This is never expected to happen.
          return null;
        }
      }
      
      // FlutterActivityLaunchConfigs
    	static final String SPLASH_SCREEN_META_DATA_KEY ="io.flutter.embedding.android.SplashScreenDrawable";
    	
    	// AndroidManifest.xml
    			<meta-data
                    android:name="io.flutter.embedding.android.SplashScreenDrawable"
                    android:resource="@drawable/launch_background" />
    

    可以看到FlutterActivity重写provideSplashScreen,返回我们在AndroidManifest.xml设置的闪屏drawable

  6. flutterView.attachToFlutterEngine(flutterEngine);

    然后将此FlutterView连接到给定的 FlutterEngine。此FlutterView将开始呈现给定FlutterEngine绘制的UI。并且这个FlutterView还将开始将交互事件从此FlutterView转发到给定的FlutterEngine例如,用户触摸事件,可访问性事件,键盘事件等

  7. 返回flutterSplashView到FlutterActivity。到此刻为止,FlutterActivityAndFragmentDelegate 的onAttach方法已全部分析完毕

  8. 同时在添加SplashScreenDrawable之后,也能解决安卓启动黑屏的问题—>从MainActivity的setContentView直到收到Flutter绘制第一帧的回调时,才会关闭这个splashView

接下来我们分析onStart方法

onStart
 // FlutterActivity
 @Override
  protected void onStart() {
    super.onStart();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
    delegate.onStart();
  }
// FlutterActivityAndFragmentDelegate
void onStart() {
    Log.v(TAG, "onStart()");
    ensureAlive();
    doInitialFlutterViewRun();
  }

可以看到FlutterActivity.onStart调用了FlutterActivityAndFragmentDelegate.onStart方法,然后其调用了doInitialFlutterViewRun方法

这个方法的话就是首次开始在FlutterView中运行Dart

private void doInitialFlutterViewRun() {
		// 1 
    if (host.getCachedEngineId() != null) {
      return;
    }
    if (flutterEngine.getDartExecutor().isExecutingDart()) {
      return;
    }
    
    // 2 
    if (host.getInitialRoute() != null) {
      flutterEngine.getNavigationChannel().setInitialRoute(host.getInitialRoute());
    }
    
    // 3
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            host.getAppBundlePath(), host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }
  1. 首先判断engine缓存id是否为空,具体实现在FlutterActivity

    	// FlutterActivity
    	@Override
      @Nullable
      public String getCachedEngineId() {
        return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
      }
    

    这里说明一下,Flutter框架是每次都去实例化一个新的FlutterEngine,上面有提到,所以这里恒为null。具体使用场景以后再说

    然后会判断Dart是否执行

  2. 这里会设置执行 Dart代码之前接收Flutter应用程序的初始路径,以确保初始路径能够及时应用。

    //FlutterActivity
    @NonNull
      public String getInitialRoute() {
        if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
          return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
        }
    
        try {
          ActivityInfo activityInfo =
              getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
          Bundle metadata = activityInfo.metaData;
          String desiredInitialRoute =
              metadata != null ? metadata.getString(INITIAL_ROUTE_META_DATA_KEY) : null;
          return desiredInitialRoute != null ? desiredInitialRoute : DEFAULT_INITIAL_ROUTE;
        } catch (PackageManager.NameNotFoundException e) {
          return DEFAULT_INITIAL_ROUTE;
        }
      }
    

    设置初始化路径可以通过Intent,还可以在Android manifest.定义指定INITIAL_ROUTE_META_DATA_KEY

    这里我们不多聊,这个最后返回的是DEFAULT_INITIAL_ROUTE,默认路径

    //FlutterActivityLaunchConfigs
    static final String DEFAULT_INITIAL_ROUTE = "/";
    
  3. 然后配置Dart代码执行入口点并且去执行它

    host.getAppBundlePath返回的是默认路径

    private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
    

    host.getDartEntrypointFunctionName()返回的是也是默认启动方法名,

    static final String DEFAULT_DART_ENTRYPOINT = "main";
    

    就是我们main.dart里的这个main方法

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    //DartExecutor 配置,引导并开始执行Dart代码。
    
    public void executeDartEntrypoint(@NonNull DartEntrypoint dartEntrypoint) {
        if (isApplicationRunning) {
          Log.w(TAG, "Attempted to run a DartExecutor that is already running.");
          return;
        }
    
        Log.v(TAG, "Executing Dart entrypoint: " + dartEntrypoint);
    
        flutterJNI.runBundleAndSnapshotFromLibrary(
            dartEntrypoint.pathToBundle, dartEntrypoint.dartEntrypointFunctionName, null, assetManager);
    
        isApplicationRunning = true;
      }
    

    可以看到这里设置 isApplicationRunning = true,代表程序正在运行,

    //DartExecutor 
    public boolean isExecutingDart() {
        return isApplicationRunning;
      }
    

    判断是否正在执行dart代码也是通过此变量

  4. FlutterJNI类是Flutter嵌入的Java代码和Flutter引擎的C / C ++代码之间的接口。这块大家自己去看吧

  5. 到此刻,一个flutter程序就正常运行起来了,接着就是执行dart代码和我们自己的业务逻辑

接下来,我们看下生命周期Channel LifecycleChannel

 void onResume() {
    Log.v(TAG, "onResume()");
    ensureAlive();
    flutterEngine.getLifecycleChannel().appIsResumed();
  }

它主要是将Android生命周期事件发送到Flutter,onPause、onStop、onDetach也做了同样处理

FlutterActivity onDestroy
  @Override
  protected void onDestroy() {
    super.onDestroy();
    delegate.onDestroyView();
    delegate.onDetach();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
  }

这里主要是做一些清除引用,销毁资源的一些操作。大家可以自行阅读源码

总结

通过这篇文章我们可以大概的看到

  • FlutterActivityAndFragmentDelegate是如何去代理FlutterActivity的工作
  • FlutterActivityAndFragmentDelegate是如何将FlutterEngine和FlutterActivity连接在一起,并执行dart代码,启动应用程序
  • FlutterRender、FlutterJNI、FlutterLoader大家可以自己去结合源码看一下,基本的启动流程就是这样

下篇文章我会通过一个Android 项目嵌入Flutter Module的混合工程来让大家更直观的看到Flutter在Android上到底是如何去展示的

前言

上篇文章Flutter Android启动源码分析(一)中主要对FlutterApplicaiton和FlutterActivity进行了分析,在FlutterActivity源码部分中FlutterActivityAndFragmentDelegate这个类一直被提到,这篇文章我们就主要分析一下它做了哪些事情

Flutter Android启动源码分析(一)

FlutterActivityAndFragmentDelegate

  • 作用
    • FlutterActivity和FlutterFragment之间相同的Flutter逻辑的委托
  • 为什么要用这个类
    • 假设可以在Activity中放置一个 Fragment,那么在FlutterActivity中使用一个FlutterFragment更有意义。Fragment支持库为应用程序增加了100k二进制大小,而全Flutter应用程序不需要二进制命中。因此,得出的结论是,Flutter必须基于AOSP(Android Open Source Project: Android 开源项目)Activity 提供FlutterActivity,并为应用程序添加开发人员提供独立的 FlutterFragment
    • 大概意思就是FlutterActivity和FlutterFragment是相互独立的,所以需要一个代理委托类去处理它们之间相同的逻辑
成员变量
  // Host实现类对象即FlutterActivity
  @NonNull private Host host;
  // Flutter执行环境
  @Nullable private FlutterEngine flutterEngine;
  // 闪屏View,直到FlutterView显示第一帧
  @Nullable private FlutterSplashView flutterSplashView;
  // Flutter UI
  @Nullable private FlutterView flutterView;
  // 安卓平台的插件实现
  @Nullable private PlatformPlugin platformPlugin;
  // 是否是Host实现类提供FlutterEngine
  private boolean isFlutterEngineFromHost;
构造函数
 FlutterActivityAndFragmentDelegate(@NonNull Host host) {
    this.host = host;
  }

在FlutterActivity的onCreate方法里里实例化FlutterActivityAndFragmentDelegate并传递当前FA上下文对象,

然后调用onAttach、onActivityCreated、onCreateView,下面我们对这三个方法进行逐一分析

 // FlutterActivity  删除部分源码
 @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onActivityCreated(savedInstanceState);
    setContentView(createFlutterView());
  }
  
  @NonNull
  private View createFlutterView() {
    return delegate.onCreateView(
        null /* inflater */, null /* container */, null /* savedInstanceState */);
  }
onAttach
 void onAttach(@NonNull Context context) {
    ensureAlive();
    if (flutterEngine == null) {
    	// 1
      setupFlutterEngine();
    }
    // 2
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
    // 3 
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine
          .getActivityControlSurface()
          .attachToActivity(host.getActivity(), host.getLifecycle());
    }
    // 4 
    host.configureFlutterEngine(flutterEngine);
  }
  1. 实例化FlutterEngine

    	void setupFlutterEngine() {
        String cachedEngineId = host.getCachedEngineId();
        if (cachedEngineId != null) {
          flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
          isFlutterEngineFromHost = true;
          if (flutterEngine == null) {
            throw new IllegalStateException(
                "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
                    + cachedEngineId
                    + "'");
          }
          return;
        }
        flutterEngine = host.provideFlutterEngine(host.getContext());
        if (flutterEngine != null) {
          isFlutterEngineFromHost = true;
          return;
        }
        flutterEngine =
            new FlutterEngine(
                host.getContext(),
                host.getFlutterShellArgs().toArray(),
                /*automaticallyRegisterPlugins=*/ false,
                /*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
        isFlutterEngineFromHost = false;
      }
    

    首先会判断是否有缓存的EngineId,如果有,去FlutterEngineCache缓存区去取到并实例化,

    如果没有,会去判断Host实现类(FlutterActivity是否有提供Engine),这个的话目前版本是返回null,

    	// FlutterActivity
    	@Nullable
      @Override
      public FlutterEngine provideFlutterEngine(@NonNull Context context) {
        // No-op. Hook for subclasses.
        return null;
      }
    

    最后就会直接去实例化一个新的Engine,然后设置isFlutterEngineFromHost 为false,说明此Engine非Host实现类提供

    我们大概看下FlutterEngine的构造函数

    public FlutterEngine(
        @NonNull Context context,
        @NonNull FlutterLoader flutterLoader,
        @NonNull FlutterJNI flutterJNI,
        @NonNull PlatformViewsController platformViewsController,
        @Nullable String[] dartVmArgs,
        boolean automaticallyRegisterPlugins,
        boolean waitForRestorationData) {
      this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
      this.dartExecutor.onAttachedToJNI();
    
      accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
      keyEventChannel = new KeyEventChannel(dartExecutor);
      lifecycleChannel = new LifecycleChannel(dartExecutor);
      localizationChannel = new LocalizationChannel(dartExecutor);
      mouseCursorChannel = new MouseCursorChannel(dartExecutor);
      navigationChannel = new NavigationChannel(dartExecutor);
      platformChannel = new PlatformChannel(dartExecutor);
      restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData);
      settingsChannel = new SettingsChannel(dartExecutor);
      systemChannel = new SystemChannel(dartExecutor);
      textInputChannel = new TextInputChannel(dartExecutor);
    
      this.localizationPlugin = new LocalizationPlugin(context, localizationChannel);
    
      this.flutterJNI = flutterJNI;
      flutterLoader.startInitialization(context.getApplicationContext());
      flutterLoader.ensureInitializationComplete(context, dartVmArgs);
    
      flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
      flutterJNI.setPlatformViewsController(platformViewsController);
      flutterJNI.setLocalizationPlugin(localizationPlugin);
      attachToJni();
    
      // TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if
      // possible.
      this.renderer = new FlutterRenderer(flutterJNI);
    
      this.platformViewsController = platformViewsController;
      this.platformViewsController.onAttachedToJNI();
    
      this.pluginRegistry =
          new FlutterEnginePluginRegistry(context.getApplicationContext(), this, flutterLoader);
    
      if (automaticallyRegisterPlugins) {
        registerPlugins();
      }
    }
    
    • dartExecutor实例化
    • 一些系统channel初始化
    • FlutterJNI、PlatformViewsController、FlutterRender、FlutterLoader初始化
    • 实例化FlutterEnginePluginRegistry插件注册表

    FlutterRender 就是与提供的RenderSurface协同工作,将Flutter 像素绘制到Android View层次结构中。FlutterRender管理渲染纹理,并通过JNI将一些Java调用转发到本地 Flutter代码

    FlutterLoader就是在应用程序APK中查找Flutter资源,并加载Flutter的本机库

    这两个大家可以自己去看一下,就不多提及了

  2. 实例化PlatformPlugin

     // FlutterActivity
     @Nullable
      @Override
      public PlatformPlugin providePlatformPlugin(
          @Nullable Activity activity, @NonNull FlutterEngine flutterEngine) {
        if (activity != null) {
          return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel());
        } else {
          return null;
        }
      }
    

    可以看到FlutterActivity重写这个方法并实例化一个新的PlatformPlugin

    这里有一个注意点:如果FlutterFragment 连接到一个新的Activity上的时候,都要重新去创建一个PlatformPlugin

    PlatformPlugin的话大家可以自己去看,就是平台提供的原生插件,如:状态栏操作、剪贴板等Plugin

  3. attachToActivity

     // FlutterActivity
     @Override
      public boolean shouldAttachEngineToActivity() {
        return true;
      }
    

    这里话默认是返回true,建立Activity和Engine的关联关系

    attachToActivity方法的作用就是通知当前连接到FlutterEngine的所有插件,将它们附加到Activity

     //  FlutterEnginePluginRegistry 插件注册表
     @Override
      public void attachToActivity(@NonNull Activity activity, @NonNull Lifecycle lifecycle) {
        detachFromAndroidComponent();
        this.activity = activity;
        this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity, lifecycle);
        flutterEngine
            .getPlatformViewsController()
            .attach(activity, flutterEngine.getRenderer(), flutterEngine.getDartExecutor());
        for (ActivityAware activityAware : activityAwarePlugins.values()) {
          if (isWaitingForActivityReattachment) {
            activityAware.onReattachedToActivityForConfigChanges(activityPluginBinding);
          } else {
            activityAware.onAttachedToActivity(activityPluginBinding);
          }
        }
        isWaitingForActivityReattachment = false;
      }
    

    FlutterEnginePluginRegistry这个类大家有兴趣可以看下,其实就是一个Engine插件注册表,这里不做过多分析

    它是在FlutterEngine的构造函数里进行实例化的

  4. configureFlutterEngine

    // FlutterActivity
    @Override
      public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        registerPlugins(flutterEngine);
      }
    

    注册pubspec.yaml里的原生插件,所以像上篇文章所说,新版本帮我们进行了自动注册。

onActivityCreated
	void onActivityCreated(@Nullable Bundle bundle) {
    Bundle pluginState = null;
    byte[] frameworkState = null;
    if (bundle != null) {
      pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
      frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
    }
    if (host.shouldRestoreAndSaveState()) {
      flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
    }
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
    }
  }

这个我们不做过多分析,就是为插件和Activity提供恢复数据

onCreateView
View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ensureAlive();
    if (host.getRenderMode() == RenderMode.surface) {
      FlutterSurfaceView flutterSurfaceView =
          new FlutterSurfaceView(
              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
      host.onFlutterSurfaceViewCreated(flutterSurfaceView);
      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    } else {
      FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
      host.onFlutterTextureViewCreated(flutterTextureView);
      flutterView = new FlutterView(host.getActivity(), flutterTextureView);
    }
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      flutterSplashView.setId(486947586);
    }
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
    flutterView.attachToFlutterEngine(flutterEngine);
    return flutterSplashView;
  }
  1. 首先会判断渲染模式

    	// FlutterActivity
    	@NonNull
      @Override
      public RenderMode getRenderMode() {
        return getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
      }
      
       @NonNull
      protected BackgroundMode getBackgroundMode() {
        if (getIntent().hasExtra(EXTRA_BACKGROUND_MODE)) {
          return BackgroundMode.valueOf(getIntent().getStringExtra(EXTRA_BACKGROUND_MODE));
        } else {
          return BackgroundMode.opaque;
        }
      }
    

    框架提供了两种渲染模式: RenderMode.surface , RenderMode.texture,Flutter框架默认使用Surface进行渲染

  2. 然后会实例化一个非透明的FlutterSurfaceView,并设置onFlutterSurfaceViewCreated回调

    	public enum BackgroundMode {
        /** Indicates a FlutterActivity with an opaque background. This is the default. */
        opaque,
        /** Indicates a FlutterActivity with a transparent background. */
        transparent
      }
    
  3. 然后接着创建拥有FlutterSurfaceView的FlutterView,上面有提到这个FlutterView就是用来在安卓设备上显示Flutter UI

     flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    

    TextureView也是一样,不去分析

  4. 然后会添加一个绘制第一帧的监听器

     flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
    
  5. 接着会创建一个FlutterSplashView,然后调用displayFlutterViewWithSplash 方法在FlutterView上显示闪屏界面,直到绘制了第一帧

      flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
      
      //FlutterActivity
      @Nullable
      @Override
      public SplashScreen provideSplashScreen() {
        Drawable manifestSplashDrawable = getSplashScreenFromManifest();
        if (manifestSplashDrawable != null) {
          return new DrawableSplashScreen(manifestSplashDrawable);
        } else {
          return null;
        }
      }
    
      @Nullable
      @SuppressWarnings("deprecation")
      private Drawable getSplashScreenFromManifest() {
        try {
          ActivityInfo activityInfo =
              getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
          Bundle metadata = activityInfo.metaData;
          int splashScreenId = metadata != null ? metadata.getInt(SPLASH_SCREEN_META_DATA_KEY) : 0;
          return splashScreenId != 0
              ? Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
                  ? getResources().getDrawable(splashScreenId, getTheme())
                  : getResources().getDrawable(splashScreenId)
              : null;
        } catch (PackageManager.NameNotFoundException e) {
          // This is never expected to happen.
          return null;
        }
      }
      
      // FlutterActivityLaunchConfigs
    	static final String SPLASH_SCREEN_META_DATA_KEY ="io.flutter.embedding.android.SplashScreenDrawable";
    	
    	// AndroidManifest.xml
    			<meta-data
                    android:name="io.flutter.embedding.android.SplashScreenDrawable"
                    android:resource="@drawable/launch_background" />
    

    可以看到FlutterActivity重写provideSplashScreen,返回我们在AndroidManifest.xml设置的闪屏drawable

  6. flutterView.attachToFlutterEngine(flutterEngine);

    然后将此FlutterView连接到给定的 FlutterEngine。此FlutterView将开始呈现给定FlutterEngine绘制的UI。并且这个FlutterView还将开始将交互事件从此FlutterView转发到给定的FlutterEngine例如,用户触摸事件,可访问性事件,键盘事件等

  7. 返回flutterSplashView到FlutterActivity。到此刻为止,FlutterActivityAndFragmentDelegate 的onAttach方法已全部分析完毕

接下来我们分析onStart方法

onStart
 // FlutterActivity
 @Override
  protected void onStart() {
    super.onStart();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
    delegate.onStart();
  }
// FlutterActivityAndFragmentDelegate
void onStart() {
    Log.v(TAG, "onStart()");
    ensureAlive();
    doInitialFlutterViewRun();
  }

可以看到FlutterActivity.onStart调用了FlutterActivityAndFragmentDelegate.onStart方法,然后其调用了doInitialFlutterViewRun方法

这个方法的话就是首次开始在FlutterView中运行Dart

private void doInitialFlutterViewRun() {
		// 1 
    if (host.getCachedEngineId() != null) {
      return;
    }
    if (flutterEngine.getDartExecutor().isExecutingDart()) {
      return;
    }
    
    // 2 
    if (host.getInitialRoute() != null) {
      flutterEngine.getNavigationChannel().setInitialRoute(host.getInitialRoute());
    }
    
    // 3
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            host.getAppBundlePath(), host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }
  1. 首先判断engine缓存id是否为空,具体实现在FlutterActivity

    	// FlutterActivity
    	@Override
      @Nullable
      public String getCachedEngineId() {
        return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
      }
    

    这里说明一下,Flutter框架是每次都去实例化一个新的FlutterEngine,上面有提到,所以这里恒为null。具体使用场景以后再说

    然后会判断Dart是否执行

  2. 这里会设置执行 Dart代码之前接收Flutter应用程序的初始路径,以确保初始路径能够及时应用。

    //FlutterActivity
    @NonNull
      public String getInitialRoute() {
        if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
          return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
        }
    
        try {
          ActivityInfo activityInfo =
              getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
          Bundle metadata = activityInfo.metaData;
          String desiredInitialRoute =
              metadata != null ? metadata.getString(INITIAL_ROUTE_META_DATA_KEY) : null;
          return desiredInitialRoute != null ? desiredInitialRoute : DEFAULT_INITIAL_ROUTE;
        } catch (PackageManager.NameNotFoundException e) {
          return DEFAULT_INITIAL_ROUTE;
        }
      }
    

    设置初始化路径可以通过Intent,还可以在Android manifest.定义指定INITIAL_ROUTE_META_DATA_KEY

    这里我们不多聊,这个最后返回的是DEFAULT_INITIAL_ROUTE,默认路径

    //FlutterActivityLaunchConfigs
    static final String DEFAULT_INITIAL_ROUTE = "/";
    
  3. 然后配置Dart代码执行入口点并且去执行它

    host.getAppBundlePath返回的是默认路径

    private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
    

    host.getDartEntrypointFunctionName()返回的是也是默认启动方法名,

    static final String DEFAULT_DART_ENTRYPOINT = "main";
    

    就是我们main.dart里的这个main方法

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    //DartExecutor 配置,引导并开始执行Dart代码。
    
    public void executeDartEntrypoint(@NonNull DartEntrypoint dartEntrypoint) {
        if (isApplicationRunning) {
          Log.w(TAG, "Attempted to run a DartExecutor that is already running.");
          return;
        }
    
        Log.v(TAG, "Executing Dart entrypoint: " + dartEntrypoint);
    
        flutterJNI.runBundleAndSnapshotFromLibrary(
            dartEntrypoint.pathToBundle, dartEntrypoint.dartEntrypointFunctionName, null, assetManager);
    
        isApplicationRunning = true;
      }
    

    可以看到这里设置 isApplicationRunning = true,代表程序正在运行,

    //DartExecutor 
    public boolean isExecutingDart() {
        return isApplicationRunning;
      }
    

    判断是否正在执行dart代码也是通过此变量

  4. FlutterJNI类是Flutter嵌入的Java代码和Flutter引擎的C / C ++代码之间的接口。这块大家自己去看吧

  5. 到此刻,一个flutter程序就正常运行起来了,接着就是执行dart代码和我们自己的业务逻辑

接下来,我们看下生命周期Channel LifecycleChannel

 void onResume() {
    Log.v(TAG, "onResume()");
    ensureAlive();
    flutterEngine.getLifecycleChannel().appIsResumed();
  }

它主要是将Android生命周期事件发送到Flutter,onPause、onStop、onDetach也做了同样处理

FlutterActivity onDestroy
  @Override
  protected void onDestroy() {
    super.onDestroy();
    delegate.onDestroyView();
    delegate.onDetach();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
  }

这里主要是做一些清除引用,销毁资源的一些操作。大家可以自行阅读源码

总结

通过这篇文章我们可以大概的看到

  • FlutterActivityAndFragmentDelegate是如何去代理FlutterActivity的工作
  • FlutterActivityAndFragmentDelegate是如何将FlutterEngine和FlutterActivity连接在一起,并执行dart代码,启动应用程序
  • FlutterRender、FlutterJNI、FlutterLoader大家可以自己去结合源码看一下,基本的启动流程就是这样
  • 在Android上,Flutter默认是作为一个Activity加载到嵌入器中。视图由FlutterView控制,它根据Flutter内容的构成和z-排序要求,将Flutter内容渲染为视图或纹理。
  • Flutter架构综述

下篇文章我会通过一个Android 项目嵌入Flutter Module的混合工程来让大家更直观的看到Flutter在Android上到底是如何去展示的

本人技术水平有限,太深入的分析就不去涉及了。如有错误,请及时指正。当然也欢迎大家能给我一些指导性意见,我们一起进步
本人技术水平有限,太深入的分析就不去涉及了。如有错误,请及时指正。当然也欢迎大家能给我一些指导性意见,我们一起进步

本文地址:https://blog.csdn.net/fighting_android/article/details/108723708

相关标签: Flutter android