Flutter startup process source analysis

Flutter startup is dependent on FlutterApplication and FlutterActivity from the Java code level. Let’s take Flutter1.12.13 as an example to look at the source code

FlutterApplication startup process

1.1, FlutterApplication. OnCreate

public void onCreate(a) {
	super.onCreate();
  // Initializes flutter related resources
	FlutterMain.startInitialization(this);
}
Copy the code

1.2, FlutterMain

The Flutter Engine initializes classes

public static void startInitialization(@NonNull Context applicationContext) {
  if (isRunningInRobolectricTest) {
    return;
  }
  // A singleton FlutterLoader was extracted from 1.9.1+hotfix.6
  FlutterLoader.getInstance().startInitialization(applicationContext);
}
Copy the code

1.3, FlutterLoader

Find flutter Resources in APK and load libflutter

FlutterLoader–>startInitialization

public void startInitialization(@NonNull Context applicationContext) {
  // Initialize a default Setting
  startInitialization(applicationContext, new Settings());
}
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
  // The global Settings has not been assigned for the first time. Ensure that startInitialization is executed only once
  if (this.settings ! =null) {
    return;
  }
  // Make sure initialization is performed in the main thread
  if(Looper.myLooper() ! = Looper.getMainLooper()) {throw new IllegalStateException("startInitialization must be called on the main thread");
  }

  // Use the application context.
  applicationContext = applicationContext.getApplicationContext();
	// Assign global Settings
  this.settings = settings;

  long initStartTimestampMillis = SystemClock.uptimeMillis();
  // Initialize the configuration
  initConfig(applicationContext);
  // Initializes resource loading
  initResources(applicationContext);
	// One of the main functions of this class is to load libflutter
  System.loadLibrary("flutter");

  VsyncWaiter.getInstance(
    (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
    .init();

  long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
  // Call the C layer code to record the application startup time
  FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}
Copy the code

FlutterLoader–>initConfig

Load the configuration of flutter in Androidmanifest.xml:

Aot mode libapp.so (default: lib/armeabi-v7a or lib/arm64-v8a)

2. Path of the flutter_assets resource file (default: assets folder)

Location of vm_snapshot_data in JIT mode (default in FLutter_assets folder for DEBUG)

4. Location of isolate_SNAPshot_data in JIT mode (in flutter_assets folder by default during DEBUG)

private void initConfig(@NonNull Context applicationContext) {
  Bundle metadata = getApplicationInfo(applicationContext).metaData;

  // There isn't a `<meta-data>` tag as a direct child of `<application>` in
  // `AndroidManifest.xml`.
  if (metadata == null) {
    return;
  }

  aotSharedLibraryName =
    metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, DEFAULT_AOT_SHARED_LIBRARY_NAME);
  flutterAssetsDir =
    metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, DEFAULT_FLUTTER_ASSETS_DIR);

  vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, DEFAULT_VM_SNAPSHOT_DATA);
  isolateSnapshotData =
    metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, DEFAULT_ISOLATE_SNAPSHOT_DATA);
}
Copy the code

FlutterLoader.initResources

In debug or JIT mode, load vm_SNAPshot_data, isolate_SNAPshot_data, and kernel_blob.bin

private void initResources(@NonNull Context applicationContext) {
  Clears out data / / / user / 0 / package/cache directory file
  new ResourceCleaner(applicationContext).start();
	Debug or JIT mode
  if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
    / / data/user / 0 / package/app_flutter directory
    final String dataDirPath = PathUtils.getDataDirectory(applicationContext);
    final String packageName = applicationContext.getPackageName();
    final PackageManager packageManager = applicationContext.getPackageManager();
    final AssetManager assetManager = applicationContext.getResources().getAssets();
    resourceExtractor =
      new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
    
    // The resource is loaded into the list
    resourceExtractor
      .addResource(fullAssetPathFrom(vmSnapshotData)) // fullAssetPathFrom is a way to spell the full path of flutter_assets
      .addResource(fullAssetPathFrom(isolateSnapshotData))
      .addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));
    
    // Start an AsyncTask that will delete the vm_snapshot_data, isolate_snapshot_data and kernel_blob.bin files corresponding to the data/user/0/package/app_flutter directory. Then copy the new files from assets in the APK installation directory for useresourceExtractor.start(); }}Copy the code

1.4, FlutterJNI

The JNI method wrapper used when libflutter. So is called

// Record the application startup time
public static native void nativeRecordStartTimestamp(long initTimeMillis);
Copy the code

1.5, flutter_main. Cc

Mainly defines two methods: nativeInit, nativeRecordStartTimestamp

bool FlutterMain::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {
      //... Omit other code
      {
        	/ / nativeRecordStartTimestamp JNI methods, into a call c + + RecordStartTimestamp method
          .name = "nativeRecordStartTimestamp",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
      },
  };
  //... Omit other code
}
Copy the code

1.6, libary_loader. Cc

The JNI_OnLoad method is triggered when loading libflutter. So

// Register the JNI method of FlutterMain
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  //... Omit other code
	result = flutter::FlutterMain::Register(env);
  //... Omit other code
}
Copy the code

