Flutter应用启动流程分析(二)

Flutter应用启动流程分析(二)

看看Flutter页面是怎么展示出来的
MainActivity
在AndroidManifest中的声明


            
            
                
                
            
        

只是声明了一个meta-data,指定是否展示加载画面,也就是应用打开时的等待画面。接着看MainActivity的代码实现

class MainActivity: FlutterActivity() {
     
  override fun onCreate(savedInstanceState: Bundle?) {
     
    super.onCreate(savedInstanceState)
    GeneratedPluginRegistrant.registerWith(this)
  }
}

乖乖,继承了FlutterActivity,复写了onCreate方法就添加了一行代码,看名称貌似是注册了什么,进去瞅瞅,嘟嘟嘟…

/**
 * Generated file. Do not edit.
 */
public final class GeneratedPluginRegistrant {
     
  public static void registerWith(PluginRegistry registry) {
     
    if (alreadyRegisteredWith(registry)) {
     
      return;
    }
  }

  private static boolean alreadyRegisteredWith(PluginRegistry registry) {
     
    final String key = GeneratedPluginRegistrant.class.getCanonicalName();
    if (registry.hasPlugin(key)) {
     
      return true;
    }
    registry.registrarFor(key);
    return false;
  }
}

Flutter应用会默认自动生成GeneratedPluginRegistrant类,负责管理在pubspec文件中依赖插件注册于更新。 调用了PluginRegistry的registrarFor方法进行插件的注册。plugin可以提供与当前原生平台交互的能力。返回去看看FlutterActivity

FlutterActivity
代码不是很多,都贴出来看看吧

/**
 * Base class for activities that use Flutter.
 */
public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory {
     
    private static final String TAG = "FlutterActivity";
    
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);

    // These aliases ensure that the methods we forward to the delegate adhere
    // to relevant interfaces versus just existing in FlutterActivityDelegate.
    private final FlutterActivityEvents eventDelegate = delegate;
    private final FlutterView.Provider viewProvider = delegate;
    private final PluginRegistry pluginRegistry = delegate;

    /**
     * Returns the Flutter view used by this activity; will be null before
     * {@link #onCreate(Bundle)} is called.
     */
    @Override
    public FlutterView getFlutterView() {
     
        return viewProvider.getFlutterView();
    }

    /**
     * Hook for subclasses to customize the creation of the
     * {@code FlutterView}.
     *
     * 

The default implementation returns {@code null}, which will cause the * activity to use a newly instantiated full-screen view.

*/
@Override public FlutterView createFlutterView(Context context) { return null; } /** * Hook for subclasses to customize the creation of the * {@code FlutterNativeView}. * *

The default implementation returns {@code null}, which will cause the * activity to use a newly instantiated native view object.

*/
@Override public FlutterNativeView createFlutterNativeView() { return null; } @Override public boolean retainFlutterNativeView() { return false; } @Override public final boolean hasPlugin(String key) { return pluginRegistry.hasPlugin(key); } @Override public final <T> T valuePublishedByPlugin(String pluginKey) { return pluginRegistry.valuePublishedByPlugin(pluginKey); } @Override public final Registrar registrarFor(String pluginKey) { return pluginRegistry.registrarFor(pluginKey); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eventDelegate.onCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); eventDelegate.onStart(); } @Override protected void onResume() { super.onResume(); eventDelegate.onResume(); } @Override protected void onDestroy() { eventDelegate.onDestroy(); super.onDestroy(); } @Override public void onBackPressed() { if (!eventDelegate.onBackPressed()) { super.onBackPressed(); } } @Override protected void onStop() { eventDelegate.onStop(); super.onStop(); } @Override protected void onPause() { super.onPause(); eventDelegate.onPause(); } @Override protected void onPostResume() { super.onPostResume(); eventDelegate.onPostResume(); } // @Override - added in API level 23 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { eventDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (!eventDelegate.onActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data); } } @Override protected void onNewIntent(Intent intent) { eventDelegate.onNewIntent(intent); } @Override public void onUserLeaveHint() { eventDelegate.onUserLeaveHint(); } @Override public void onTrimMemory(int level) { eventDelegate.onTrimMemory(level); } @Override public void onLowMemory() { eventDelegate.onLowMemory(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); eventDelegate.onConfigurationChanged(newConfig); } }

