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