Attached is the sequence diagram of FlutterApplication

image-flutter-application.png

Second, the FlutterActivity

In the flutter has two FlutterActivity, one is the IO. Flutter. App. FlutterActivity, another is the IO flutter. Embedding. Android. FlutterActivity, The former is an older version of the Flutter runtime class and is no longer recommended in version 1.12. Reference documentation, https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects, Interpretation of the following are the IO. Flutter. Embedding. Android. FlutterActivity.

2.1, FlutterActivity

2.1.1, onCreate
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
  // Check whether there are configuration topics in MeteData
  switchLaunchThemeForNormalTheme();
  super.onCreate(savedInstanceState);
  lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
	// Initialize the delegate
  delegate = new FlutterActivityAndFragmentDelegate(this);
  // Initializes the flutter engine
  delegate.onAttach(this);
  // Provide onRestoreInstanceState for the plug-in to restore state
  delegate.onActivityCreated(savedInstanceState);

  // If the Intent's backgroundMode is transparent, then the window is transparent
  configureWindowForTransparency();
  / / create FlutterView
  setContentView(createFlutterView());
  configureStatusBarForFullscreenFlutterExperience();
}
Copy the code
2.1.2, configureWindowForTransparency
public FlutterView.RenderMode getRenderMode(a) {
  	// Get the backgroundMode passed in the intent, opaque means opaque
    return getBackgroundMode() == BackgroundMode.opaque
        ? FlutterView.RenderMode.surface
        : FlutterView.RenderMode.texture;
}
private void configureWindowForTransparency(a) {
    BackgroundMode backgroundMode = getBackgroundMode();
    if (backgroundMode == BackgroundMode.transparent) {
      getWindow().setBackgroundDrawable(newColorDrawable(Color.TRANSPARENT)); getWindow().setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ); }}Copy the code
2.1.3, createFlutterView
private View createFlutterView(a) {
	// Create the flutterView by proxy
	return delegate.onCreateView(
  	null /* inflater */.null /* container */.null /* savedInstanceState */);
}
Copy the code

2.2, FlutterActivityAndFragmentDelegate

2.2.1, onAttach

Mainly do the following things:

Get or create the Flutter Engine

2. Create and configure PlatformPlugin

3. Attach flutterEngine to the activity

void onAttach(@NonNull Context context) {
    ensureAlive();

    // When this FlutterActivity is multiplexed, the Flutter engine multiplexes
    if (flutterEngine == null) {
      setupFlutterEngine();
    }

    // Create and configure the Platform plugin
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);

    if (host.shouldAttachEngineToActivity()) {
      Attach the Flutter engine to the activity
      Log.d(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment.");
      flutterEngine.getActivityControlSurface().attachToActivity(
          host.getActivity(),
          host.getLifecycle()
      );
    }
		// The flutter activity configuration provides entry to the flutter engine
    host.configureFlutterEngine(flutterEngine);
  }
Copy the code

2.2.2, onCreateView

View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.v(TAG, "Creating FlutterView.");
    ensureAlive();
  	/ / create flutterView
    flutterView = new FlutterView(host.getActivity(), host.getRenderMode(), host.getTransparencyMode());
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
		// Create a flutter in view until the first frame of flutter is displayed
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      flutterSplashView.setId(486947586);
    }
  	// Splash View will be removed after the first frame of flutter view is rendered
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());

    return flutterSplashView;
 }
Copy the code

Third, FlutterEngine

3.1. Called when constructing a method
public FlutterEngine( @NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI, @NonNull PlatformViewsController platformViewsController, @nullable String[] dartVmArgs,// FlutterActivity Override getFlutterShellArgs to add parametersboolean automaticallyRegisterPlugins) {
    this.flutterJNI = flutterJNI;
  	// Initialize the configuration, resources, and load libflutter. If FlutterApplication is used, initialization is not repeated
    flutterLoader.startInitialization(context.getApplicationContext());
  	// Make sure initialization is complete
    flutterLoader.ensureInitializationComplete(context, dartVmArgs);

    flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
  	// Call flutterJNI's attachToNative to initialize the setting configuration
    attachToJni();

    this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
    this.dartExecutor.onAttachedToJNI();

    //... omit
  }
Copy the code
3.2, attachToJni
private void attachToJni(a) {
    Log.v(TAG, "Attaching to JNI.");
    // Call the method in libflutter. So with FlutterJNI
    flutterJNI.attachToNative(false);
    if(! isAttachedToJni()) {throw new RuntimeException("FlutterEngine failed to attach to its native Object reference."); }}Copy the code

Four, FlutterJNI

This class calls the C/C++ code in the Flutter engine, corresponding to the platform_view_android_jni.cc code

// pass the Java layer initialization parameters to the C++ layer
public static native void nativeInit( @NonNull Context context, @NonNull String[] args, @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath);
Copy the code
// Initialize AndroidShellHolder
private native long nativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView);
Copy the code

Attached is the FlutterActivity startup sequence diagram

After learning about the startup process of Flutter, in the next article we will configure the build environment of Flutter Engine and make Flutter dynamic step by step