Flutter初始化分析(二)

作者: 小波_po | 来源:发表于2019-03-28 18:03 被阅读22次

    接着上篇分析,这篇从FlutterActivity创建开始切入。

    public class MainActivity extends FlutterActivity {
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            GeneratedPluginRegistrant.registerWith(this);
        }
    
    }
    

    首先可以看出,默认创建的MainActivity 没有我们常见的setContentView(),那应该是在FlutterActivity里面设置的。

    public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
        private static final String TAG = "FlutterActivity";
        private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
        private final FlutterActivityEvents eventDelegate;
        private final Provider viewProvider;
        private final PluginRegistry pluginRegistry;
    
        public FlutterActivity() {
            this.eventDelegate = this.delegate;
            this.viewProvider = this.delegate;
            this.pluginRegistry = this.delegate;
        }
    
        public FlutterView getFlutterView() {
            return this.viewProvider.getFlutterView();
        }
    
        public FlutterView createFlutterView(Context context) {
            return null;
        }
    
        public FlutterNativeView createFlutterNativeView() {
            return null;
        }
    
        public boolean retainFlutterNativeView() {
            return false;
        }
    
        public final boolean hasPlugin(String key) {
            return this.pluginRegistry.hasPlugin(key);
        }
    
        public final <T> T valuePublishedByPlugin(String pluginKey) {
            return this.pluginRegistry.valuePublishedByPlugin(pluginKey);
        }
    
        public final Registrar registrarFor(String pluginKey) {
            return this.pluginRegistry.registrarFor(pluginKey);
        }
    
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.eventDelegate.onCreate(savedInstanceState);
        }
    
        protected void onStart() {
            super.onStart();
            this.eventDelegate.onStart();
        }
    
        protected void onResume() {
            super.onResume();
            this.eventDelegate.onResume();
        }
    
        protected void onDestroy() {
            this.eventDelegate.onDestroy();
            super.onDestroy();
        }
    
        public void onBackPressed() {
            if(!this.eventDelegate.onBackPressed()) {
                super.onBackPressed();
            }
    
        }
    
        protected void onStop() {
            this.eventDelegate.onStop();
            super.onStop();
        }
    
        protected void onPause() {
            super.onPause();
            this.eventDelegate.onPause();
        }
    
        protected void onPostResume() {
            super.onPostResume();
            this.eventDelegate.onPostResume();
        }
    
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            this.eventDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if(!this.eventDelegate.onActivityResult(requestCode, resultCode, data)) {
                super.onActivityResult(requestCode, resultCode, data);
            }
    
        }
    
        protected void onNewIntent(Intent intent) {
            this.eventDelegate.onNewIntent(intent);
        }
    
        public void onUserLeaveHint() {
            this.eventDelegate.onUserLeaveHint();
        }
    
        public void onTrimMemory(int level) {
            this.eventDelegate.onTrimMemory(level);
        }
    
        public void onLowMemory() {
            this.eventDelegate.onLowMemory();
        }
    
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            this.eventDelegate.onConfigurationChanged(newConfig);
        }
    }
    

    可以看出FlutterActivity也没有setContentView(),并且创建FlutterView也是为null,那么核心逻辑应该在FlutterActivityDelegate

    FlutterActivityDelegate.class
    
    public void onCreate(Bundle savedInstanceState) {
            if(VERSION.SDK_INT >= 21) {
                Window window = this.activity.getWindow();
                window.addFlags(-2147483648);
                window.setStatusBarColor(1073741824);
                window.getDecorView().setSystemUiVisibility(1280);
            }
    
            String[] args = getArgsFromIntent(this.activity.getIntent());
            FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
            this.flutterView = this.viewFactory.createFlutterView(this.activity);
            if(this.flutterView == null) {
                FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
                this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
                this.flutterView.setLayoutParams(matchParent);
                this.activity.setContentView(this.flutterView);
                this.launchView = this.createLaunchView();
                if(this.launchView != null) {
                    this.addLaunchView();
                }
            }
    
            if(!this.loadIntent(this.activity.getIntent())) {
                String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
                if(appBundlePath != null) {
                    this.runBundle(appBundlePath);
                }
    
            }
        }
    
    1. 有个关键的方法FlutterMain.ensureInitializationComplete(),下面分析。
    2. 接着看创建FlutterView。this.viewFactory.createFlutterNativeView()最终来到FlutterActivity.createFlutterNativeView(),结果返回的为null,所以FlutterNativeView的创建是在FlutterView中,下面分析。
    3. 创建了flutterView后,用了setContentView(this.flutterView),所以整个activity的布局就是一个surfaceView
    4. 运行的方法this.runBundle(appBundlePath);,最后分析。
    FlutterMain.ensureInitializationComplete()
    FlutterMain.class
    
        public static void ensureInitializationComplete(Context applicationContext, String[] args) {
            if(Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
            } else if(sSettings == null) {
                throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
            } else if(!sInitialized) {
                try {
                    sResourceExtractor.waitForCompletion();
                    List<String> shellArgs = new ArrayList();
                    shellArgs.add("--icu-symbol-prefix=_binary_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());
                    }
    
                    String appBundlePath = findAppBundlePath(applicationContext);
                    String appStoragePath = PathUtils.getFilesDir(applicationContext);
                    String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
                    nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);
                    sInitialized = true;
                } catch (Exception var6) {
                    Log.e("FlutterMain", "Flutter initialization failed.", var6);
                    throw new RuntimeException(var6);
                }
            }
        }
    

    方法作用在创建FlutterView之前先确保FlutterMain初始化完成,就是FlutterMain.startInitialization()要完成,关于此方法分析见上文。
    关键的检查方法是sResourceExtractor.waitForCompletion();,在资源初始化完成后进行nativeInit,此时调用了C++层的方法init,开始初始化。

    FlutterView

    接着if(this.flutterView == null) 的判断,这里需要创建FlutterView。
    FlutterView不是直接继承View,而是SurfaceView,相关知识可以自行搜索。
    android SurfaceView 详解

    FlutterView.class
    
        public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
            super(context, attrs);
            this.nextTextureId = new AtomicLong(0L);
            this.mIsSoftwareRenderingEnabled = false;
            this.mAccessibilityEnabled = false;
            this.mTouchExplorationEnabled = false;
            this.mAccessibilityFeatureFlags = 0;
            Activity activity = (Activity)this.getContext();
            if(nativeView == null) {
                this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
            } else {
                this.mNativeView = nativeView;
            }
    
            this.dartExecutor = new DartExecutor(this.mNativeView.getFlutterJNI());
            this.mNativeView.getFlutterJNI();
            this.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
            this.mAnimationScaleObserver = new FlutterView.AnimationScaleObserver(new Handler());
            this.mMetrics = new FlutterView.ViewportMetrics();
            this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
            this.setFocusable(true);
            this.setFocusableInTouchMode(true);
            this.mNativeView.attachViewAndActivity(this, activity);
            this.mSurfaceCallback = new Callback() {
                public void surfaceCreated(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
                }
    
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
                }
    
                public void surfaceDestroyed(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
                }
            };
            this.getHolder().addCallback(this.mSurfaceCallback);
            this.mAccessibilityManager = (AccessibilityManager)this.getContext().getSystemService("accessibility");
            this.mActivityLifecycleListeners = new ArrayList();
            this.mFirstFrameListeners = new ArrayList();
            this.navigationChannel = new NavigationChannel(this.dartExecutor);
            this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
            this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
            this.systemChannel = new SystemChannel(this.dartExecutor);
            this.settingsChannel = new SettingsChannel(this.dartExecutor);
            this.mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.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.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel);
            this.setLocales(this.getResources().getConfiguration());
            this.sendUserPlatformSettingsToDart();
        }
    

    onCreate()比较关键的有

    1. 创建FlutterNativeView
    2. 初始化DartExecutor,JNI的创建在下面FlutterNativeView提到。
    3. 设置surfaceView的回调,通过FlutterJNI使得与Java层和dart层的状态同步。
    4. 创建系统的native插件,关于插件的分析会另起一文。
    FlutterNativeView

    FlutterNativeView不是View,它是与C++层进行消息传递的媒介,实现了BinaryMessenger,二进制消息传递方法。

    public interface BinaryMessenger {
        void send(String var1, ByteBuffer var2);
    
        void send(String var1, ByteBuffer var2, BinaryMessenger.BinaryReply var3);
    
        void setMessageHandler(String var1, BinaryMessenger.BinaryMessageHandler var2);
    
        public interface BinaryReply {
            void reply(ByteBuffer var1);
        }
    
        public interface BinaryMessageHandler {
            void onMessage(ByteBuffer var1, BinaryMessenger.BinaryReply var2);
        }
    }
    

    由类源码可知,定义消息发送、处理消息、设置消息处理器、响应消息的接口或者方法。在FlutterNativeView实现。

    FlutterNativeView.class
    
     public FlutterNativeView(Context context) {
            this(context, false);
        }
    
        public FlutterNativeView(Context context, boolean isBackgroundView) {
            this.mNextReplyId = 1;
            this.mPendingReplies = new HashMap();
            this.mContext = context;
            this.mPluginRegistry = new FlutterPluginRegistry(this, context);
            this.mFlutterJNI = new FlutterJNI();
            this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
            this.mFlutterJNI.setPlatformMessageHandler(new FlutterNativeView.PlatformMessageHandlerImpl());
            this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
            this.attach(this, isBackgroundView);
            this.assertAttached();
            this.mMessageHandlers = new HashMap();
        }
    

    可知

    1. 创建了插件的注册者
    2. 创建了FlutterJNI用于与C++层进行交互
    3. 关键方法attach(this, isBackgroundView);
    FlutterNativeView.attach()
    FlutterNativeView.class
    
        private void attach(FlutterNativeView view, boolean isBackgroundView) {
            this.mFlutterJNI.attachToNative(isBackgroundView);
        }
    
    FlutterJNI.class
    
        @UiThread
        public void attachToNative(boolean isBackgroundView) {
            this.ensureNotAttachedToNative();
            this.nativePlatformViewId = Long.valueOf(this.nativeAttach(this, isBackgroundView));
        }
    
        private native long nativeAttach(FlutterJNI var1, boolean var2);
    

    最终会调用C++层的AttachJNI()

    static jlong AttachJNI(JNIEnv* env,
                           jclass clazz,
                           jobject flutterJNI,
                           jboolean is_background_view) {
      fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
      auto shell_holder = std::make_unique<AndroidShellHolder>(
          FlutterMain::Get().GetSettings(), java_object, is_background_view);
      if (shell_holder->IsValid()) {
        return reinterpret_cast<jlong>(shell_holder.release());
      } else {
        return 0;
      }
    }
    

    attach成功后会返回nativePlatformViewId,用于标志attach过,供一些方法可用于检查。

        private void ensureNotAttachedToNative() {
            if(this.nativePlatformViewId != null) {
                throw new RuntimeException("Cannot execute operation because FlutterJNI is attached to native.");
            }
        }
    
        private void ensureAttachedToNative() {
            if(this.nativePlatformViewId == null) {
                throw new RuntimeException("Cannot execute operation because FlutterJNI is not attached to native.");
            }
        }
    

    至此,Java层初始化核心逻辑大致说完,还剩下一个运行的方法。

    FlutterActivityDelegate.runBundle(appBundlePath)
    FlutterActivityDelegate.class
    
        public void onCreate(Bundle savedInstanceState) {
            if(VERSION.SDK_INT >= 21) {
                Window window = this.activity.getWindow();
                window.addFlags(-2147483648);
                window.setStatusBarColor(1073741824);
                window.getDecorView().setSystemUiVisibility(1280);
            }
    
            String[] args = getArgsFromIntent(this.activity.getIntent());
            FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
            this.flutterView = this.viewFactory.createFlutterView(this.activity);
            if(this.flutterView == null) {
                FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
                this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
                this.flutterView.setLayoutParams(matchParent);
                this.activity.setContentView(this.flutterView);
                this.launchView = this.createLaunchView();
                if(this.launchView != null) {
                    this.addLaunchView();
                }
            }
    
            if(!this.loadIntent(this.activity.getIntent())) {
                String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
                if(appBundlePath != null) {
                    this.runBundle(appBundlePath);
                }
    
            }
        }
    
    FlutterActivityDelegate.class
    
    private void runBundle(String appBundlePath) {
            if(!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
                FlutterRunArguments args = new FlutterRunArguments();
                ArrayList<String> bundlePaths = new ArrayList();
                ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
                if(resourceUpdater != null) {
                    File patchFile = resourceUpdater.getInstalledPatch();
                    JSONObject manifest = resourceUpdater.readManifest(patchFile);
                    if(resourceUpdater.validateManifest(manifest)) {
                        bundlePaths.add(patchFile.getPath());
                    }
                }
    
                bundlePaths.add(appBundlePath);
                args.bundlePaths = (String[])bundlePaths.toArray(new String[0]);
                args.entrypoint = "main";
                this.flutterView.runFromBundle(args);
            }
    
        }
    
    FlutterView.class
    
        public void runFromBundle(FlutterRunArguments args) {
            this.assertAttached();
            this.preRun();
            this.mNativeView.runFromBundle(args);
            this.postRun();
        }
    
    FlutterNativeView.class
    
        public void runFromBundle(FlutterRunArguments args) {
            boolean hasBundlePaths = args.bundlePaths != null && args.bundlePaths.length != 0;
            if(args.bundlePath == null && !hasBundlePaths) {
                throw new AssertionError("Either bundlePath or bundlePaths must be specified");
            } else if((args.bundlePath != null || args.defaultPath != null) && hasBundlePaths) {
                throw new AssertionError("Can't specify both bundlePath and bundlePaths");
            } else if(args.entrypoint == null) {
                throw new AssertionError("An entrypoint must be specified");
            } else {
                if(hasBundlePaths) {
                    this.runFromBundleInternal(args.bundlePaths, args.entrypoint, args.libraryPath);
                } else {
                    this.runFromBundleInternal(new String[]{args.bundlePath, args.defaultPath}, args.entrypoint, args.libraryPath);
                }
    
            }
        }
    
    FlutterNativeView.class
    
        private void runFromBundleInternal(String[] bundlePaths, String entrypoint, String libraryPath) {
            this.assertAttached();
            if(this.applicationIsRunning) {
                throw new AssertionError("This Flutter engine instance is already running an application");
            } else {
                this.mFlutterJNI.runBundleAndSnapshotFromLibrary(bundlePaths, entrypoint, libraryPath, this.mContext.getResources().getAssets());
                this.applicationIsRunning = true;
            }
        }
    

    最后还是调用FlutterJNI.runBundleAndSnapshotFromLibrary(),并设置启动标志为true。

    FlutterJNI.class
    
        @UiThread
        public void runBundleAndSnapshotFromLibrary(@NonNull String[] prioritizedBundlePaths, @Nullable String entrypointFunctionName, @Nullable String pathToEntrypointFunction, @NonNull AssetManager assetManager) {
            this.ensureAttachedToNative();
            this.nativeRunBundleAndSnapshotFromLibrary(this.nativePlatformViewId.longValue(), prioritizedBundlePaths, entrypointFunctionName, pathToEntrypointFunction, assetManager);
        }
    
        private native void nativeRunBundleAndSnapshotFromLibrary(long var1, @NonNull String[] var3, @Nullable String var4, @Nullable String var5, @NonNull AssetManager var6);
    
    platform_view_android_jni.cc
    
    static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
                                                jobject jcaller,
                                                jlong shell_holder,
                                                jobjectArray jbundlepaths,
                                                jstring jEntrypoint,
                                                jstring jLibraryUrl,
                                                jobject jAssetManager) {
      auto asset_manager = std::make_shared<blink::AssetManager>();
      for (const auto& bundlepath :
           fml::jni::StringArrayToVector(env, jbundlepaths)) {
        if (bundlepath.empty()) {
          continue;
        }
    
        // If we got a bundle path, attempt to use that as a directory asset
        // bundle or a zip asset bundle.
        const auto file_ext_index = bundlepath.rfind(".");
        if (bundlepath.substr(file_ext_index) == ".zip") {
          asset_manager->PushBack(std::make_unique<blink::ZipAssetStore>(
              bundlepath, "assets/flutter_assets"));
    
        } else {
          asset_manager->PushBack(
              std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
                  bundlepath.c_str(), false, fml::FilePermission::kRead)));
    
          // Use the last path component of the bundle path to determine the
          // directory in the APK assets.
          const auto last_slash_index = bundlepath.rfind("/", bundlepath.size());
          if (last_slash_index != std::string::npos) {
            auto apk_asset_dir = bundlepath.substr(
                last_slash_index + 1, bundlepath.size() - last_slash_index);
    
            asset_manager->PushBack(std::make_unique<blink::APKAssetProvider>(
                env,                       // jni environment
                jAssetManager,             // asset manager
                std::move(apk_asset_dir))  // apk asset dir
            );
          }
        }
      }
    
      auto isolate_configuration = CreateIsolateConfiguration(*asset_manager);
      if (!isolate_configuration) {
        FML_DLOG(ERROR)
            << "Isolate configuration could not be determined for engine launch.";
        return;
      }
    
      RunConfiguration config(std::move(isolate_configuration),
                              std::move(asset_manager));
    
      {
        auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint);
        auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl);
    
        if ((entrypoint.size() > 0) && (libraryUrl.size() > 0)) {
          config.SetEntrypointAndLibrary(std::move(entrypoint),
                                         std::move(libraryUrl));
        } else if (entrypoint.size() > 0) {
          config.SetEntrypoint(std::move(entrypoint));
        }
      }
    
      ANDROID_SHELL_HOLDER->Launch(std::move(config));
    }
    

    可见最后走到C++层的Launch(),后面开始启动的逻辑,这里不再展开了。

    总结

    1. 在FlutterApplication中调用FlutterMain.startInitialization()开始初始化,初始化一些配置和加载so库,在C++层动态注册供Java使用的方法,同时也获取Java的类和方法。
    2. FlutterActivity创建FlutterActivityDelegate用与处理所有逻辑。
    3. FlutterNativeView创建FlutterJNI进行attach C++层、创建插件注册者进行插件消息的管理等。
    4. FlutterView创建FlutterNativeView、创建PlatformPlugin管理平台插件等。
    5. FlutterActivityDelegate.onCreate()中进行C++层的init、创建FlutterView、setContentView()、最后调用runBundle()开始启动App。

    相关文章

      网友评论

        本文标题:Flutter初始化分析(二)

        本文链接:https://www.haomeiwen.com/subject/fiyqbqtx.html