react-native启动流程(android端)
一、前言
好吧,其实就是想看看rn在android上是怎么启动的,因为我是个android攻城师,出于对新技术的追求(公司项目需要),我开始了我的rn之旅。我想在搜索这篇文章的你应该也是一个对android有一定基础的同学,也该有一定的基础,这样你才能看下去,若是没有,我不建议你继续阅读下去(那是浪费时间)。
二、分析前的场景介绍
为了更好的(没有干扰)的分析启动流程,我们新建一个空白的rn项目,通过react-native init testGradle命令生成一个名为testGradle的新的rn项目,该命令会为按照一定的结构生成一些目录和文件,进入我们熟悉的android>app>src.main.java.com.testgradle目录,我们会看到已经为我们默认生成了一个MainActivity.java和MainApplication.java两个文件,通过文件的后缀我们不难猜想到这两个java类分别继承了Activity和Application这两个类,在这儿我得说一下,rn生成的在android上的应用和原生java写的android应用在本质上没什么区别,因此我可以用分析android应用启动的流程方式来分析rn生成的应用在android上的启动流程。
三、分析步骤
1.MainApplication.java
熟悉android应用启动流程的同学应该知道,android应用在启动(调用生命周期方法onCreate)第一个Activity之前会先创建一个全局唯一的Application对象,关于application对象的创建时机分析,没有在网上找到合适的文章,等我有空再补上吧,这篇文章是关于Android应用程序启动过程源代码分析也提到了application的创建,不过文章比较长,但的确写的很好,大神之做,建议细细品味!
首先来分析下MainApplication.java这个文件, 它的继承结构如下
image.png
在MainApplication对象创建时,创建成员变量mReactNativeHost对象,进而注入了一些配置,主要注入配置如下:
- getUseDeveloperSupport() 配置是否开启调试
- getPackages() 配置要加载的模块
- getJSMainModuleName() 配置js模块的入口文件名
2.MainActivity.java 进入主要启动流程
这个activity是第一个启动的activity,我们通过它来分析启动流程
Step 1.ReactActivityDelegate.loadApk()
ReactActivityDelegate类的的说明如下
Delegate class for {@link ReactActivity} and {@link ReactFragmentActivity}. You can subclass this
to provide custom implementations for e.g. {@link #getReactNativeHost()}, if your Application
class doesn't implement {@link ReactApplication}.
英文不太好,就不献丑了,请自行理解。
ReactActivityDelegate.java的源代码位置为react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java
protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); }
这一步主要完成了三件事:
- 创建了一个mReactRootView对象,它是一个ViewGroup的子类
- mReactRootView.startReactApplication()开启rn初始化,并获得或者创建一个ReactInstanceManager对象
- 通过 getPlainActivity().setContentView(mReactRootView);为当前它所代理的Activity设置显示的view
在进行mReactRootView.startReactApplication()之前,我们来分析下该方法的三个参数:
- ReactInstanceManager ,非常重要的一个对象,用于管理react中的instance;
- moduleName,我们这是"testGradle",它必须与js模块中通过AppRegistry.registerComponent()方法注入的名称一致;
- initialProperties,Bundle类型对象,用于传递一些初始化属性值;
ReactInstanceManager对象在创建时会对一些管理的对象进行默认的初始化,所以它的创建过程很重要,我们先来看看它的创造流程
Step 2.ReactNativeHost.getReactInstanceManager()
ReactNativeHost.java的源代码位置为react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java
//获取单列的ReactInstanceManager对象 public ReactInstanceManager getReactInstanceManager() { if (mReactInstanceManager == null) { mReactInstanceManager = createReactInstanceManager(); } return mReactInstanceManager; }
ReactInstanceManager对象是全局唯一的
Step 3.ReactNativeHost.createReactInstanceManager()
//用Builder模式创建一个ReactInstanceManager对象 protected ReactInstanceManager createReactInstanceManager() { ReactInstanceManagerBuilder builder = ReactInstanceManager.builder() .setApplication(mApplication)//设置Application对象,这儿就是MainApplication对象 .setJSMainModulePath(getJSMainModuleName())//设置js模块的入口文件名 .setUseDeveloperSupport(getUseDeveloperSupport())//设置是否支持调试 .setRedBoxHandler(getRedBoxHandler())//设置 .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory()) .setUIImplementationProvider(getUIImplementationProvider()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);//设置当前最开始的生命周期状态 for (ReactPackage reactPackage : getPackages()) {//收集所有模块 builder.addPackage(reactPackage); } String jsBundleFile = getJSBundleFile();//获取要加载的JSBundleFile文件的路径,这个方法是热更新的关键方法 if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile);//从自定义路径获取JSBundleFile文件 } else { //加载默认路径(android项目assets目录)下的文件名为"index.android.bundle"的JSBundleFile文件,若是文件不存在,程序直接抛出error并退出。 builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())); } return builder.build(); }
上面代码主要做了两件事:
- 创建一个ReactInstanceManagerBuilder对象,并通过该对象进行一些参数设置
- 调用ReactInstanceManagerBuilder对象的build()方法创造ReactInstanceManager对象
我们接下里继续分析ReactInstanceManagerBuilder的build()方法
step 4.ReactInstanceManagerBuilder.build()
ReactRootView.java源代码位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
public ReactInstanceManager build() { Assertions.assertNotNull( mApplication, "Application property has not been set with this builder"); Assertions.assertCondition( mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null, "JS Bundle File or Asset URL has to be provided when dev support is disabled"); Assertions.assertCondition( mJSMainModulePath != null || mJSBundleAssetUrl != null || mJSBundleLoader != null, "Either MainModulePath or JS Bundle File needs to be provided"); if (mUIImplementationProvider == null) { // create default UIImplementationProvider if the provided one is null. mUIImplementationProvider = new UIImplementationProvider(); } // We use the name of the device and the app for debugging & metrics String appName = mApplication.getPackageName(); String deviceName = getFriendlyDeviceName(); return new ReactInstanceManager( mApplication,//就是MainApplication mCurrentActivity,//就是MainaActivity mDefaultHardwareBackBtnHandler,//物理返回键的处理类,这儿是null mJavaScriptExecutorFactory == null//java层js调用执行器,持有一些c++/java的混合对象 ? new JSCJavaScriptExecutorFactory(appName, deviceName) : mJavaScriptExecutorFactory, (mJSBundleLoader == null && mJSBundleAssetUrl != null)//JSBundle文件的信息存储类,CatalystInstance用它来加载正确的JSBundle文件 ? JSBundleLoader.createAssetLoader( mApplication, mJSBundleAssetUrl, false /*Asynchronous*/) : mJSBundleLoader, mJSMainModulePath,//这儿为默认值"index.android"; mPackages,//一个Arraylist集合,收集了所有的模块的package mUseDeveloperSupport,//是否支持调试 mBridgeIdleDebugListener,//监听bridge的状态(空闲和忙碌) Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),//检查生命周期状态是否设置,若没有设置,则给出提示,并中断程序 mUIImplementationProvider,// mNativeModuleCallExceptionHandler,//js调用本地模块时的异常,可以自行定义异常处理方式 mRedBoxHandler,//一个监听接口,通过它可以在DevSupportManagerImpl中拦截到开发状态下的异常信息 mLazyNativeModulesEnabled,// mLazyViewManagersEnabled, mDelayViewManagerClassLoadsEnabled, mDevBundleDownloadListener, mMinNumShakes, mMinTimeLeftInFrameForNonBatchedOperationMs); }
上面代码进行主要做了两件事:
- 创建ReactInstanceManager对象前,检查必要的设置是否已经调用
- 创建ReactInstanceManager对象,并注入一些对象
接下来调用了ReactInstanceManager的构造函数进行创建对象,构造函数中又有一些重要对象的初始化,我们来看看
step 5.ReactInstanceManager构造函数
ReactRootView.java源代码位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
/* package */ ReactInstanceManager( Context applicationContext, @Nullable Activity currentActivity, @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler, JavaScriptExecutorFactory javaScriptExecutorFactory, @Nullable JSBundleLoader bundleLoader, @Nullable String jsMainModulePath, List packages, boolean useDeveloperSupport, @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, LifecycleState initialLifecycleState, UIImplementationProvider uiImplementationProvider, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, @Nullable RedBoxHandler redBoxHandler, boolean lazyNativeModulesEnabled, boolean lazyViewManagersEnabled, boolean delayViewManagerClassLoadsEnabled, @Nullable DevBundleDownloadListener devBundleDownloadListener, int minNumShakes, int minTimeLeftInFrameForNonBatchedOperationMs) { Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()"); initializeSoLoaderIfNecessary(applicationContext); DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext); mApplicationContext = applicationContext; mCurrentActivity = currentActivity; mDefaultBackButtonImpl = defaultHardwareBackBtnHandler; mJavaScriptExecutorFactory = javaScriptExecutorFactory; mBundleLoader = bundleLoader; mJSMainModulePath = jsMainModulePath; mPackages = new ArrayList<>(); mInitFunctions = new ArrayList<>(); mUseDeveloperSupport = useDeveloperSupport; mDevSupportManager = DevSupportManagerFactory.create( applicationContext, createDevHelperInterface(), mJSMainModulePath, useDeveloperSupport, redBoxHandler, devBundleDownloadListener, minNumShakes); mBridgeIdleDebugListener = bridgeIdleDebugListener; mLifecycleState = initialLifecycleState; mMemoryPressureRouter = new MemoryPressureRouter(applicationContext); mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; mLazyNativeModulesEnabled = lazyNativeModulesEnabled; mDelayViewManagerClassLoadsEnabled = delayViewManagerClassLoadsEnabled; synchronized (mPackages) { PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages"); mPackages.add( new CoreModulesPackage( this, new DefaultHardwareBackBtnHandler() { @Override public void invokeDefaultOnBackPressed() { ReactInstanceManager.this.invokeDefaultOnBackPressed(); } }, uiImplementationProvider, lazyViewManagersEnabled, minTimeLeftInFrameForNonBatchedOperationMs)); if (mUseDeveloperSupport) { mPackages.add(new DebugCorePackage()); } mPackages.addAll(packages); } // Instantiate ReactChoreographer in UI thread. ReactChoreographer.initialize(); if (mUseDeveloperSupport) { mDevSupportManager.startInspector();//处于开发模式,则开启 } }
上面代码主要做了四件事:
- 将构造函数传入的数据赋值给相应的变量
- 创建一个mDevSupportManager对象,用于开发模式的交互
- 创建一个CoreModulesPackage类型对象,封装了对物理返回键的默认处理功能,如果处于开发模式,则加入DebugCorePackage功能模块
接下来我们继续回到step1中的mReactRootView.startReactApplication()方法
step 5.ReactRootView.startReactApplication()
ReactRootView.java源代码位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties) { ...... UiThreadUtil.assertOnUiThread();//判断是否是在ui线程,不是就抛异常,中断程序 Assertions.assertCondition( mReactInstanceManager == null, "This root view has already been attached to a catalyst instance manager"); mReactInstanceManager = reactInstanceManager;//持有reactInstanceManager mJSModuleName = moduleName; mAppProperties = initialProperties; if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { mReactInstanceManager.createReactContextInBackground();//初始化ReactContext } attachToReactInstanceManager();//将自己关联到ReactInstanceManager对象上 ...... }
上面这步主要完成了三件事:
- 将传入的三个参数reactInstanceManager、moduleName、initialProperties赋值给了ReactRootView对象
- 开始初始化话ReactContext
- 将自己关联到ReactInstanceManager对象上,
当前场景下mReactInstanceManager.hasStartedCreatingInitialContext()为false,我们进入 mReactInstanceManager.createReactContextInBackground()。
step 6.ReactInstanceManager.createReactContextInBackground()
ReactRootView.java源代码位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
public void createReactContextInBackground() { Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()"); //mHasStartedCreatingInitialContext用于标识createReactContextInBackground()方法是否调用过 Assertions.assertCondition( !mHasStartedCreatingInitialContext, "createReactContextInBackground should only be called when creating the react " + "application for the first time. When reloading JS, e.g. from a new file, explicitly" + "use recreateReactContextInBackground"); mHasStartedCreatingInitialContext = true; recreateReactContextInBackgroundInner(); }
上面这步做了两件事
- 判断createReactContextInBackground()是否已经调用过了,是则抛出异常,中断程序
- 将createReactContextInBackground()方法是已经被调用的flag设置为true,并调用recreateReactContextInBackgroundInner()进行ReactContext创造流程
step 7.ReactInstanceManager.recreateReactContextInBackgroundInner()
private void recreateReactContextInBackgroundInner() { Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()"); PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground"); UiThreadUtil.assertOnUiThread();//保证在主线程运行 if (mUseDeveloperSupport && mJSMainModulePath != null && !Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) { final DeveloperSettings devSettings = mDevSupportManager.getDevSettings(); // If remote JS debugging is enabled, load from dev server. if (mDevSupportManager.hasUpToDateJSBundleInCache() && !devSettings.isRemoteJSDebugEnabled()) { // If there is a up-to-date bundle downloaded from server, // with remote JS debugging disabled, always use that. onJSBundleLoadedFromServer(); } else if (mBundleLoader == null) { mDevSupportManager.handleReloadJS(); } else { mDevSupportManager.isPackagerRunning( new PackagerStatusCallback() { @Override public void onPackagerStatusFetched(final boolean packagerIsRunning) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { if (packagerIsRunning) { mDevSupportManager.handleReloadJS(); } else { // If dev server is down, disable the remote JS debugging. devSettings.setRemoteJSDebugEnabled(false); recreateReactContextInBackgroundFromBundleLoader(); } } }); } }); } return; } recreateReactContextInBackgroundFromBundleLoader(); }
由于mUseDeveloperSupport为true,mJSMainModulePath 为"index.android",Systrace.isTracing()为false
未完待续......
更多相关文章
- Android(安卓)集成 FFmpeg (四) 轻松实现一个音视频编辑 App
- android:apk版本的的比对、下载、安装
- Android(安卓)Service 优先级
- 通过OTA的方式在局域网分发iOS应用
- android之MediaPlayer播放音频或者视频文件
- Android(安卓)APK文件在电脑(PC虚拟机)上面运行方法
- Android(安卓)打包及引用 aar 文件的方法
- android下用itext修改pdf模板文件
- Android开发之 混淆加固和反编译