首页 > 编程语言 >APP中RN页面热更新流程-ReactNative源码分析

APP中RN页面热更新流程-ReactNative源码分析

时间:2023-05-18 22:55:54浏览次数:47  
标签:原生 APP bundle js 源码 RN JS

平时使用WebStorm或VSCode对RN工程中的文件修改后,在键盘上按一下快捷cmd+s进行文件保存,此时当前调试的RN页面就会自动进行刷新,这是RN开发相比于原生开发一个很大的优点:热更新。 那么,从按一下快捷cmd+s到RN页面展示出最新的JS页面,这个过程是怎样发生的呢?下面根据时间顺序来梳理一下。 这里约定后面说的原生部分是指iOS端,ReactNative源码分析指的是iOS端集成的RN框架分析。   原生APP中RN页面的热更新简要流程 React Native应用包含两部分:原生代码和JavaScript代码。JavaScript和原生代码通信的桥梁是Bridge,而Bridge的实现又依赖于JSThread的runloop。 当JS有消息要传递给原生时,它会把消息封装成事件放入到JSThread的runloop的事件队列中,而JSThread的runloop会监听消息队列中的事件,一旦有事件需要处理,就会将其交给Bridge处理,从而实现JavaScript和原生代码的相互调用和数据传输。   基于JavaScript和原生代码的消息传递机制,RN热更新步骤如下: 1.在iOS原生中的RN页面触发热更新时,首先是JS环境中的websocket收到了Metro服务器的通知,在这个通知中包含了需要更新的JS bundle的URL地址,然后js将这个通知事件放到了JSThread的runloop中传到了RCTCxxBridge。 2.RCTCxxBridge收到热更新事件后,调用JavaScriptCore框架中的方法来执行一个JavaScript脚本,这个脚本会告诉JavaScript环境去下载新的JS bundle并执行它。事件又回到了JS。 3.JavaScript环境调用下载命令向远程服务器请求新的JS bundle,事件又被转回到了原生侧。 4.原生侧下载最新的bundle.js,下载完成后调用加载,执行js方法。 5.重新设置RN页面的根组件。   热更新触发条件 React Native在调试模式下有两种热更新方式:Hot Reloading和Live Reload。Hot Reloading可以实现代码的增量更新,而Live Reload技术则是全量更新。 下面以在index.js中新增一个组件注册语句为例。 在RN项目中index.js是ReactNative项目的入口文件,RN启动时首先会执行这个文件,把组件注册到AppRegistry中,这里在index.js的文件底部顺序添加一个组件注册,然后按快捷键cmd+s保存修改

AppRegistry.registerComponent('FlatListDemo', () => FlatListDemo);
这时本地的Packager服务会监听本地文件系统的变化,当有文件修改并保存时,Packager会运行RN命令行工具,自动生成一个新的bundle文件
react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --assets-dest ios
然后将生成的bundle文件上传至服务器,接着Metro 服务器通过 WebSocket 链接发送消息给APP应用程序。

 

触发热更新

在APP中RN框架启动时,会在APP的JS运行上下文中创建一个websocket链接并与js服务器建立连接,它用于监听Metro服务器发来的bundle.js更新通知。 当Packger打了新的bundle.js并上传到js服务器后,Metor服务器就会向与它链接的websocket发送更新通知,js引擎收到服务器的通知后,就会做后续的事件处理。 具体js建立websocket的代码如下: 在iOS端ReactNative框架中,RCTCxxBridge文件中的+ (void)runRunLoop方法内负责创建并运行JS引擎对应的jsThread的runloop。它在APP启动时被创建,用来处理js引擎的任务和事件,并保证了_jsThread的常驻,不被销毁。 runloop被注册时机在RN框架启动时: js引擎收到服务器的通知后,被包成一个原生runloop的事件源放入到事件队列中,然后jsThread的runloop开始处理事件。 然后把事件加入到RCTMessageThread中进行异步处理 RCTCxxBridge调用js脚本,让js处理与最新bundle.js下载相关的事件。把事件传入到js事件队列中 js引擎处理完JS层面的事件后,将事件转回给原生,让原生代码执行实际的下载工作 原生侧的RCTDevSettings模块的reloadWithReason:方法进行处理。调用ReloadCommand监听的触发器,进行触发reloadCommand命令 RCTReloadCommand发送didReceiveReloadCommand收到下载指令 接着调用RCTBridge中的didReceiveReloadCommand方法,RCTBridge中销毁之前的js缓存,调用setUp进行js环境重置,js资源下载 js资源下载完成后,执行js代码 js资源reload完成后,调用js引擎,展示目标组件 当js文件加载成功后,APP会重新创建一个RCTRootContentView, 并将旧的移除,把新的添加上去。新的RCTRootContentView.reactTag使用规则递增
- (void)bundleFinishedLoading:(RCTBridge *)bridge
{
  RCTAssert(bridge != nil, @"Bridge cannot be nil");
  if (!bridge.valid) {
    return;
  }
  
  [_contentView removeFromSuperview];
  _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
                                                    bridge:bridge
                                                  reactTag:self.reactTag
                                            sizeFlexiblity:_sizeFlexibility];
  [self runApplication:bridge];
  
  _contentView.passThroughTouches = _passThroughTouches;
  [self insertSubview:_contentView atIndex:0];
  
  if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) {
    self.intrinsicContentSize = self.bounds.size;
  }
}
  