看代码并没有实现什么具体的功能, 与FlutterActivityDelegate之间就一个代理模式的实现。继承了Activity并实现了FlutterView.Provider、PluginRegistry、ViewFactory三个接口,内部有一个FlutterActivityDelegate对象,也是最终干活的苦力,其他的三个成员变量也都被设置为了delegate对象。这样实现我们也可以不用继承FlutterActivity写自己的Activity依样画葫芦的把FlutterActivityDelegate代理类挪过来就可以了,哈哈哈…下面我们看看FlutterActivity实现的这几个接口都是什么鬼:

FlutterView.Provider

 /**
     * Interface for those objects that maintain and expose a reference to a
     * {@code FlutterView} (such as a full-screen Flutter activity).
     *
     * 

* This indirection is provided to support applications that use an activity * other than {@link io.flutter.app.FlutterActivity} (e.g. Android v4 support * library's {@code FragmentActivity}). It allows Flutter plugins to deal in * this interface and not require that the activity be a subclass of * {@code FlutterActivity}. *

*/
public interface Provider { /** * Returns a reference to the Flutter view maintained by this object. This may * be {@code null}. */ FlutterView getFlutterView(); }

FlutterView的内部定义的接口,返回一个FlutterView,FlutterView是负责展示Dart UI的容器。

PluginRegistry
注册用于原生平台交互的插件。

public interface PluginRegistry {
     
    Registrar registrarFor(String pluginKey);
    boolean hasPlugin(String pluginKey);
    <T> T valuePublishedByPlugin(String pluginKey);

    interface Registrar {
     
        Activity activity();
        Context context();
        Context activeContext();
        BinaryMessenger messenger();
        TextureRegistry textures();
        PlatformViewRegistry platformViewRegistry();
        FlutterView view();
        String lookupKeyForAsset(String asset);
        String lookupKeyForAsset(String asset, String packageName);
        Registrar publish(Object value);
        Registrar addRequestPermissionsResultListener(RequestPermissionsResultListener listener);
        Registrar addActivityResultListener(ActivityResultListener listener);
        Registrar addNewIntentListener(NewIntentListener listener);
        Registrar addUserLeaveHintListener(UserLeaveHintListener listener);
        Registrar addViewDestroyListener(ViewDestroyListener listener);
    }
    interface RequestPermissionsResultListener {
     
        boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
    }
    interface ActivityResultListener {
     
        boolean onActivityResult(int requestCode, int resultCode, Intent data);
    }
    interface NewIntentListener {
     
        boolean onNewIntent(Intent intent);
    }
    interface UserLeaveHintListener {
     
        void onUserLeaveHint();
    }
    interface ViewDestroyListener {
     
        boolean onViewDestroy(FlutterNativeView view);
    }
    interface PluginRegistrantCallback {
     
        void registerWith(PluginRegistry registry);
    }
}

内部有7个接口,现在只关注FlutterActivity所要实现的三个方法:
registrarFor:注册插件并返回这个插件的Registrar;
hasPlugin:指定的插件名称是否已经存在;
valuePublishedByPlugin:从已注册的插件集合中获取指定的插件。

ViewFactory

    /**
     * Specifies the mechanism by which Flutter views are created during the
     * operation of a {@code FlutterActivityDelegate}.
     *
     * 

A delegate's view factory will be consulted during * {@link #onCreate(Bundle)}. If it returns {@code null}, then the delegate * will fall back to instantiating a new full-screen {@code FlutterView}.

* *

A delegate's native view factory will be consulted during * {@link #onCreate(Bundle)}. If it returns {@code null}, then the delegate * will fall back to instantiating a new {@code FlutterNativeView}. This is * useful for applications to override to reuse the FlutterNativeView held * e.g. by a pre-existing background service.

*/
public interface ViewFactory { FlutterView createFlutterView(Context context); FlutterNativeView createFlutterNativeView(); /** * Hook for subclasses to indicate that the {@code FlutterNativeView} * returned by {@link #createFlutterNativeView()} should not be destroyed * when this activity is destroyed. */ boolean retainFlutterNativeView(); }

FlutterActivityDelegate类中定义的接口,用来创建FlutterView和FlutterNativeView的,最后一个方法是用于控制是否在页面销毁时同步销毁FlutterNativeView。这三个方法在FlutterActivity的实现中均是返回的默认值。

    private final FlutterActivityEvents eventDelegate = delegate;
    private final FlutterView.Provider viewProvider = delegate;
    private final PluginRegistry pluginRegistry = delegate;

