“互联网+”
技术服务解决方案提供商

0371-61875577

react native设计原理与填坑记录

react
刘大可 2019-07-22T01:19:41.000Z
318 1 2

react native设计原理与填坑记录
使用react native也有几个年头了,之前都是看别的大神总结的文章,今天也来自己总结下rn的设计原理和自己碰到的很多的“坑”。也算是给大家一些问题个例,个人觉得原理没什么可看的,但是坑却是实实在在的爬出来的,万一你现在的问题跟我这个撞衫了,不是就不用再去爬那么多资料了对吧!

镇楼图:N年前自己写的第一段代码
1.png

#react native原理

这部分就简单描述一下吧,毕竟太多大神都写过既完善又深入的文章了。毕竟跨平台框架的思想都是想通的,不管借鉴的谁家的设计思想(PS:前端为啥都喜欢抄React),总之想要达到的目标都是一致的!那就是: Write one , Run anywhere!(虽然Facebook说是learn once, run everywhere,但我觉得这句可能更恰当)。
        不闲扯了,直接上图

2.png

图片来自网络:作者:breaktian。侵权删除(我太懒…懒得画了,毕竟类似图太多了,而且画的还没人家好!-.-)。
        这张图基本诠释了rn如何运行的,图为OC部分,当然Android有一样的映射机制,无非就是映射组件的名字换一下。react native基于实时的翻译机制,你写下的所有模块都有对应的原生模块,最后使用webpack打包出来就是个js的bundle资源文件,rn的所有框架就是为了解释运行这个js 脚本文件,当然还有js 扩展的API, 则是直接通过bridge(此处是rn自己封装的桥接,并非web通用的brigde)调用native方法; 如果是UI界面, 则映射到virtual DOM这个虚拟的JS数据结构中,通过bridge 传递到native , 然后根据数据属性设置各个对应的真实native的View。 这样说吧,你写的所有rn模块,都会通过rn来调用对应的原生方法。 不过不同于js Patch,你不可以动态改变调用原生api的代码(桥接部分),因为像苹果这些厂商都为了防止你动态改变调用api,主要是怕你动态调用一些私有api,影响了它的生(收)态(入)。所以对调用原生api部分的代码,也就是你桥接的原生部分,你是无法动态改变的,这也就是rn热更局限的部分。不过这已有的东西已经够我们大部分业务发挥了。

js-native通信机制简介

3.png

js-native通信桥接具体过程
        JavaScript代码可以创建一个,你自己定义模块的NativeEventEmitter实例来订阅这些事件。通过约定固定的方法名字符串,实现双边api调用,通过定义模块:RCT_EXPORT_MODULE()导出native模块到js,简单来说就是存了一个同名的js常量字符串在映射表中,如果你不传入参数,那么你在iOS中导出的模块名就是类名,你也可以插入参数作为自定义模块名。为了桥接js跟native,native层引入了RCTBridge这个类负责双方的通信,不过起作用的是RCTBatchedBridge这个类,这是个比较重要的类。RN层Libraries/BatchedBridge包下面有3个JS文件:BatchedBridge.js、MessageQueue.js、NativeModules.js,它们封装了通信桥在RN层的实现。通过这样一套 api-桥接(字符串方法映射)-native Api,建立起一套完整的通信机制,具体的js-native的类型映射如下图(取自官方文档)。具体的还可以在这些通信中加入一些钩子了类似的高级用法,喜欢的可以自行去百度。
4.png
js-native桥接类型映射
        话外题说一下,就是当初闹的沸沸扬扬的禁止热更这个事情。首先呢,苹果爸爸是允许热更的,有Apple’s developer agreement为证。不过必须是静默更新。当初那个热更被下架(js Patch表示很难受)事件,主要是苹果怕你动态改变api调用用到一些不(私)该(有)用(的)东西上。因为你反过来想想,AppStore营收里游戏占大头好吧(具体说句不记得了,前两年貌似百分八十??),如果热更完全禁了,游戏先死好吧!所以怎么想都不会跟钱过不去对吧。

好了,rn设计原理到此为止,别问我为什么写这么少,网上一搜资料一堆。写的全是重复的,没什么意义对吧,我又不一定比人家写的都好对吧。

But! 下面我会把我到现在为止碰到的问题、报错特征、排查过程、具体原因,全部列出来,相信这些基本不说独一无二吧,但应该你随便百度搜搜是出不来了。相信还是有一定意义的。往下看之前,建议一定要有一定的rn或者跨平台开发经验,不然看着没什么意义。
填坑记录
        前言:现在rn版本经过社区维护越来越趋于完善,我提到的大部分问题,都是有对应的版本的,在新的版本中,很有可能就已经修复了,所以当你当前版本是老版本而且无暇去升级,但又需要修复这些问题时,可能对你很有帮助。

react-native-link失败 全版本
        在集成很多rn第三方时候,他都会指导你使用react-native-link这个命令。不过讲道理,失败率很高。因为各个项目集成情况都不一致,Android成功率很高,因为基本都是一种集成方式。而iOS有用CocoaPod和本地两种集成方式,这两种编译时对React先后顺序可能不一样。如果link之后报错-lReact缺失:将pod中React项目在target中提升至最前面,或者删除多余Search header(偶然间发现这个貌似也有影响)。
        尤其注意一点,link命令只在于按照rn官方目录结构下使用,就是node_modole和iOS/android同级,不然有时候不报错,但就是没效果。

Android桥接原生View改变LayoutParam无效 0.44
症状:桥接原生UI到rn使用,如果在js中调用桥接方法去改变原生UI模块的frame,iOS有效,Android无效果,移除有效,添加新UI无效。
原因:在桥接后rn将Android的UI绘制方法重写,在你改变Android原生LayoutParam的时候,这些组件重走requestLayout的时候并不会主动重新计算组件大小,所以你无论如何改变,都是原UI大小,而且新添的组件size永远是0,0。
办法:重写requestLayout,重新计算frame。如图
5.png
这个算是巨坑,碰到的都难受
Code-push私服问题 0.44
症状:用到Code-push私服时候,私服地址https://github.com/lisong/code-push-server。iOS集成过程中,有缺失DiffMatchPatch.h文件,手动添加后有arc引用问题和添加-fno-objc-arc标记。这些都是常规排错,iOS干过一些的应该都能找出来。坑在Android,由于Android使用的是旧版本代码,但是这个库里的Android代码集成后报jsBundle找不到,最终问题是Android引用的rn库文件缺失。
原因:私服库代码与rn版本库未一致(重点是私服库并没有标志使用哪个版本)
办法:只能去官方Code-push库里找到你对应rn版本的库文件,然后对本地的Code-push库文件替换,就可以了。
打包上传小米Monkey lineNumber报错
rn官方报错,0.59.5被修复,以下版本Monkey测试均可能出现,传送门:https://github.com/facebook/react-native/issues/24382

报错截图
6.png
结尾
        作为公司发展博客,希望在座各位可以多多献计献策,多交流,在促进公司积极氛围的同时,也可补充自己的知识盲区。能看到不一样的技术范畴和技能点,其实是一件很好的事儿。一边能享受大家在一起聊天唠嗑的乐趣,一边还能充实自己的见闻,偶尔如果能碰撞出点新奇的点子当然就更好了。
最后放一句我很喜欢的话:
Keep calm and carry on,just coding!

2
2

点击展开全文

0/200

全部评论

  • 现实与梦境

    感谢填坑!!!

    2019-07-24T11:47:25.000Z
    0
    1

查看更多