当前位置: 首页 > article >正文

ReactNative 启动应用(2)

ReactNative 启动应用

简述

本节我们来看一下ReactNative在Android上启动Activity的流程,ReactNative在Android上也是一个Apk,它的实现全部都在应用层,所以它肯定也是符合我们Android应用的启动流程的,UI页面的载体也是一个Activity,然后启动JS引擎来加载index.js,执行javascript的代码,然后javascript通过Fabric渲染器和TurboModule执行到java代码,调用到最终的Native实现,本节我们就来看一下启动的这个过程。

Application启动

1.1 MainApplication.init
ReactNative的能力被包装为Package,Package里面包含一些Module,每个Module是一个子能力,后续介绍TurboModule的时候会介绍包加载的流程。

class MainApplication : Application(), ReactApplication {

    // 主要就是构建了DefaultReactNativeHost和ReactHost
    override val reactNativeHost: ReactNativeHost =
        object : DefaultReactNativeHost(this) {
            override fun getPackages(): List<ReactPackage> =
                // 这里加载了所有包
                PackageList(this).packages.apply {
                // Packages that cannot be autolinked yet can be added manually here, for example:
                // add(MyReactNativePackage())
                }
            
            override fun getJSMainModuleName(): String = "index"

            override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

            override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
            override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
        }
    // 详见1.2
    override val reactHost: ReactHost
        get() = getDefaultReactHost(applicationContext, reactNativeHost)

    override fun onCreate() {
        super.onCreate()
        SoLoader.init(this, false)
        if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
            load()
        }
    }
}

1.2 getDefaultReactHost
调用ReactNativeHost.toReactHost构造ReactHost。

@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(
    context: Context,
    reactNativeHost: ReactNativeHost,
): ReactHost {
    require(reactNativeHost is DefaultReactNativeHost) {
    "You can call getDefaultReactHost only with instances of DefaultReactNativeHost"
    }
    //详见1.3
    return reactNativeHost.toReactHost(context)
}

1.3 toReactHost
调用了getDefaultReactHost

@UnstableReactNativeAPI
internal fun toReactHost(context: Context): ReactHost =
    // 详见1.4
    DefaultReactHost.getDefaultReactHost(
        context,
        packages,
        jsMainModuleName,
        bundleAssetName ?: "index",
        isHermesEnabled ?: true,
        useDeveloperSupport,
    )

1.4 getDefaultReactHost
初始化了JS引擎,加载了js代码,还构建了DefaultReactHostDelegate,最终会把这些信息封装到一个ReactHostImpl中,ReactHost建立了React和Activity一些交互的接口。

@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(
    context: Context,
    packageList: List<ReactPackage>,
    jsMainModulePath: String = "index",
    jsBundleAssetPath: String = "index",
    isHermesEnabled: Boolean = true,
    useDevSupport: Boolean = ReactBuildConfig.DEBUG,
    cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
): ReactHost {
    // 构建ReactHostImpl
    if (reactHost == null) {
        // 创建jsBundleLoader,这个是用来执行JS代码的
        val jsBundleLoader =
            JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true)
        // 创建JS引擎
        val jsRuntimeFactory = if (isHermesEnabled) HermesInstance() else JSCInstance()
        val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()
        cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) }
        // 构建DefaultReactHostDelegate
        val defaultReactHostDelegate =
            DefaultReactHostDelegate(
                jsMainModulePath = jsMainModulePath,
                jsBundleLoader = jsBundleLoader,
                reactPackages = packageList,
                jsRuntimeFactory = jsRuntimeFactory,
                turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder)
        val componentFactory = ComponentFactory()
        DefaultComponentsRegistry.register(componentFactory)
        // 创建ReactHostImpl,详见1.5
        reactHost =
            ReactHostImpl(
                    context,
                    defaultReactHostDelegate,
                    componentFactory,
                    true /* allowPackagerServerAccess */,
                    useDevSupport,
                )
                .apply {
                    jsEngineResolutionAlgorithm =
                        if (isHermesEnabled) {
                        JSEngineResolutionAlgorithm.HERMES
                        } else {
                        JSEngineResolutionAlgorithm.JSC
                        }
                }
    }
    return reactHost as ReactHost
}