三个成员变量实际上都指向了delegate,最终FlutterActivity中所有的调用都会调用到FlutterActivityDelegate中。

FlutterActivityDelegate
呀!现在找到真正干事情的老实人了,我们来简单看一下他的属性和构造方法:

public final class FlutterActivityDelegate
        implements FlutterActivityEvents,
                   FlutterView.Provider,
                   PluginRegistry {
     
   	private final Activity activity;
    private final ViewFactory viewFactory;
    private FlutterView flutterView;
    private View launchView;
    
 	public FlutterActivityDelegate(Activity activity, ViewFactory viewFactory) {
     
        this.activity = Preconditions.checkNotNull(activity);
        this.viewFactory = Preconditions.checkNotNull(viewFactory);
    }
}       

viewFactory:这个也就是FlutterActivity,创建FlutterActivityDelegate时传入的。
flutterView:当前Activity中所要显示的View。
launchView:加载Flutter时等待界面,这个View会根据在AndroidManifest中的配置来控制是否展示。
与FlutterActivity不同的是它实现了FlutterActivityEvents:

public interface FlutterActivityEvents
        extends ComponentCallbacks2,
                ActivityResultListener,
                RequestPermissionsResultListener {
     
    /**
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    void onCreate(Bundle savedInstanceState);

    /**
     * @see android.app.Activity#onNewIntent(Intent)
     */
    void onNewIntent(Intent intent);

    /**
     * @see android.app.Activity#onPause()
     */
    void onPause();

    /**
     * @see android.app.Activity#onStart()
     */
    void onStart();

    /**
     * @see android.app.Activity#onResume()
     */
    void onResume();

    /**
     * @see android.app.Activity#onPostResume()
     */
    void onPostResume();

    /**
     * @see android.app.Activity#onDestroy()
     */
    void onDestroy();

    /**
     * @see android.app.Activity#onStop()
     */
    void onStop();

    /**
     * Invoked when the activity has detected the user's press of the back key.
     *
     * @return {@code true} if the listener handled the event; {@code false}
     *     to let the activity continue with its default back button handling.
     * @see android.app.Activity#onBackPressed()
     */
    boolean onBackPressed();

    /**
     * @see android.app.Activity#onUserLeaveHint()
     */
    void onUserLeaveHint();
}

FlutterActivityEvents定义了与Activity生命周期和一些特定交互相关的方法,便于实现代理模式。

回到FlutterActivityDelegate中,在FlutterActivity创建是首先会走onCreate方法,因FlutterActivityDelegate是FlutterActivity的代理实现,我们定位到这里

   @Override
    public void onCreate(Bundle savedInstanceState) {
     
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
     
            Window window = activity.getWindow();
            window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(0x40000000);
            window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
        }

        String[] args = getArgsFromIntent(activity.getIntent());
        FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);

        flutterView = viewFactory.createFlutterView(activity);
        if (flutterView == null) {
     
            FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
            flutterView = new FlutterView(activity, null, nativeView);
            flutterView.setLayoutParams(matchParent);
            activity.setContentView(flutterView);
            launchView = createLaunchView();
            if (launchView != null) {
     
                addLaunchView();
            }
        }

        if (loadIntent(activity.getIntent())) {
     
            return;
        }

        String appBundlePath = FlutterMain.findAppBundlePath();
        if (appBundlePath != null) {
     
            runBundle(appBundlePath);
        }
    }

onCreate方法做了以下事情:
1、根据sdk版本设置状态条的样式;
2、确认Flutter engine初始化,没有,初始化Flutter engine;
3、创建FlutterView;
4、添加FlutterView到页面中(展示Dart UI);
5、创建launchView;
6、launchView不为null,添加到页面中,在FlutterView渲染完成第一帧时移除;
7、加载Dart页面

step 2 初始化Flutter Engine:FlutterMain ensureInitializationComplete方法最终调用了FlutterLoader的ensureInitializationComplete方法