- (void)runApplication:(RCTBridge *)bridge
{
  NSString *moduleName = _moduleName ?: @"";
  NSDictionary *appParameters = @{
    @"rootTag" : _contentView.reactTag,
    @"initialProps" : _appProperties ?: @{},
  };
  
  RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters);
  [bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[ moduleName, appParameters ] completion:NULL];
}
  

至此,APP中RN页面的热更新主要流程结束。

 

标签:原生,APP,bundle,js,源码,RN,JS
From: https://www.cnblogs.com/zhou--fei/p/17410767.html

相关文章

  • LearnPrompt:开源的prompt学习网站
    这个GitHub开源项目,打算手把手教你成为一名提示工程师。理论与实例结合,浅显易懂,可以免费学习,关键还是中文!如果觉得GitHub界面看起来不方便,还可以到搭建好的网站里去学。即使是纯小白,有了它,学习起来也十分轻松。ChatGPT、Midjourney、StableDiffusion等热门AI工具应有尽有。......
  • 深入理解之JavaScript之call, apply, bind方法
    在JavaScript中,call、apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。Function.prototype.call()call()方法调用一个函数,其具有一个指定的this值和多个参数(参数的列表)。fun.call(thisArg,a......
  • Sentinel基本使用与源码分析
    系列文章目录和关于我一丶什么是SentinelSentinel官网Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。流量整形:限制流......
  • 东邻到家小程序|东邻到家小程序源码|东邻到家小程序开发功能
    上门服务这几年已经越来越火爆,不论是家政、按摩、美甲等等都在不断的发展上门服务,这几年东邻到家小程序系统在不断的摸索阶段,对于系统各方面的需求也在不断提升,东郊到家小程序通过线上匹配用户和技师的需求,让人们可以更加容易的享受上门服务,下面小编就给大家介绍下东邻到家小程序系......
  • APP-Notes
    常用ADB命令#查看当前PC连接的设备号adbdevices#进入设备adbshell#退出设备Ctrl+D或exit#进入指定设备adbconnect设备号例:adbconnect127.0.0.1:52001(同一局域网下使用)adb-s设备号例:adb-semulator-554shell(通过USB数据线连接下使用)#查询设备的ID和序列......
  • 软件测试系列:移动端安卓APP测试必备之ADB命令 (二)
    adb常见命令1、查看日志adblogcat-vtime表示打印时间adblogcat-vcolor表示使用不同的颜色来显示每个优先级adblogcat-f<filename>表示将日志输出到文件(文件存在手机上),例如,adblogcat-f/sdcard/log.logadblogcat>log.log表示保存日志到PC上adblogca......
  • 第四十届中国软件质量大会:APP专项测试
    结合我自身的经验与本次大会宋琦(俊逸)老师的讲解,我将从以下几个方面来说为什么进行APP专项测试和如何进行。1.什么是专项测试,手机的专项测试有哪些?   专项测试是为了与区分pc端开来,移动端所特有的,例如:弱网,安装升级卸载,系统兼容(安卓(各个厂商),ios),系统交互,性能等;2.为什么进行专项......
  • 8 Kubernetes Scanner to find Security Vulnerability and Misconfiguration
    https://geekflare.com/kubernetes-security-scanner/YouareusingKubernetes.Great!Howaboutitssecurity?WeallknowthatKuberneteshasbecomeoneofthebestcontainerorchestrationplatformstoday.Morethan80%oforganizationstodayareleveraging......
  • RocketMQ源码(三):服务端NameSrv启动流程
    有关Namesrv的概念及功能,详见RocketMQ(三):架构设计中技术架构组成namesrv,这里不再赘述。RocketMQ中Namesrv启动入口:org.apache.rocketmq.namesrv.NamesrvStartup。Namesrv启动,NamesrvStartup#main0()核心伪代码:1publicstaticNamesrvControllermain0(String[......
  • Machine Learning:什么是谷歌云功能
    推荐:将NSDT场景编辑器加入你的3D工具链3D工具集:NSDT简石数字孪生行动和反应。 简而言之,这就是GoogleCloudFunctions。但是,当然,由于这并不能涵盖此服务很酷的所有方式,因此让我们更详细地介绍一下。在本文中,我将更详细地概述GoogleCloudFunctions,比较第一代和第二代环境,并讨......