1.5 ReactHostImpl
构建了一个DevSupportManager。

public ReactHostImpl(
    Context context,
    ReactHostDelegate delegate,
    ComponentFactory componentFactory,
    Executor bgExecutor,
    Executor uiExecutor,
    boolean allowPackagerServerAccess,
    boolean useDevSupport) {
    mContext = context;
    mReactHostDelegate = delegate;
    mComponentFactory = componentFactory;
    mBGExecutor = bgExecutor;
    mUIExecutor = uiExecutor;
    mQueueThreadExceptionHandler = ReactHostImpl.this::handleHostException;
    mMemoryPressureRouter = new MemoryPressureRouter(context);
    mAllowPackagerServerAccess = allowPackagerServerAccess;
    mUseDevSupport = useDevSupport;
    // debug版本和release版本,分别构建不同的SupportManager
    if (mUseDevSupport) {
        mDevSupportManager =
            new BridgelessDevSupportManager(
                ReactHostImpl.this, mContext, mReactHostDelegate.getJsMainModulePath());
    } else {
        mDevSupportManager = new ReleaseDevSupportManager();
    }
}

Application中主要是初始化了一些React的对象,主要就是一个ReactHostImpl,ReactHostImpl里面持有了JS代码和引擎,以及要加载的包信息等等。

Activity启动

2.1 ReactActivity.onCreate
调了ReactActivityDelegate的onCreate

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 详见2.2
    mDelegate.onCreate(savedInstanceState);
}

2.2 ReactActivityDelegate.onCreate
构建ReactDelegate,会根据flag构建ReactDelegate传入不同的参数,我们跟新架构的路径。
ReactDelegate会持有ReactHost或者ReactNativeHost,新架构是前者,老架构师后者。

public void onCreate(Bundle savedInstanceState) {
    String mainComponentName = getMainComponentName();
    final Bundle launchOptions = composeLaunchOptions();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled()) {
        mActivity.getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
    }
    if (ReactFeatureFlags.enableBridgelessArchitecture) {
        // 详见2.3
        mReactDelegate =
            new ReactDelegate(getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
    } else {
        mReactDelegate =
            new ReactDelegate(
                getPlainActivity(),
                getReactNativeHost(),
                mainComponentName,
                launchOptions,
                isFabricEnabled()) {
                    @Override
                    protected ReactRootView createRootView() {
                        ReactRootView rootView = ReactActivityDelegate.this.createRootView();
                        if (rootView == null) {
                            rootView = super.createRootView();
                        }
                        return rootView;
                    }
            };
    }
    if (mainComponentName != null) {
        // 详见2.3
        loadApp(mainComponentName);
    }
}

2.3 ReactActivityDelegate.loadApp
构建根View,配置给Activity。