public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
     
        if (initialized) {
     
            return;
        }
        if (Looper.myLooper() != Looper.getMainLooper()) {
     
          throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
        }
        if (settings == null) {
     
          throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
        }
        try {
     
            if (resourceExtractor != null) {
     
                resourceExtractor.waitForCompletion();
            }

            List<String> shellArgs = new ArrayList<>();
            shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");

            ApplicationInfo applicationInfo = getApplicationInfo(applicationContext);
            shellArgs.add("--icu-native-lib-path=" + applicationInfo.nativeLibraryDir + File.separator + DEFAULT_LIBRARY);

            if (args != null) {
     
                Collections.addAll(shellArgs, args);
            }

            String kernelPath = null;
            if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
     
                String snapshotAssetPath = PathUtils.getDataDirectory(applicationContext) + File.separator + flutterAssetsDir;
                kernelPath = snapshotAssetPath + File.separator + DEFAULT_KERNEL_BLOB;
                shellArgs.add("--" + SNAPSHOT_ASSET_PATH_KEY + "=" + snapshotAssetPath);
                shellArgs.add("--" + VM_SNAPSHOT_DATA_KEY + "=" + vmSnapshotData);
                shellArgs.add("--" + ISOLATE_SNAPSHOT_DATA_KEY + "=" + isolateSnapshotData);
            } else {
     
                shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + aotSharedLibraryName);

                // Most devices can load the AOT shared library based on the library name
                // with no directory path.  Provide a fully qualified path to the library
                // as a workaround for devices where that fails.
                shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + applicationInfo.nativeLibraryDir + File.separator + aotSharedLibraryName);
            }

            shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
            if (settings.getLogTag() != null) {
     
                shellArgs.add("--log-tag=" + settings.getLogTag());
            }

            String appStoragePath = PathUtils.getFilesDir(applicationContext);
            String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
            FlutterJNI.nativeInit(applicationContext, shellArgs.toArray(new String[0]),
                kernelPath, appStoragePath, engineCachesPath);

            initialized = true;
        } catch (Exception e) {
     
            Log.e(TAG, "Flutter initialization failed.", e);
            throw new RuntimeException(e);
        }
    }

确保Flutter已经初始化完成,前面介绍打开应用时在Debug模式下Flutter会异步进行资源解压缩操作,resourceExtractor.waitForCompletion()保证前面的异步任务执行完毕才能往下执行。当任务完成后,配置一些参数调用FlutterJNI.nativeInit(applicationContext, shellArgs.toArray(new String[0]),
kernelPath, appStoragePath, engineCachesPath)Native方法来完成C++层的Flutter Engine的初始化。上面代码看到在DEBUG、JIT_RELEASE和RELEASE配置参数不同,我们先只关注RELEASE模式,配置了AOT编译模式下需要的参数:
1、也就是flutter应用编译生成的so库名称(这个是可在Manifest中配置的,默认名称为libapp.so);
2、还有so库所在的绝对路径,便于底层engine加载。
再就是向底层engine传入了三个应用路径:
kernelPath :在RELEASE下这个路径 为null;
appStoragePath:/data/user/0/package/files
engineCachesPath:/data/user/0/package/code_cache

step 3、4 创建FlutterView

   flutterView = viewFactory.createFlutterView(activity);
        if (flutterView == null) {
     
            FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
            flutterView = new FlutterView(activity, null, nativeView);
            flutterView.setLayoutParams(matchParent);
            activity.setContentView(flutterView);
            launchView = createLaunchView();
            if (launchView != null) {
     
                addLaunchView();
            }
        }

FlutterView为Dart UI的跟布局,会优先从ViewFactory的createFlutterView方法中获取,这里的viewFactory就是FlutterActivity,方法没有实现默认返回null,所以一定会进入下面的判断,在下面代码中也是会调用viewFactory.createFlutterNativeView优先获取FlutterNativeView,同样也是返回了null,接着new了个FlutterView并设置为全屏显示添加到Activity中。
看看FlutterView的创建:卧槽进去了一下比较复杂些,先略过后面在单个分析,我们现在只要知道它继承自SurfaceView并实现了BinaryMessenger接口(原生平台与Flutter通讯的消息)和TextureRegistry接口(待了解)。好吧我们回来接着往下看。

step 5 创建launchView
默认会创建一个launchView用于在加载Flutter页面时展示的等待画面,会获取当前Activity配置的WindowBackground Drawable资源,为null则不创建。

 private View createLaunchView() {
     
        if (!showSplashScreenUntilFirstFrame()) {
     
            return null;
        }
        final Drawable launchScreenDrawable = getLaunchScreenDrawableFromActivityTheme();
        if (launchScreenDrawable == null) {
     
            return null;
        }
        final View view = new View(activity);
        view.setLayoutParams(matchParent);
        view.setBackground(launchScreenDrawable);
        return view;
    }
    private Drawable getLaunchScreenDrawableFromActivityTheme() {
     
        TypedValue typedValue = new TypedValue();
        if (!activity.getTheme().resolveAttribute(
            android.R.attr.windowBackground,
            typedValue,
            true)) {
     
            return null;
        }
        if (typedValue.resourceId == 0) {
     
            return null;
        }
        try {
     
            return activity.getResources().getDrawable(typedValue.resourceId);
        } catch (NotFoundException e) {
     
            Log.e(TAG, "Referenced launch screen windowBackground resource does not exist");
            return null;
        }
    }

step 6 添加launchView
在以上执行创建launchView成功后会将launchView添加至Activity中,同样也是设置为全屏,这时launchView会覆盖在FlutterView的上层,这样在加载Flutter时看到的是launchView。

 private void addLaunchView() {
     
        if (launchView == null) {
     
            return;
        }

        activity.addContentView(launchView, matchParent);
        flutterView.addFirstFrameListener(new FlutterView.FirstFrameListener() {
     
            @Override
            public void onFirstFrame() {
     
                FlutterActivityDelegate.this.launchView.animate()
                    .alpha(0f)
                    // Use Android's default animation duration.
                    .setListener(new AnimatorListenerAdapter() {
     
                        @Override
                        public void onAnimationEnd(Animator animation) {
     
                            // Views added to an Activity's addContentView is always added to its
                            // root FrameLayout.
                            ((ViewGroup) FlutterActivityDelegate.this.launchView.getParent())
                                .removeView(FlutterActivityDelegate.this.launchView);
                            FlutterActivityDelegate.this.launchView = null;
                        }
                    });

                FlutterActivityDelegate.this.flutterView.removeFirstFrameListener(this);
            }
        });

        // Resets the activity theme from the one containing the launch screen in the window
        // background to a blank one since the launch screen is now in a view in front of the
        // FlutterView.
        //
        // We can make this configurable if users want it.
        activity.setTheme(android.R.style.Theme_Black_NoTitleBar);
    }

添加launchView时同时注册了Flutter渲染第一帧的回调,在收到回调后移除launchView让FlutterView得以显示。

step 7 加载Dart页面

  private boolean loadIntent(Intent intent) {
     
        String action = intent.getAction();
        if (Intent.ACTION_RUN.equals(action)) {
     
            String route = intent.getStringExtra("route");
            String appBundlePath = intent.getDataString();
            if (appBundlePath == null) {
     
                // Fall back to the installation path if no bundle path was specified.
                appBundlePath = FlutterMain.findAppBundlePath();
            }
            if (route != null) {
     
                flutterView.setInitialRoute(route);
            }

            runBundle(appBundlePath);
            return true;
        }

        return false;
    }

这里可以指定Flutter Bundle的文件路径和route参数,这个route参数最终在加载Dart UI入口中带入window.defaultRouteName获取,
例:void main() => runApp(_widgetForRoute(window.defaultRouteName));
Flutter Bundle文件路径现在有点模糊后续再看(因在上边的分析中我们知道在DEBUG模式中是存在资源文件解压到应用文件中的可以理解通,但在RELEASE中没有资源解压缩的操作,只有个libapp.so文件,而这个路径也在启动Flutter engine中传入了,所以就有点模糊了,以后再看…)。
以上可知两个参数的传入只有在Intent action等于Intent.ACTION_RUN的情况下可用,否则不执行任何操作,直接返回false。但最终都会执行到runBundle(String appBundlePath)方法

  private void runBundle(String appBundlePath) {
     
        if (!flutterView.getFlutterNativeView().isApplicationRunning()) {
     
            FlutterRunArguments args = new FlutterRunArguments();
            args.bundlePath = appBundlePath;
            args.entrypoint = "main";
            flutterView.runFromBundle(args);
        }
    }

首先会判断当前的FlutterView应用是否已经在运行,如果已经运行就不会重新执行。没有运行会构建运行参数,entrypoint为dart应用的入口函数名,调用FlutterView的runFromBundle来运行。

再看看FlutterActivityDelegate的其他方法,都是Activity的生命周期方法调用,最终都通知到了FlutterView。

通过这篇分析了解到FlutterActivity只是一个空壳,我们可以自定义自己的实现,真正干活的是FlutterActivityDelegate。加载运行flutter应用的是FlutterView,而FlutterView通过FlutterActivityDelegate响应了Activity的生命周期。最终的核心在FlutterView。

你可能感兴趣的:(android,java)