introduce

Flutter applications are created, initialized, and launched by platforms (and Native). Here we take a quick look at the startup process using Android as an example, in order to get a sense of what is going on on the platform side.

Startup process on Android

The startup process actually involves a lot of native layer work, but for the sake of space, just look at the Android terminal.Copy the code

FlutterApplication

The native startup process of flutter does not change. Let’s look at the onCreate function of Application.

  @Override
  @CallSuper
  public void onCreate() {
    super.onCreate();
    FlutterMain.startInitialization(this);
  }

Copy the code

It’s simple. Keep going in

  public static void startInitialization(@NonNull Context applicationContext) {
    if (isRunningInRobolectricTest) {
      return;
    }
    FlutterLoader.getInstance().startInitialization(applicationContext);
  }
Copy the code

The above method is used to initialize the Native system and will eventually call the following methods:

I have put the instructions in annotated form belowCopy the code
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) { if (this.settings ! = null) { return; } /// make sure to run on the main thread if (looper.mylooper ()! = Looper.getMainLooper()) { throw new IllegalStateException("startInitialization must be called on the main thread"); } // Ensure that the context is actually the application context. final Context appContext = applicationContext.getApplicationContext(); this.settings = settings; initStartTimestampMillis = SystemClock.uptimeMillis(); // Configure parameters such as aotSharedLibraryName, flutterAssetsDir, vmSnapshotData, isolateSnapshotData // initConfig(appContext); // When the vsync signal arrives, the callback we set is called, Will eventually trigger a page refresh VsyncWaiter. GetInstance () (WindowManager appContext) getSystemService (Context. WINDOW_SERVICE)). The init (); // subthread // Callable<InitResult> initTask = new Callable<InitResult>() {@override public InitResult  call() { ResourceExtractor resourceExtractor = initResources(appContext); System.loadLibrary("flutter"); // Prefetch the default font manager as soon as possible on a background thread. // It helps to reduce time cost of engine setup that blocks the platform thread. Executors.newSingleThreadExecutor() .execute( new Runnable() { @Override public void run() { FlutterJNI.nativePrefetchDefaultFontManager(); }}); if (resourceExtractor ! = null) { resourceExtractor.waitForCompletion(); } return new InitResult( PathUtils.getFilesDir(appContext), PathUtils.getCacheDirectory(appContext), PathUtils.getDataDirectory(appContext)); }}; initResultFuture = Executors.newSingleThreadExecutor().submit(initTask); }Copy the code

At this point, the relevant flow of FlutterApplication is complete.

In addition, although the above code uses child threads, it will not enter the flutter side until these tasks are completed. Let’s proceed to the FlutterActivity.

FlutterActivity & onCreate

The onCreate() method is the same place to start:

@ Override protected void onCreate (@ Nullable Bundle savedInstanceState) {/ / / switch switchLaunchThemeForNormalTheme (); super.onCreate(savedInstanceState); / / / notify the life cycle of lifecycle. HandleLifecycleEvent (lifecycle. Event. ON_CREATE); / / / initializes the delete, this is very important, / / / all of the work is done by it to the delegate = new FlutterActivityAndFragmentDelegate (this); delegate.onAttach(this); / / / do you need (including notification plug-in) some state delegate. OnActivityCreated (savedInstanceState); / / / configuration window configureWindowForTransparency (); // createFlutterView setContentView(createFlutterView()); configureStatusBarForFullscreenFlutterExperience(); }Copy the code

Some of the heavier lines are these:

delegate = new FlutterActivityAndFragmentDelegate(this); delegate.onAttach(this); . setContentView(createFlutterView());Copy the code

We step by step, first create the FlutterActivityAndFragmentDelegate and calls its who attacks (this) method.

FlutterActivityAndFragmentDelegate

void onAttach(@NonNull Context context) { ensureAlive(); If (flutterEngine == null) {setupFlutterEngine(); } /// initializes the platform plugin /// essentially binds the engine's channel callback to the platform's system services /// e.g. vibrate, copy and paste, sound playback, etc. platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine); if (host.shouldAttachEngineToActivity()) { Log.v(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment."); PlatformViewsController is a class you should be familiar with (if you have access to native Views) .getActivityControlSurface() .attachToActivity(host.getActivity(), host.getLifecycle()); } / / / / / / registered plug-ins by reflection calls "IO. Flutter. Plugins. GeneratedPluginRegistrant" / / / "registerWith" method, this process is covered, Your plugin can use the host basic. ConfigureFlutterEngine (flutterEngine); }Copy the code

From the above, we have a general idea of when the platform function used on the Flutter end was assembled.

Let’s go back to FlutterActivity and continue with the important second step:

setContentView(createFlutterView());

  @NonNull
  private View createFlutterView() {
    return delegate.onCreateView(
        null /* inflater */, null /* container */, null /* savedInstanceState */);
  }
Copy the code
By the way, take a look at this article:Copy the code

Flutter&Android startup page (splash screen page) loading process and optimization scheme

The onCreateView for delete will eventually be called:

@NonNull View onCreateView( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { Log.v(TAG, "Creating FlutterView."); ensureAlive(); If (host.getRenderMode() == rendermode.surface) {rendermode.surface, FlutterSurfaceView FlutterSurfaceView FlutterSurfaceView = new FlutterSurfaceView(host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent); // Allow our host to customize FlutterSurfaceView, if desired. host.onFlutterSurfaceViewCreated(flutterSurfaceView); // After flutterView is created, addView is called to display the flutterSurfaceView, FlutterView = new flutterView (host.getActivity(), flutterSurfaceView); } else { ... Omit code... } // Add listener to be notified when Flutter renders its first frame. 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); } /// this page displays a white screen by default. AndroidMainfest. XML < metadata > set flutterSplashView. DisplayFlutterViewWithSplash (flutterView, host.provideSplashScreen()); / / / will flutterview bound to the engine flutterview. AttachToFlutterEngine (flutterEngine); return flutterSplashView; }Copy the code

FlutterView internally holds the flutterSurfaceView (a Surface), and is eventually bound to engine via attachToFlutterEngine. Let’s look at its internal implementation:

public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) { ... Omit some code... this.flutterEngine = flutterEngine; Engine's getRenderer allows you to draw the textures of flutter onto Android. FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer(); isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi(); renderSurface.attachToRenderer(flutterRenderer); flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener); . Omit some code... / / / input plug-in textInputPlugin = new textInputPlugin (this, this, flutterEngine getTextInputChannel (), this.flutterEngine.getPlatformViewsController()); / / / internationalization plug-in localizationPlugin = this. FlutterEngine. GetLocalizationPlugin (); / / / that is associated with the above textInputPlugin androidKeyProcessor = new androidKeyProcessor (this) flutterEngine) getKeyEventChannel (), textInputPlugin); Initialization / / / / / touch events/touch related data will be sent to flutter androidTouchProcessor = new androidTouchProcessor (this) flutterEngine) getRenderer ());  / / / assist accessibilityBridge = new accessibilityBridge (this, flutterEngine getAccessibilityChannel (), (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE), getContext().getContentResolver(), this.flutterEngine.getPlatformViewsController()); . Omit some code... / / / by the initialization, send user Settings related to flutter sendUserSettingsToFlutter (); localizationPlugin.sendLocalesToFlutter(getResources().getConfiguration()); sendViewportMetricsToFlutter(); / / / the current flutter view are bound to the PlatformViewsController flutterEngine. GetPlatformViewsController () attachToView (this); . Omit some code... }Copy the code

Once the initialization is complete, the activity lifecycle moves from onCreate to onStart().

FlutterActivity & onStart()

@Override protected void onStart() { super.onStart(); lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START); /// delegate. OnStart (); }Copy the code

Delegate.onstart () This method will eventually call the doInitialFlutterViewRun () method:

private void doInitialFlutterViewRun() { ... Omit some code... // This is the path to get the libapp.so we packaged. And execute it DartExecutor. DartEntrypoint entrypoint = new DartExecutor. DartEntrypoint (host. GetAppBundlePath (), host.getDartEntrypointFunctionName()); flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); }Copy the code

At this point the entire Android startup process is finished, and here is a review of the summary.

conclusion

In flutterApplication:

Initialize some resource paths, set relevant parameters to extract resources and load (assets) to load the key library of flutter. So - finally go JNI_OnLoad into native for related work - such as binding flutter JNI and initializing vsyncWaiterCopy the code

In flutterActivity:

Class will be initialized important FlutterActivityAndFragmentDelegate activity the life cycle, The delegate is also triggered to bind the platform's system functions (vibration, clipboard) to the platformViewController and the system channel to create the flutterView (which holds a surfaceView internally) - corresponding to the callback We'll eventually go into Native and initialize our engine and load our Dart code in the onStart lifecycle and start executingCopy the code

In the whole process, the work of the Native layer is interspersed, and the main() function of the flutter terminal is finally called by the Native layer. As there are many contents here, they will be introduced in the following articles.

Finally, thank you for your reading and please point out any mistakes.

series

Flutter mimics netease Cloud music App

Flutter&Android startup page (splash screen page) loading process and optimization scheme

Flutter version of imitation. Parallax effect of Zhihu list

Flutter — Realize progressive card switching for netease Cloud Music

Flutter imitates flush list of self-selected stocks