protected void loadApp(String appKey) {
    // 详见2.4
    mReactDelegate.loadApp(appKey);
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

2.4 ReactDelegate.loadApp
这里一样有两套逻辑,新架构一套老架构一套,我们还是看新架构的流程。
这里构建了一个ReactSurfaceImpl,ReactSurfaceImpl里面会持有一个ReactSurfaceView,ReactSurfaceView是一个FrameLayout的子类,作为根View。
然后调用了mReactSurface.start来初始化。

public void loadApp(String appKey) {
    // With Bridgeless enabled, create and start the surface
    if (ReactFeatureFlags.enableBridgelessArchitecture) {
    if (mReactSurface == null) {
        // 构建了一个ReactSurfaceImpl和ReactSurfaceView,ReactSurfaceImpl持有ReactSurfaceView  
        // ReactSurfaceView本质就是一个FrameLayout
        mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);
        mActivity.setContentView(mReactSurface.getView());
    }
    // 启动ReactSurfaceImpl,详见2.5
    mReactSurface.start();
    } else {
    if (mReactRootView != null) {
        throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
        getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
    }
}

2.5 ReactSurfaceImpl.start
这里的Task是ReactNative自己写的一套逻辑,封装了异步调用的能力,功能类似于RXJava,就不详细看了,只要知道这是干啥用的就可以。
大致就是在mBGExecutor线程池里面调用getOrCreateStartTask返回的Task,然后等任务完成后回调getResult。
逻辑在getOrCreateStartTask里。

public TaskInterface<Void> start() {
    // 详见2.6
    return Task.call(this::getOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
}

2.6 ReactSurfaceImpl.getOrCreateStartTask
主要就是通过waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance的Task

private Task<Void> getOrCreateStartTask() {
    final String method = "getOrCreateStartTask()";
    if (mStartTask == null) {
    log(method, "Schedule");
    mStartTask =
        // 调用waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance,首次就会构建,后续使用缓存,详见2.7
        waitThenCallGetOrCreateReactInstanceTask()
            .continueWithTask(
                (task) -> {
                    if (task.isFaulted()) {
                    mReactHostDelegate.handleInstanceException(task.getError());
                    // 如果出现异常则调用DestoryTask。
                    return getOrCreateDestroyTask(
                            "getOrCreateStartTask() failure: " + task.getError().getMessage(),
                            task.getError())
                        .continueWithTask(destroyTask -> Task.forError(task.getError()))
                        .makeVoid();
                    }
                    return task.makeVoid();
                },
                mBGExecutor);
    }
    return mStartTask;
}

2.7 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
直接调用了waitThenCallGetOrCreateReactInstanceTaskWithRetries重载函数

@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTask() {
    // 调用重载函数,传入参数为重试次数,详见2.8
    return waitThenCallGetOrCreateReactInstanceTaskWithRetries(0, 4);
}

2.8 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
这里最终调用了getOrCreateReactInstanceTask来创建 创建ReactInstance的Task,也就是说其实最终是通过getOrCreateReactInstanceTask返回的Task里面的任务来创建ReactTask,其他的代码都是负责处理辅助逻辑,如失败重试,失败销毁,切换线程执行等。

@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTaskWithRetries(
    int tryNum, int maxTries) {
    final String method = "waitThenCallGetOrCreateReactInstanceTaskWithRetries";
    if (mReloadTask != null) {
        log(method, "React Native is reloading. Return reload task.");
        return mReloadTask;
    }

    if (mDestroyTask != null) {
        // 如果失败后重试次数没到最大重试次数,还可以重试
        boolean shouldTryAgain = tryNum < maxTries;
        if (shouldTryAgain) {
            log(
                method,
                "React Native is tearing down."
                    + "Wait for teardown to finish, before trying again (try count = "
                    + tryNum
                    + ").");
            return mDestroyTask.onSuccessTask(
                (task) -> waitThenCallGetOrCreateReactInstanceTaskWithRetries(tryNum + 1, maxTries),
                mBGExecutor);
        }

        raiseSoftException(
            method,
            "React Native is tearing down. Not wait for teardown to finish: reached max retries.");
    }
    // 调用getOrCreateReactInstanceTask来创建ReactInstance,详见2.9
    return getOrCreateReactInstanceTask();
}

2.9 ReactSurfaceImpl.getOrCreateReactInstanceTask
ReactInstance代表着React的一个实例,里面持有了FabricUIManager,TurboModuleManager等,且提供了loadJSBundle执行JS代码,是React在Java侧最重要的管理类了。
这里最终调用了instance.loadJSBundle来执行JS代码。

@ThreadConfined("ReactHost")
private Task<ReactInstance> getOrCreateReactInstanceTask() {
    final String method = "getOrCreateReactInstanceTask()";
    log(method);

    return mCreateReactInstanceTaskRef.getOrCreate(
        () -> {
        log(method, "Start");
        ReactMarker.logMarker(
            ReactMarkerConstants.REACT_BRIDGELESS_LOADING_START, BRIDGELESS_MARKER_INSTANCE_KEY);
        // 获取JsBundleLoder,最终是通过这个来执行JS代码的,这个JsBundleLoader就是我们在Application初始化ReactHost的时候创建的那个。
        return getJsBundleLoader()
            .onSuccess(
                task -> {
                    // 前面Task完成后会进onSuccess,task.getResult可以拿到前面方法的返回值,就是JsBundleLoader
                    final JSBundleLoader bundleLoader = task.getResult();
                    final BridgelessReactContext reactContext = getOrCreateReactContext();
                    final DevSupportManager devSupportManager = getDevSupportManager();
                    reactContext.setJSExceptionHandler(devSupportManager);

                    log(method, "Creating ReactInstance");
                    // 构建ReactInstance,这里初始化了很多内容,比较重要的有FabricUIManager,TurboModuleManager
                    final ReactInstance instance =
                        new ReactInstance(
                            reactContext,
                            mReactHostDelegate,
                            mComponentFactory,
                            devSupportManager,
                            mQueueThreadExceptionHandler,
                            mUseDevSupport,
                            getOrCreateReactHostInspectorTarget());
                    mReactInstance = instance;

                    instance.initializeEagerTurboModules();

                    MemoryPressureListener memoryPressureListener =
                        createMemoryPressureListener(instance);
                    mMemoryPressureListener = memoryPressureListener;
                    mMemoryPressureRouter.addMemoryPressureListener(memoryPressureListener);

                    log(method, "Loading JS Bundle");
                    // 执行JS代码,详见2.10
                    instance.loadJSBundle(bundleLoader);
                    // ...

                    return new Result();
                },
                mBGExecutor)
            .onSuccess(
                task -> {
                    // ...流转生命周期
                    return reactInstance;
                },
                mUIExecutor);
        });
}

2.10 ReactInstance.loadJSBundle
这里逻辑挺绕的,这里会调用JSBundleLoader的loadScript,JSBundleLoader是在1.4通过createAssetLoader创建的,是一个匿名内部类,里面就是调用了JSBundleLoaderDelegate.loadScriptFromAssets,JSBundleLoaderDelegate是loadscript的一个入参,是这里的匿名内部类,随意就是执行了这里的loadScriptFromAssets。

public void loadJSBundle(JSBundleLoader bundleLoader) {
    // Load the JS bundle
    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstance.loadJSBundle");
    bundleLoader.loadScript(
        new JSBundleLoaderDelegate() {
        @Override
        public void loadScriptFromFile(
            String fileName, String sourceURL, boolean loadSynchronously) {
            mBridgelessReactContext.setSourceURL(sourceURL);
            loadJSBundleFromFile(fileName, sourceURL);
        }

        @Override
        public void loadSplitBundleFromFile(String fileName, String sourceURL) {
            loadJSBundleFromFile(fileName, sourceURL);
        }

        @Override
        public void loadScriptFromAssets(
            //执行的是这,我们在编译后会将js打包到assets目录下,这里就是执行入口。
            AssetManager assetManager, String assetURL, boolean loadSynchronously) {
            mBridgelessReactContext.setSourceURL(assetURL);
            // 详见2.11
            loadJSBundleFromAssets(assetManager, assetURL);
        }

        @Override
        public void setSourceURLs(String deviceURL, String remoteURL) {
            mBridgelessReactContext.setSourceURL(deviceURL);
        }
        });
    Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}



public static JSBundleLoader createAssetLoader(
    final Context context, final String assetUrl, final boolean loadSynchronously) {
    return new JSBundleLoader() {
    @Override
    public String loadScript(JSBundleLoaderDelegate delegate) {
        delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
        return assetUrl;
    }
    };
}

2.11 ReactInstance.loadJSBundleFromAssets
这个是native方法,映射到C++层是JReactInstance::loadJSBundleFromAssets。

void JReactInstance::loadJSBundleFromAssets(
    jni::alias_ref<JAssetManager::javaobject> assetManager,
    const std::string& assetURL) {
    const int kAssetsLength = 9; // strlen("assets://");
    auto sourceURL = assetURL.substr(kAssetsLength);

    auto manager = extractAssetManager(assetManager);
    // 加载asset内的文件,将结果存在script
    auto script = loadScriptFromAssets(manager, sourceURL);
    // 最终调用的C++层的ReactInstance::loadScript
    instance_->loadScript(std::move(script), sourceURL);
}

2.12 ReactInstance::loadScript
这里调用了JSCRuntime.evaluateJavaScript,这里就到了JSI到逻辑了,JSI是使用JS引擎提供的api封装的轻量级框架,用于提供Ojbect-C和JS或者C++和JS通信,我们这里就不继续深入了,后面会有专门一节介绍JSI。
这里调用JSI接口执行JS代码,就到了index.js了,后续index.js代码是怎么最终通知Native构建View以及显示的逻辑我们在Fabric渲染器章节再来介绍。

void ReactInstance::loadScript(
    std::unique_ptr<const JSBigString> script,
    const std::string& sourceURL) {
auto buffer = std::make_shared<BigStringBuffer>(std::move(script));
std::string scriptName = simpleBasename(sourceURL);

runtimeScheduler_->scheduleWork(
    [this,
    scriptName,
    sourceURL,
    buffer = std::move(buffer),
    weakBufferedRuntimeExecuter = std::weak_ptr<BufferedRuntimeExecutor>(
        bufferedRuntimeExecutor_)](jsi::Runtime& runtime) {
        try {
        SystraceSection s("ReactInstance::loadScript");
        bool hasLogger(ReactMarker::logTaggedMarkerBridgelessImpl);
        if (hasLogger) {
            ReactMarker::logTaggedMarkerBridgeless(
                ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
        }
        // 调用JSCRuntime.evaluateJavaScript,这就到了JSI层了,我们这里暂时不继续看了,后面会有一节专门讲JSI
        runtime.evaluateJavaScript(buffer, sourceURL);
        if (hasLogger) {
            ReactMarker::logTaggedMarkerBridgeless(
                ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
            ReactMarker::logMarkerBridgeless(
                ReactMarker::INIT_REACT_RUNTIME_STOP);
            ReactMarker::logMarkerBridgeless(ReactMarker::APP_STARTUP_STOP);
        }
        if (auto strongBufferedRuntimeExecuter =
                weakBufferedRuntimeExecuter.lock()) {
            strongBufferedRuntimeExecuter->flush();
        }
        } catch (jsi::JSError& error) {
            jsErrorHandler_->handleFatalError(error);
        }
    });
}

小结

通过上面的介绍,我们知道了ReactNative的Android app是怎么启动并且最终执行到JS到index.js代码,中间我们跳过了一些逻辑,比如加载TruboModule包,且后面index.js执行后又是怎么通知到Native侧,让应用更新对应的View布局,以及JSI是怎么通过JS引擎提供的接口实现JS和C++层通信,这些我们会在后面的章节来介绍。


http://www.kler.cn/news/367964.html

相关文章:

  • C++线程池手写实现
  • 2024 7月算法刷题记录
  • OpenTelemetry 实际应用
  • 技术总结(十四)
  • JS面试八股文(一)
  • vue3 树型视图,利用自定义SFC来定义一个TreeItem,然后进行渲染出一个树形。
  • 【Linux操作系统】Linux配置OpenSSH服务器步骤记录
  • 【Linux】操作系统初步理解与Linux指令入门
  • CesiumJS 案例 P6:添加图片图层、添加图片图层并覆盖指定区域
  • Kafka文档阅读笔记之基本操作
  • js构造函数和原型对象,ES6中的class,四种继承方式
  • FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误
  • 宝塔-修改docker加速镜像-daemon.json配置文件格式错误!
  • android 与网页交互通过网页修改宿主布局和异常处理——未来之窗行业应用跨平台架构
  • 【OpenAI】第五节(图像生成)利用 OpenAI 的 DALL·E 实现自动化图像生成:从文本到图像的完整教程
  • 【报错解决】C++ 出现错误error: default argument given for parameter的解决办法
  • 15分钟学 Go 第 14 天:切片
  • 详细解读 CVPR2024:VideoBooth: Diffusion-based Video Generation with Image Prompts
  • Matlab 疲劳检测系统【源码 GUI】
  • HarmonyOS 相对布局(RelativeContainer)
  • 【达梦数据库】两台或多台服务器之间免密登录设置-【dmdba用户】
  • 【Ubuntu更换镜像源】
  • 机器视觉-相机、镜头、光源(总结)
  • 48页PPT数字政府智慧政务一网通办解决方案
  • vue2 使用环境变量
  • 34. 在排序数组中查找元素的第一个和最后一个位置