React native热更新思路(一)之ReactNativeHost类解析【适用于Android开发者】

来源:互联网 发布:js 上传照片插件 编辑:程序博客网 时间:2024/06/06 20:35

        React Native发展到今天,之所以受到大家的青睐一个最重要的原因就是它支持动态更新,并且这种动态更新的方式较原生的来看要方便的很多。所以今天我将带领大家来看看React native是如何实现动态更新的。

      首先我们一起来看看ReactNativeHost类到底写了些什么?

/** * Simple class that holds an instance of {@link ReactInstanceManager}. This can be used in your * {@link Application class} (see {@link ReactApplication}), or as a static field. */public abstract class ReactNativeHost {  private final Application mApplication;  private @Nullable ReactInstanceManager mReactInstanceManager;  protected ReactNativeHost(Application application) {    mApplication = application;  }  /**   * 获取一个react native的核心管理类的的对象   */  public ReactInstanceManager getReactInstanceManager() {    if (mReactInstanceManager == null) {      mReactInstanceManager = createReactInstanceManager();    }    return mReactInstanceManager;  }  /**   * Get whether this holder contains a {@link ReactInstanceManager} instance, or not. I.e. if   * {@link #getReactInstanceManager()} has been called at least once since this object was created   * or {@link #clear()} was called.   */  public boolean hasInstance() {    return mReactInstanceManager != null;  }  /**   * Destroy the current instance and release the internal reference to it, allowing it to be GCed.   */  public void clear() {    if (mReactInstanceManager != null) {      mReactInstanceManager.destroy();      mReactInstanceManager = null;    }  }
  /**   * 构建 ReactInstanceManager 对象,ReactInstanceManager会在下次详细介绍   */
protected ReactInstanceManager createReactInstanceManager() { ReactInstanceManager.Builder builder = ReactInstanceManager.builder() .setApplication(mApplication) .setJSMainModuleName(getJSMainModuleName()) .setUseDeveloperSupport(getUseDeveloperSupport()) .setRedBoxHandler(getRedBoxHandler()) .setUIImplementationProvider(getUIImplementationProvider()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE); for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); }
  /**   * 今天的重点,判断是否存在jsbundle,如果存在则加载,反之则加载assets中的jsbundle
   * 这里是热更新的开始 具体如何判断请看getJSBundleFile方法   */
String jsBundleFile = getJSBundleFile(); if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile); } else { builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())); } return builder.build(); } /** * Get the {@link RedBoxHandler} to send RedBox-related callbacks to. */ protected @Nullable RedBoxHandler getRedBoxHandler() { return null; } protected final Application getApplication() { return mApplication; } /** * Get the {@link UIImplementationProvider} to use. Override this method if you want to use a * custom UI implementation. * * Note: this is very advanced functionality, in 99% of cases you don't need to override this. */ protected UIImplementationProvider getUIImplementationProvider() { return new UIImplementationProvider(); } /** * Returns the name of the main module. Determines the URL used to fetch the JS bundle * from the packager server. It is only used when dev support is enabled. * This is the first file to be executed once the {@link ReactInstanceManager} is created. * e.g. "index.android" */ protected String getJSMainModuleName() { return "index.android"; } /** * 这里可以设置你的最新jsbundle进来 */ protected @Nullable String getJSBundleFile() { return null; } /** * Returns the name of the bundle in assets. If this is null, and no file path is specified for * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will * always try to load the JS bundle from the packager server. * e.g. "index.android.bundle" */ protected @Nullable String getBundleAssetName() { return "index.android.bundle"; } /** * Returns whether dev mode should be enabled. This enables e.g. the dev menu. */ protected abstract boolean getUseDeveloperSupport(); /** * Returns a list of {@link ReactPackage} used by the app. * You'll most likely want to return at least the {@code MainReactPackage}. * If your app uses additional views or modules besides the default ones, * you'll want to include more packages here. */ protected abstract List<ReactPackage> getPackages();}

代码中有关热更新的地方我都用红色字体做了中文注释

看完ReactNativeHost类的代码,我们大致可以了解到React native的确为我们提供了热更新的功能,并且我们只需要实现ReactNativeHost类的同时去重写两个方法即可,如下

protected @Nullable String getJSBundleFile() {  return null;}
protected String getJSMainModuleName() {  return "index.android";}

最新版的React native为我们提供了一个ReactApplication,我们只需要继承它去实现getReactNativeHost方法就可以将我们的重写好的ReactNativeHost配置进去,这样就初步搭建好了React native的热更新


下面我们一起来找找这里面的坑

 1.这里没有具体介绍jsbundle的校验问题,每个人的校验方式都不同,也有很多方式,不懂得可以百度

 2.有人可能会疑惑,ReactNativeHost是在Application中配置好的,如果说程序运行过程中有新的jsbundle下载到本地,那我应该如何去加载它呢?

       作者一开始也想着手动去调用一下加载的方法,可是怎么都没找到,后来看了codepush源码之后,发现他们利用类反射去调用了一个叫recreateReactContextInBackground的方法,后来又去查看这个方法的源码才明白这样是完全可行的【切记在UI thread 中去调用它】

/** * Recreate the react application and context. This should be called if configuration has * changed or the developer has requested the app to be reloaded. It should only be called after * an initial call to createReactContextInBackground. * * Called from UI thread. */public void recreateReactContextInBackground() {  Assertions.assertCondition(      mHasStartedCreatingInitialContext,      "recreateReactContextInBackground should only be called after the initial " +          "createReactContextInBackground call.");  recreateReactContextInBackgroundInner();}
 3.资源文件该怎么办呢?

       其实React native已经为我们提供好了资源文件的加载,我们只需要将最新的资源文件和你的jsbundle保存在相同的路径下即可,具体的实现大家可以看React native image加载本地图片的实现源码。

 4.是否有源码可以分享出来?

       前段时间写了一个,只是将热更新的流程走通了,还有一些功能要逐步完善,有兴趣的可以一起GitHub

   

   今天大致带大家了解了下ReactNativeHost到底做了哪些事,对于初学RN的伙伴来说,利用今天分享完全可以体验到React native的热更新功能。

   希望对大家有帮助     

   QQ群581621024


1 0
原创粉丝点击