回想在公司工做拿到的第一個項目是一個flash遊戲項目,在那個時候flash遊戲很是流行,尚未被html5取代的跡象。遊戲程序架構採用的是後端mfc+前端flash框架,整個項目代碼20萬行,就我本身一我的開發。公司的要求是能修改、增長遊戲的功能。當時我雖然有一點mfc的基礎,可是遊戲沒有接觸過、flash的actionscript3更是一竅不通。那怎麼辦呢?學唄。因而通過一兩個月的各類畫uml圖、流程圖、寫僞代碼等等一系列的理解學習,發現不但理解了後端、前端的工做原理,甚至能夠開始擼框架了。那個時候整天跟人吹牛,如今想起來仍是以爲十分的有趣。一個看似龐大的體系從一竅不通到完全掌握,這個過程只要經歷一遍,以後就以爲沒有什麼問題是解決不了的。html
flutter在實現上破天荒的沒有采用目前的各類成熟視圖體系,而是採用了本身構建一套視圖體系,用gpu加速,因此性能高、界面流暢。對此,表示十分的感興趣。那麼要完全的挖掘一個框架的本質,就只有研究源碼這麼一條道路。從今天起,預計花一到兩個月的時間來分析flutter的源碼,在這裏給你們分享下研究的過程。前端
這一系列的文章應該會很是長,研究源碼須要耐心,不是麼。html5
筆者認爲這樣android
/// activity實現了三個接口 public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory { /// 視圖提供類,一個方法getFlutterView public interface Provider { FlutterView getFlutterView(); } /// 插件註冊 public interface PluginRegistry { /// 註冊一個插件 PluginRegistry.Registrar registrarFor(String var1); /// 是否有這個插件 boolean hasPlugin(String var1); /// 插件發佈值 <T> T valuePublishedByPlugin(String var1); /// 下面開始爲插件生命週期回調 public interface PluginRegistrantCallback { void registerWith(PluginRegistry var1); } /// 顯然是視圖銷燬的回調 public interface ViewDestroyListener { boolean onViewDestroy(FlutterNativeView var1); } //// 不知道幹啥,先留着 public interface UserLeaveHintListener { void onUserLeaveHint(); } //// activity生命週期回調之onNewIntent public interface NewIntentListener { boolean onNewIntent(Intent var1); } //// activity生命週期回調之onActivityResult public interface ActivityResultListener { boolean onActivityResult(int var1, int var2, Intent var3); } //// activity生命週期回調之onRequestPermissionsResult public interface RequestPermissionsResultListener { boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3); } /// 插件的註冊者,至關於插件的宿主。 public interface Registrar { Activity activity(); Context context(); Context activeContext(); /// 這個BinaryMessager還不知道幹啥 BinaryMessenger messenger(); /// TextureRegistry不清楚 TextureRegistry textures(); /// 獲取視圖 FlutterView view(); /// 尋找資源 String lookupKeyForAsset(String var1); /// 尋找資源 String lookupKeyForAsset(String var1, String var2); /// 發佈值,與上面的valuePublishedByPlugin對應 PluginRegistry.Registrar publish(Object var1); /// 增長生命週期回調 PluginRegistry.Registrar addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener var1); /// 增長生命週期回調 PluginRegistry.Registrar addActivityResultListener(PluginRegistry.ActivityResultListener var1); PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener var1); /// 增長生命週期回調 PluginRegistry.Registrar addUserLeaveHintListener(PluginRegistry.UserLeaveHintListener var1); /// 增長生命週期回調 PluginRegistry.Registrar addViewDestroyListener(PluginRegistry.ViewDestroyListener var1); } } /// 視圖工廠 public interface ViewFactory { /// 建立flutterView FlutterView createFlutterView(Context var1); //// 建立nativeview FlutterNativeView createFlutterNativeView(); /// 暫時搞不清楚幹啥的,先留着 boolean retainFlutterNativeView(); }
這些問題在以後的分析中應該能解決。shell
///建立FlutterActivityDelegate private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this); private final FlutterActivityEvents eventDelegate; private final Provider viewProvider; private final PluginRegistry pluginRegistry; public FlutterActivity() { /// FlutterActivityDelegate實現了這三個接口,並賦值給三個變量,這樣調用起來更加清晰。 this.eventDelegate = this.delegate; this.viewProvider = this.delegate; this.pluginRegistry = this.delegate; }
///這裏都是由建立FlutterActivityDelegate代理執行,就不一一貼出來了 protected void onXXX() { super.onXXX(); this.eventDelegate.onXXX(); }
值得注意的是這裏的三個回調,表示FlutterView是如何建立出來的。後端
public FlutterView getFlutterView() { /// 有關的函數,只有這個由FlutterActivityDelegate代理執行 return this.viewProvider.getFlutterView(); } public FlutterView createFlutterView(Context context) { return null; } public FlutterNativeView createFlutterNativeView() { return null; } public boolean retainFlutterNativeView() { return false; }
/// 啓動參數解析 String[] args = getArgsFromIntent(this.activity.getIntent()); /// 等待並保證初始化完成 FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args); /// 建立flutterView,注意到上面默認的返回null this.flutterView = this.viewFactory.createFlutterView(this.activity); if (this.flutterView == null) { /// 默認走這裏,createFlutterNativeView默認返回null FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView(); //實際建立了FlutterView this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView); // 設置layout,並添加到當前activity,做爲主視圖 this.flutterView.setLayoutParams(matchParent); this.activity.setContentView(this.flutterView); //建立啓動ui this.launchView = this.createLaunchView(); if (this.launchView != null) { //若是有建立啓動ui成功,那麼增長到當前activity上面 this.addLaunchView(); } }
看下FlutterMain.ensureInitializationComplete緩存
public static void ensureInitializationComplete(Context applicationContext, String[] args) { // 保證ui線程運行 if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("ensureInitializationComplete must be called on the main thread"); } else if (!sInitialized) { try { // 等待完成,這裏有個疑問點,sResourceExtractor是何時建立的 sResourceExtractor.waitForCompletion(); // 繼續解析參數 List<String> shellArgs = new ArrayList(); shellArgs.add("--icu-data-file-path=" + new File(PathUtils.getDataDirectory(applicationContext), "icudtl.dat")); if (args != null) { Collections.addAll(shellArgs, args); } if (sIsPrecompiledAsSharedLibrary) { shellArgs.add("--aot-shared-library-path=" + new File(PathUtils.getDataDirectory(applicationContext), sAotSharedLibraryPath)); } else { if (sIsPrecompiledAsBlobs) { shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext)); } else { shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext)); shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext) + "/" + sFlutterAssetsDir); } shellArgs.add("--vm-snapshot-data=" + sAotVmSnapshotData); shellArgs.add("--vm-snapshot-instr=" + sAotVmSnapshotInstr); shellArgs.add("--isolate-snapshot-data=" + sAotIsolateSnapshotData); shellArgs.add("--isolate-snapshot-instr=" + sAotIsolateSnapshotInstr); } if (sSettings.getLogTag() != null) { shellArgs.add("--log-tag=" + sSettings.getLogTag()); } // 查找bundle String appBundlePath = findAppBundlePath(applicationContext); // native初始化,參數爲解析的全部啓動參數和一個bundle的路徑 nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath); sInitialized = true; } catch (Exception var4) { Log.e("FlutterMain", "Flutter initialization failed.", var4); throw new RuntimeException(var4); } } }
///這裏的nativeInit是jni調用,實際做用是? 這裏我猜是初始化dart環境,並初始化加載bundle,相似初始化js環境,並加載jsbundle private static native void nativeInit(Context var0, String[] var1, String var2);
看下:架構
sResourceExtractor.waitForCompletion();
sResourceExtractor是啥時候建立的?那麼這裏全局搜索了一番,瞭解到到FlutterMain#startInitialization這個方法是在FlutterApplication中調用的,因此先看下Application。這裏先提出疑問,以後解決。app
原本這個Application應該是第一個分析的,可是首先用戶看到的flutter建立的example裏面暴露的第一個類應該就是FlutterActivity。FlutterApplication是在AndroidManifest中定義的,因此筆者一開始沒有注意到,這裏插個隊補上。框架
public class FlutterApplication extends Application { private Activity mCurrentActivity = null; public FlutterApplication() { } // 顯然這裏進行了全局初始化 @CallSuper public void onCreate() { super.onCreate(); FlutterMain.startInitialization(this); } public Activity getCurrentActivity() { return this.mCurrentActivity; } // 設置當前的Activity public void setCurrentActivity(Activity mCurrentActivity) { this.mCurrentActivity = mCurrentActivity; } }
public static void startInitialization(Context applicationContext, FlutterMain.Settings settings) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("startInitialization must be called on the main thread"); } else if (sSettings == null) { sSettings = settings; long initStartTimestampMillis = SystemClock.uptimeMillis(); initConfig(applicationContext); initAot(applicationContext); initResources(applicationContext); System.loadLibrary("flutter"); long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; nativeRecordStartTimestamp(initTimeMillis); } }
這裏的Setting很是簡單,只是提供了日誌的tag,那麼這個logTag在哪裏用?又是一個疑問。
public static class Settings { private String logTag; public Settings() { } public String getLogTag() { return this.logTag; } public void setLogTag(String tag) { this.logTag = tag; } }
initConfig,這個函數主要用於初始化配置
private static void initConfig(Context applicationContext) { try { Bundle metadata = applicationContext.getPackageManager().getApplicationInfo(applicationContext.getPackageName(), 128).metaData; if (metadata != null) { sAotSharedLibraryPath = metadata.getString(PUBLIC_AOT_AOT_SHARED_LIBRARY_PATH, "app.so"); sAotVmSnapshotData = metadata.getString(PUBLIC_AOT_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data"); sAotVmSnapshotInstr = metadata.getString(PUBLIC_AOT_VM_SNAPSHOT_INSTR_KEY, "vm_snapshot_instr"); sAotIsolateSnapshotData = metadata.getString(PUBLIC_AOT_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data"); sAotIsolateSnapshotInstr = metadata.getString(PUBLIC_AOT_ISOLATE_SNAPSHOT_INSTR_KEY, "isolate_snapshot_instr"); sFlx = metadata.getString(PUBLIC_FLX_KEY, "app.flx"); sSnapshotBlob = metadata.getString(PUBLIC_SNAPSHOT_BLOB_KEY, "snapshot_blob.bin"); sFlutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets"); } } catch (NameNotFoundException var2) { throw new RuntimeException(var2); } }
這裏能夠看到flutter的定製選項,能夠在androd的meta裏面定義
關於aot,這裏有幾篇博文介紹:
https://www.cnblogs.com/zengm...
https://www.cnblogs.com/tinyt...
AOT是一種靜態編譯技術,與JIT對應
private static void initAot(Context applicationContext) { // 列出全部的assets文件夾中的資源 Set<String> assets = listRootAssets(applicationContext); // sIsPrecompiledAsBlobs = assets.containsAll(Arrays.asList(sAotVmSnapshotData, sAotVmSnapshotInstr, sAotIsolateSnapshotData, sAotIsolateSnapshotInstr)); sIsPrecompiledAsSharedLibrary = assets.contains(sAotSharedLibraryPath); // 意思是兩個不能同時存在? if (sIsPrecompiledAsBlobs && sIsPrecompiledAsSharedLibrary) { throw new RuntimeException("Found precompiled app as shared library and as Dart VM snapshots."); } }
private static void initResources(Context applicationContext) { // 開始清理資源 (new ResourceCleaner(applicationContext)).start(); // 建立sResourceExtractor sResourceExtractor = (new ResourceExtractor(applicationContext)).addResources(SKY_RESOURCES).addResource(fromFlutterAssets(sFlx)).addResource(fromFlutterAssets(sSnapshotBlob)).addResource(fromFlutterAssets(sAotVmSnapshotData)).addResource(fromFlutterAssets(sAotVmSnapshotInstr)).addResource(fromFlutterAssets(sAotIsolateSnapshotData)).addResource(fromFlutterAssets(sAotIsolateSnapshotInstr)).addResource(fromFlutterAssets("kernel_blob.bin")).addResource(fromFlutterAssets("platform.dill")); // 增長資源 if (sIsPrecompiledAsSharedLibrary) { sResourceExtractor.addResource(sAotSharedLibraryPath); } else { sResourceExtractor.addResource(sAotVmSnapshotData).addResource(sAotVmSnapshotInstr).addResource(sAotIsolateSnapshotData).addResource(sAotIsolateSnapshotInstr).addResource(sSnapshotBlob); } //開始 sResourceExtractor.start(); }
看下:
(new ResourceCleaner(applicationContext)).start(),做用是清理緩存
boolean result = name.startsWith(".org.chromium.Chromium."); return result; ... protected Void doInBackground(Void... unused) { File[] var2 = this.mFilesToDelete; int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { File file = var2[var4]; if (file.exists()) { this.deleteRecursively(file); } } }
看下:sResourceExtractor.start();
ResourceExtractor start() { assert this.mExtractTask == null; this.mExtractTask = new ResourceExtractor.ExtractTask(); this.mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Void[0]); return this; } ... private void extractResources() { File dataDir = new File(PathUtils.getDataDirectory(ResourceExtractor.this.mContext)); ... InputStream is = manager.open(asset); Throwable var9 = null; try { OutputStream os = new FileOutputStream(output); Throwable var11 = null; ... while((count = is.read(buffer, 0, 16384)) != -1) { os.write(buffer, 0, count); } ... } ... public final class PathUtils { ... public static String getDataDirectory(Context applicationContext) { return applicationContext.getDir("Lflutter", 0).getPath(); } ... }
這段代碼是將指定的assert文件夾中的文件拷貝到應用程序目錄中的flutter文件夾下,說明後續程序須要直接使用文件,而不是assert文件夾中的二進制。
System.loadLibrary("flutter"); nativeRecordStartTimestamp(initTimeMillis);
初始化native,並記錄時間,native的部分,這篇文章先不予考慮,專門在一個專題裏面寫。
此次光看代碼比較難以理解,須要動態調試了
此次顯然已經解決了前面的問題(8), FlutterActivity在啓動的時候,須要等待FlutterApplicaiton中的異步加載資源完畢
FlutterApplication在onCreate的時候,初始化加載Flutter中的資源,含bundle、so庫等重要啓動資源,而在FlutterActivity的onCreate中,會等待FlutterApplication的這個過程完畢以後再進行下一步的初始化。
這裏接着上面來分析FlutterView的建立過程:
public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry, AccessibilityStateChangeListener {
注意到FlutterView繼承了SurfaceView,關於SurfaceView,能夠參考幾篇博文理解:
https://blog.csdn.net/android...
https://www.cnblogs.com/zhang...
SurfaceView使用的繪圖線程不是ui線程,咱們平時使用的攝像頭、遊戲之類的要求圖形性能比較高的場景就靠它了。
看下構造函數:
this.nextTextureId = new AtomicLong(0L); ... @Override public TextureRegistry.SurfaceTextureEntry createSurfaceTexture() { final SurfaceTexture surfaceTexture = new SurfaceTexture(0); surfaceTexture.detachFromGLContext(); final SurfaceTextureRegistryEntry entry = new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture); nativeRegisterTexture(mNativeView.get(), entry.id(), surfaceTexture); return entry; }
這裏使用到了SurfaceTexture,並執行了nativeRegisterTexture,關於SurfaceTexture,找到這麼幾篇博文:
https://www.cnblogs.com/wytig...
https://blog.csdn.net/hejjunl...
https://blog.csdn.net/u010949...
https://blog.csdn.net/tq08g2z...
https://blog.csdn.net/OnafioO...
https://blog.csdn.net/u010949...
https://blog.csdn.net/u010949...
基本上全是csdn的老文章!
這個SurfactTexture具體做用?先放放。
接着往下看:
this.mIsSoftwareRenderingEnabled = nativeGetIsSoftwareRenderingEnabled();
關於android的軟件渲染仍是硬件渲染:
https://blog.csdn.net/wlwl007...
https://blog.csdn.net/luoshen...
http://www.sohu.com/a/1605251...
繼續
this.mMetrics = new FlutterView.ViewportMetrics(); this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density; ... private void updateViewportMetrics() { if (this.isAttached()) { nativeSetViewportMetrics(this.mNativeView.get(), this.mMetrics.devicePixelRatio, this.mMetrics.physicalWidth, this.mMetrics.physicalHeight, this.mMetrics.physicalPaddingTop, this.mMetrics.physicalPaddingRight, this.mMetrics.physicalPaddingBottom, this.mMetrics.physicalPaddingLeft, this.mMetrics.physicalViewInsetTop, this.mMetrics.physicalViewInsetRight, this.mMetrics.physicalViewInsetBottom, this.mMetrics.physicalViewInsetLeft); WindowManager wm = (WindowManager)this.getContext().getSystemService("window"); float fps = wm.getDefaultDisplay().getRefreshRate(); VsyncWaiter.refreshPeriodNanos = (long)(1.0E9D / (double)fps); } } ... protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { this.mMetrics.physicalWidth = width; this.mMetrics.physicalHeight = height; this.updateViewportMetrics(); super.onSizeChanged(width, height, oldWidth, oldHeight); } public final WindowInsets onApplyWindowInsets(WindowInsets insets) { this.mMetrics.physicalPaddingTop = insets.getSystemWindowInsetTop(); this.mMetrics.physicalPaddingRight = insets.getSystemWindowInsetRight(); this.mMetrics.physicalPaddingBottom = 0; this.mMetrics.physicalPaddingLeft = insets.getSystemWindowInsetLeft(); this.mMetrics.physicalViewInsetTop = 0; this.mMetrics.physicalViewInsetRight = 0; this.mMetrics.physicalViewInsetBottom = insets.getSystemWindowInsetBottom(); this.mMetrics.physicalViewInsetLeft = 0; this.updateViewportMetrics(); return super.onApplyWindowInsets(insets); } protected boolean fitSystemWindows(Rect insets) { if (VERSION.SDK_INT <= 19) { this.mMetrics.physicalPaddingTop = insets.top; this.mMetrics.physicalPaddingRight = insets.right; this.mMetrics.physicalPaddingBottom = 0; this.mMetrics.physicalPaddingLeft = insets.left; this.mMetrics.physicalViewInsetTop = 0; this.mMetrics.physicalViewInsetRight = 0; this.mMetrics.physicalViewInsetBottom = insets.bottom; this.mMetrics.physicalViewInsetLeft = 0; this.updateViewportMetrics(); return true; } else { return super.fitSystemWindows(insets); } } private boolean isAttached() { return this.mNativeView != null && this.mNativeView.isAttached(); }
這裏又涉及到幾個概念,基本都不怎麼經常使用:
WindowInsets,onApplyWindowInsets:
https://blog.csdn.net/me_touc...
fitSystemWindows:
https://blog.csdn.net/ys40897...
static final class ViewportMetrics { float devicePixelRatio = 1.0F; int physicalWidth = 0; int physicalHeight = 0; int physicalPaddingTop = 0; int physicalPaddingRight = 0; int physicalPaddingBottom = 0; int physicalPaddingLeft = 0; int physicalViewInsetTop = 0; int physicalViewInsetRight = 0; int physicalViewInsetBottom = 0; int physicalViewInsetLeft = 0; ViewportMetrics() { } }
這段代碼的意思顯然是適配窗口大小的變化,並在恰當的時候更新mMetrics,並設置到native中
private static native void nativeSetViewportMetrics(long nativePlatformViewAndroid, float devicePixelRatio, int physicalWidth, int physicalHeight, int physicalPaddingTop, int physicalPaddingRight, int physicalPaddingBottom, int physicalPaddingLeft, int physicalViewInsetTop, int physicalViewInsetRight, int physicalViewInsetBottom, int physicalViewInsetLeft);
繼續:
Activity activity = (Activity)this.getContext(); if (nativeView == null) { this.mNativeView = new FlutterNativeView(activity.getApplicationContext()); } else { this.mNativeView = nativeView; }
NativeView是什麼?
public class FlutterNativeView implements BinaryMessenger { ... public FlutterNativeView(Context context) { this.mContext = context; // 插件管理 this.mPluginRegistry = new FlutterPluginRegistry(this, context); this.attach(this); this.assertAttached(); // 消息管理 this.mMessageHandlers = new HashMap(); } ... //涉及到和native打交道 private static native long nativeAttach(FlutterNativeView var0); private static native void nativeDestroy(long var0); private static native void nativeDetach(long var0); private static native void nativeRunBundleAndSnapshot(long var0, String var2, String var3, String var4, boolean var5, AssetManager var6); private static native void nativeRunBundleAndSource(long var0, String var2, String var3, String var4); private static native void nativeSetAssetBundlePathOnUI(long var0, String var2); private static native String nativeGetObservatoryUri(); private static native void nativeDispatchEmptyPlatformMessage(long var0, String var2, int var3); private static native void nativeDispatchPlatformMessage(long var0, String var2, ByteBuffer var3, int var4, int var5); private static native void nativeInvokePlatformMessageEmptyResponseCallback(long var0, int var2); private static native void nativeInvokePlatformMessageResponseCallback(long var0, int var2, ByteBuffer var3, int var4); }
NativeView顯然是一個插件、消息的管理類,並與native打交道,那麼和FlutterView的關係,顯然一個負責展現,一個負責交互。這裏解決了問題(1)
再往下看
this.mSurfaceCallback = new Callback() { public void surfaceCreated(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.nativeSurfaceCreated(FlutterView.this.mNativeView.get(), holder.getSurface(), color); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { FlutterView.this.assertAttached(); FlutterView.nativeSurfaceChanged(FlutterView.this.mNativeView.get(), width, height); } public void surfaceDestroyed(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.nativeSurfaceDestroyed(FlutterView.this.mNativeView.get()); } }; this.getHolder().addCallback(this.mSurfaceCallback);
這裏監聽了SurfaceView的生命週期,並調用native
this.mAccessibilityManager = (AccessibilityManager)this.getContext().getSystemService("accessibility"); this.mActivityLifecycleListeners = new ArrayList(); this.mFirstFrameListeners = new ArrayList(); this.mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE); this.mFlutterNavigationChannel = new MethodChannel(this, "flutter/navigation", JSONMethodCodec.INSTANCE); this.mFlutterKeyEventChannel = new BasicMessageChannel(this, "flutter/keyevent", JSONMessageCodec.INSTANCE); this.mFlutterLifecycleChannel = new BasicMessageChannel(this, "flutter/lifecycle", StringCodec.INSTANCE); this.mFlutterSystemChannel = new BasicMessageChannel(this, "flutter/system", JSONMessageCodec.INSTANCE); this.mFlutterSettingsChannel = new BasicMessageChannel(this, "flutter/settings", JSONMessageCodec.INSTANCE); PlatformPlugin platformPlugin = new PlatformPlugin(activity); MethodChannel flutterPlatformChannel = new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE); flutterPlatformChannel.setMethodCallHandler(platformPlugin); this.addActivityLifecycleListener(platformPlugin); this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method"); this.mTextInputPlugin = new TextInputPlugin(this); this.setLocale(this.getResources().getConfiguration().locale); this.setUserSettings();
這段代碼註冊了一些Flutter的自帶插件,主要用於輸入、生命週期、國際化等系統相關的插件,有時間再一個一個分析,先放放。
大部分問題在這裏都解釋不了,這裏先用一張圖表示一下啓動流程:
若有疑問,請加qq羣854192563討論