flutter:跨平台(Android/iOS),图形引擎,Dart语言 这些都有什么关系呢
我们先看下在安卓平台下的初始化:
入口:manifest
我们看到没有 Application,只有一个 MainActivity,还有一堆 meta-data
接下来看下 MainActivity 做了什么
class MainActivity: FlutterActivity() {}
发现只是继承了 io.flutter 包下的FlutterActivity
public class FlutterActivity extends Activity implements Host, LifecycleOwner {
继承了 android.app.Activity 实现了LifecycleOwner 通过 LifecycleRegistry(this); 实现了一套 Lifecycler ,还有个 Host 接口 来扩展 Flutter 相关的功能,那么Flutter 引擎如何初始化的呢?发现 FlutterActivity 的 onCreate 执行了一些相关逻辑
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
this.lifecycle.handleLifecycleEvent(Event.ON_CREATE);
this.delegate = new FlutterActivityAndFragmentDelegate(this);
this.delegate.onAttach(this);
this.delegate.onActivityCreated(savedInstanceState);
this.configureWindowForTransparency();
this.setContentView(this.createFlutterView());
this.configureStatusBarForFullscreenFlutterExperience();
}
1: 创建了 FlutterActivityAndFragmentDelegate 并 onAttach
2: 创建 FlutterView 通过 setContentView 添加到 Window
先看下第一步
void onAttach(@NonNull Context context) {
this.ensureAlive();
if (this.flutterEngine == null) {
this.setupFlutterEngine();
}
this.platformPlugin = this.host.providePlatformPlugin(this.host.getActivity(), this.flutterEngine);
if (this.host.shouldAttachEngineToActivity()) {
Log.v("FlutterActivityAndFragmentDelegate", "Attaching FlutterEngine to the Activity that owns this Fragment.");
this.flutterEngine.getActivityControlSurface().attachToActivity(this.host.getActivity(), this.host.getLifecycle());
}
this.host.configureFlutterEngine(this.flutterEngine);
}
void setupFlutterEngine() {
Log.v("FlutterActivityAndFragmentDelegate", "Setting up FlutterEngine.");
String cachedEngineId = this.host.getCachedEngineId();
if (cachedEngineId != null) {
this.flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
this.isFlutterEngineFromHost = true;
if (this.flutterEngine == null) {
throw new IllegalStateException("The requested cached FlutterEngine did not exist in the FlutterEngineCache: '" + cachedEngineId + "'");
}
} else {
this.flutterEngine = this.host.provideFlutterEngine(this.host.getContext());
if (this.flutterEngine != null) {
this.isFlutterEngineFromHost = true;
} else {
Log.v("FlutterActivityAndFragmentDelegate", "No preferred FlutterEngine was provided. Creating a new FlutterEngine for this FlutterFragment.");
this.flutterEngine = new FlutterEngine(this.host.getContext(), this.host.getFlutterShellArgs().toArray(), false, this.host.shouldRestoreAndSaveState());
this.isFlutterEngineFromHost = false;
}
}
}
setupFlutterEngin 方法去创建了 FlutterEngine 对象,这个对象是做什么到呢,我们看它到构造
public FlutterEngine(@NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI, @NonNull PlatformViewsController platformViewsController, @Nullable String[] dartVmArgs, boolean automaticallyRegisterPlugins, boolean waitForRestorationData) {
this.engineLifecycleListeners = new HashSet();
this.engineLifecycleListener = new FlutterEngine.EngineLifecycleListener() {
public void onPreEngineRestart() {
Log.v("FlutterEngine", "onPreEngineRestart()");
Iterator var1 = FlutterEngine.this.engineLifecycleListeners.iterator();
while(var1.hasNext()) {
FlutterEngine.EngineLifecycleListener lifecycleListener = (FlutterEngine.EngineLifecycleListener)var1.next();
lifecycleListener.onPreEngineRestart();
}
FlutterEngine.this.platformViewsController.onPreEngineRestart();
FlutterEngine.this.restorationChannel.clearData();
}
};
this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
this.dartExecutor.onAttachedToJNI();
this.accessibilityChannel = new AccessibilityChannel(this.dartExecutor, flutterJNI);
this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
this.localizationChannel = new LocalizationChannel(this.dartExecutor);
this.mouseCursorChannel = new MouseCursorChannel(this.dartExecutor);
this.navigationChannel = new NavigationChannel(this.dartExecutor);
this.platformChannel = new PlatformChannel(this.dartExecutor);
this.restorationChannel = new RestorationChannel(this.dartExecutor, waitForRestorationData);
this.settingsChannel = new SettingsChannel(this.dartExecutor);
this.systemChannel = new SystemChannel(this.dartExecutor);
this.textInputChannel = new TextInputChannel(this.dartExecutor);
this.localizationPlugin = new LocalizationPlugin(context, this.localizationChannel);
this.flutterJNI = flutterJNI;
flutterLoader.startInitialization(context.getApplicationContext());
flutterLoader.ensureInitializationComplete(context, dartVmArgs);
flutterJNI.addEngineLifecycleListener(this.engineLifecycleListener);
flutterJNI.setPlatformViewsController(platformViewsController);
flutterJNI.setLocalizationPlugin(this.localizationPlugin);
this.attachToJni();
this.renderer = new FlutterRenderer(flutterJNI);
this.platformViewsController = platformViewsController;
this.platformViewsController.onAttachedToJNI();
this.pluginRegistry = new FlutterEnginePluginRegistry(context.getApplicationContext(), this, flutterLoader);
if (automaticallyRegisterPlugins) {
this.registerPlugins();
}
}
监听了引擎到变化,初始化了一些系统基础 Channel(Dart通道) , FlutterLoader 对象 start ,flutterJNI 对象初始化,FlutterRender及FlutterView初始化,registerPlugins(插件初始化)
先看下 FlutterLoader 的 startInitialization 方法吧 ensureInitializationComplete,这个是整个 Flutter引擎 初始化的基础:
startInitialization 方法
public void startInitialization(@NonNull Context applicationContext, @NonNull FlutterLoader.Settings settings) {
if (this.settings == null) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
} else {
final Context appContext = applicationContext.getApplicationContext();
this.settings = settings;
this.initStartTimestampMillis = SystemClock.uptimeMillis();
this.initConfig(appContext);
VsyncWaiter.getInstance((WindowManager)appContext.getSystemService("window")).init();
Callable initTask = new Callable() {
public FlutterLoader.InitResult call() {
ResourceExtractor resourceExtractor = FlutterLoader.this.initResources(appContext);
System.loadLibrary("flutter");
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
FlutterJNI.nativePrefetchDefaultFontManager();
}
});
if (resourceExtractor != null) {
resourceExtractor.waitForCompletion();
}
return new FlutterLoader.InitResult(PathUtils.getFilesDir(appContext), PathUtils.getCacheDirectory(appContext), PathUtils.getDataDirectory(appContext));
}
};
this.initResultFuture = Executors.newSingleThreadExecutor().submit(initTask);
}
}
}
初始化了 flutter 的 c 库,并将 安卓系统的 vsync 同步到 flutter
public void init() {
FlutterJNI.setAsyncWaitForVsyncDelegate(this.asyncWaitForVsyncDelegate);
float fps = this.windowManager.getDefaultDisplay().getRefreshRate();
FlutterJNI.setRefreshRateFPS(fps);
}
private final AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new AsyncWaitForVsyncDelegate() {
public void asyncWaitForVsync(final long cookie) {
Choreographer.getInstance().postFrameCallback(new FrameCallback() {
public void doFrame(long frameTimeNanos) {
float fps = VsyncWaiter.this.windowManager.getDefaultDisplay().getRefreshRate();
long refreshPeriodNanos = (long)(1.0E9D / (double)fps);
FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);
}
});
}
};
ensureInitializationComplete方法
public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
if (!this.initialized) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
} else if (this.settings == null) {
throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
} else {
try {
FlutterLoader.InitResult result = (FlutterLoader.InitResult)this.initResultFuture.get();
List shellArgs = new ArrayList();
shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
ApplicationInfo applicationInfo = this.getApplicationInfo(applicationContext);
shellArgs.add("--icu-native-lib-path=" + applicationInfo.nativeLibraryDir + File.separator + "libflutter.so");
if (args != null) {
Collections.addAll(shellArgs, args);
}
String kernelPath = null;
String snapshotAssetPath = result.dataDirPath + File.separator + this.flutterAssetsDir;
kernelPath = snapshotAssetPath + File.separator + "kernel_blob.bin";
shellArgs.add("--snapshot-asset-path=" + snapshotAssetPath);
shellArgs.add("--vm-snapshot-data=" + this.vmSnapshotData);
shellArgs.add("--isolate-snapshot-data=" + this.isolateSnapshotData);
shellArgs.add("--cache-dir-path=" + result.engineCachesPath);
if (this.settings.getLogTag() != null) {
shellArgs.add("--log-tag=" + this.settings.getLogTag());
}
long initTimeMillis = SystemClock.uptimeMillis() - this.initStartTimestampMillis;
Bundle bundle = applicationInfo.metaData;
if (bundle != null) {
boolean use_embedded_view = bundle.getBoolean("io.flutter.embedded_views_preview");
if (use_embedded_view) {
shellArgs.add("--use-embedded-view");
}
}
FlutterJNI.nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), kernelPath, result.appStoragePath, result.engineCachesPath, initTimeMillis);
this.initialized = true;
} catch (Exception var11) {
Log.e("FlutterLoader", "Flutter initialization failed.", var11);
throw new RuntimeException(var11);
}
}
}
}
加载 assets 下的资源, vm_snapshot_data 和 isolate_snapshot_data 并调用Nactive 方法 FlutterJNI.nativeInit 交给 Flutter 引擎
再回到 FlutterActivityAndFragmentDelegate 我们看下在 setContentView FlutterView 的创建:
View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.v("FlutterActivityAndFragmentDelegate", "Creating FlutterView.");
this.ensureAlive();
if (this.host.getRenderMode() == RenderMode.surface) {
FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(this.host.getActivity(), this.host.getTransparencyMode() == TransparencyMode.transparent);
this.host.onFlutterSurfaceViewCreated(flutterSurfaceView);
this.flutterView = new FlutterView(this.host.getActivity(), flutterSurfaceView);
} else {
FlutterTextureView flutterTextureView = new FlutterTextureView(this.host.getActivity());
this.host.onFlutterTextureViewCreated(flutterTextureView);
this.flutterView = new FlutterView(this.host.getActivity(), flutterTextureView);
}
this.flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener);
this.flutterSplashView = new FlutterSplashView(this.host.getContext());
if (VERSION.SDK_INT >= 17) {
this.flutterSplashView.setId(View.generateViewId());
} else {
this.flutterSplashView.setId(486947586);
}
this.flutterSplashView.displayFlutterViewWithSplash(this.flutterView, this.host.provideSplashScreen());
Log.v("FlutterActivityAndFragmentDelegate", "Attaching FlutterEngine to FlutterView.");
this.flutterView.attachToFlutterEngine(this.flutterEngine);
return this.flutterSplashView;
}
我们看到 contentView 是 FlutterSplashView 并调用了 displayFlutterViewWithSplash 方法
final class FlutterSplashView extends FrameLayout {
public FlutterSplashView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.flutterEngineAttachmentListener = new FlutterEngineAttachmentListener() {
public void onFlutterEngineAttachedToFlutterView(@NonNull FlutterEngine engine) {
FlutterSplashView.this.flutterView.removeFlutterEngineAttachmentListener(this);
FlutterSplashView.this.displayFlutterViewWithSplash(FlutterSplashView.this.flutterView, FlutterSplashView.this.splashScreen);
}
public void onFlutterEngineDetachedFromFlutterView() {
}
};
......
public void displayFlutterViewWithSplash(@NonNull FlutterView flutterView, @Nullable SplashScreen splashScreen) {
if (this.flutterView != null) {
this.flutterView.removeOnFirstFrameRenderedListener(this.flutterUiDisplayListener);
this.removeView(this.flutterView);
}
if (this.splashScreenView != null) {
this.removeView(this.splashScreenView);
}
this.flutterView = flutterView;
this.addView(flutterView);
this.splashScreen = splashScreen;
if (splashScreen != null) {
if (this.isSplashScreenNeededNow()) {
Log.v(TAG, "Showing splash screen UI.");
this.splashScreenView = splashScreen.createSplashView(this.getContext(), this.splashScreenState);
this.addView(this.splashScreenView);
flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener);
} else if (this.isSplashScreenTransitionNeededNow()) {
Log.v(TAG, "Showing an immediate splash transition to Flutter due to previously interrupted transition.");
this.splashScreenView = splashScreen.createSplashView(this.getContext(), this.splashScreenState);
this.addView(this.splashScreenView);
this.transitionToFlutter();
} else if (!flutterView.isAttachedToFlutterEngine()) {
Log.v(TAG, "FlutterView is not yet attached to a FlutterEngine. Showing nothing until a FlutterEngine is attached.");
flutterView.addFlutterEngineAttachmentListener(this.flutterEngineAttachmentListener);
}
}
}
将 flutterView 和 SplashScreen(一个metadata 生成的 DrawableView)先后添加到 frameLayout 里,FlutterView 在 attachToFlutterEngine 时候回调将 SplashScreen 这个 View transitionToFlutter ,也就是 Alpha 设置为 0
public void transitionToFlutter(@NonNull final Runnable onTransitionComplete) {
if (this.splashView == null) {
onTransitionComplete.run();
} else {
this.splashView.animate().alpha(0.0F).setDuration(this.crossfadeDurationInMillis).setListener(new AnimatorListener() {
public void onAnimationStart(Animator animation) {
}
public void onAnimationEnd(Animator animation) {
onTransitionComplete.run();
}
public void onAnimationCancel(Animator animation) {
onTransitionComplete.run();
}
public void onAnimationRepeat(Animator animation) {
}
});
}
}
看了上面到源码感觉 flutter 引擎很像 WebView: