58车商通RN落地实践

引言

开发已经经历了几个阶段,从Native App 到 WebApp大火,再到苹果公司禁Web,又发展到了Hybrid的Web与原生共生。再到React Native,这种利用Js 转成原生的取中方案。

React Native 说到底还是调用Native原生,所以效率损耗的话很接近原生开发。所以目前很多App 都采用了RN开发,本文将就58车商通介绍下RN在其中的应用场景,以及发展阶段

RN开发背景

58车商通

58车商通是58体系下的为车商打造的一款工具类App,帮助车商高效的管理自己的车辆。
主要功能包括:

  1. 发布车源(核心功能)帮助车商快速发布车源,和主App 58同城起到相辅相成的作用。需求变化比较频繁,开始采用原生开发,但是无法满足需求的频繁变化,于是2017年改版为Hybrid。后续考虑改版为RN

  2. 库存管理(核心功能)帮助车商高效的管理自己的车辆,包括已经发布的,已经售出的,已经下架的,等等,以及定价,预警等相关功能。需求变化相对稳定。

  3. 客户管理(核心功能)帮助车商管理自己的客户,区分出客户的购买意向程度,以及后续沟通等等。变化频率相对稳定

  4. 营销推广(核心功能)帮助车商推广车辆,包括置顶,刷新服务等,变化频率相对较高

总结:58车商通是58集团二手车部门的一个重要的App产物,帮助车商方便管理自己的车源,随时发布,同步其他市场。而 RN 模块第一次尝试放在了车商通的每日任务模块。

为什么会选中每日任务模块

每日任务模块:用户每日登陆之后可以通过每日的任务来赚取积分。用于推广等功能等。

那我们为什么要用每日任务模块来做呢。

首先,每日任务模块体量较轻,入手起来相对比较简单

其次,线上有成熟的h5,如果出现严重问题的话,我们可以及时切换到线上h5进行补救

然后,每日任务模块虽然量轻,但是可以覆盖协议的大部分功能。

最后就是这个模块需求变化相对来说比较快,也可以检验热更新模块。

接下来我们来聊聊RN。

什么是RN?

其实关于RN的概念可能大家也比较清楚了,在这里我们简单的说一下。

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用;

RN的目标是:高效跨平台的开发Native应用;

RN的宗旨是:一次学习,多个平台编写代码;

如下图:我们可以清楚的看到RN是构建在React和JSX的基础上的。

为什么使用RN?

  • 移动设备环境比web设备复杂得多,导致Native开发成本高;
  • 为寻求APP的开发效率、成本、体验之间的平衡,我们之前选择了Hybrid的开发方案,这样既能拥有高效的开发效率,又能快速更新迭代APP;
  • 然而在webview中嵌入HTML页面存在一些性能和体验上的弱势;

这也为技术发展提出了一个新的挑战:如何将开发成本和用户体检做好更好的平衡呢?

基于此我们可以使用React Native来解决,对于前端开发来说,既然H5能够替代原生应用,为什么还要去使用别的技术,但是,实际上来说,H5应用在用户体验和性能上远远无法比拟原生应用的,RN的切入点就是兼顾开发效率和用户体验的;

RN特性:

  1. 提供了原生控件支持

    使用RN可以使用底层原生控件,iOS可以使用UITabBar、UINavigationController等标准的iOS平台组件;在Android平台我们可以使用Drawer控件;这样,就让我们的App从使用上和视觉上拥有像原生App一样的体验

  2. 异步执行

所有的JavaScript逻辑与原生平台之间的所有操作都采用异步执行模式,原生模块使用额外线程

  1. 触屏处理

    RN引入了一个类似于iOS上Responder Chain响应链事件处理机制的响应体系,并基于此为开发者提供了诸如TouchableHighlight等更高级的组件,实现了高性能的图层点击与接触处理

58车商通RN模块整体技术架构

车商通RN整体分为三个部分:

  • 客户端:提供部分基础组件、提供交互协议、支持UI渲染展示页面
  • 服务端:提供业务接口、提供项目bundle下载地址
  • 热更新平台:提供项目bundle文件、支持更新、回滚

####58车商通客户端设计和开发

客户端整体框架如下:

3.1、入口组件

每个应用程序都有一个对应的入口文件,index.js是Android和iOS渲染前端UI的统一入口定义声明UI模块的moduleName:

import { AppRegistry } from "react-native";
import App from "./src/index"; //业务入口AppRegistry.registerComponent("Wuba***", () => App);

把当前APP的前端UI对象注册到AppRegistry组件中;

  • AppRegistry 是运行所有 React Native 应用程序的 JS 入口点

  • 应用程序入口组件需要通过 AppRegistry.registerComponent 来注册它们自身

  • 当注册完应用程序组件后,Native就会加载jsbundle文件并触发AppRegistry.runApplication运行应用

3.2、RN启动流程(以OC 为例)

  1. 创建RCTRootView
    设置窗口的跟控制器的View,把注册的RN模块添加进去
  2. 创建RCTBridge
    桥接对象,管理JS和OC交互
  3. 执行RCTBridge loadSource
    加载前端js代码
  4. 执行RCTBridge initModulesWithDispatchGroup
    创建OC模块表
  5. 执行RCTJSCExecutor injectJSONText
    往JS中插入OC模块表
  6. 执行JS代码,回调OC,调用OC组件
  7. 完成UI渲染

3.3、RN通信机制

这部分内容,其实网上的资料比较多,而我们结合源码,和已经一些已经公开的知识点,简单跟大家分享一下。后续如果大家干兴趣,可以在单拿出一篇文章来分析讨论。下面我们来简单看下RN从JS 端开始调起原生方法的原理(以OC为例)

OC生成一张模块配置表,包含所有模块和模块里的方法,根据特定的标识宏(RCT_EXPORT_MODULE()),将可以暴露的方法暴露给JS。

OC-JS交互流程:(注:此图是网上的示意图,但是表达的意思很明确,所以借用一下)

  1. js调用OC模块暴露出来的方法
  2. 把调用方法分解为ModuleName、MethodName、arguments,在丢给MessageQueue处理
  3. 把js的callback函数缓存在MessageQueue的一个成员变量里面,同时生成一个CallbackID来代表callback;在通过保存在MessageQueue的模块配置表把ModuleName、MethodName转成ModuleID、MethodID
  4. 把ModuleID、MethodID、CallbackID和其他参数传给OC(JavaScriptCore)
  5. OC接到消息,通过模块配置表拿到对于的模块和方法
  6. RCTModuleMethod对js传过来的参数进行处理
  7. OC模块方法执行完,执行block回调
  8. 调用第6步中RCTModuleMethod生成的block
  9. block带着CallbackID和block传过来的参数去掉用js里的MessageQueue方法invokeCallbackAndReturnFlushedQueue
  10. MessageQueue通过CallbackID找到相应的js的callback方法
  11. 调用callback方法,并把OC带过来的参数一起传过去完成回调

以上就是通信交互整个流程,但是在实际业务开发中我们发现,RN提供的基础组件已经不能满足我们的业务开发,部分需要依赖native原生功能来实现比如:模块间的跳转、分享等,这就需要我们与native底层约定一些交互方法来满足各种各样的业务场景,基于此前端封装了一个中间交互的协议层

3.3、交互协议设计

协议层是native和前端对NativeModules进行了一些约定的封装和处理,方便业务使用。

目前前端协议层通过一下几种类型类集中封装的:

  • RN跳转类
  • 调起Native组件类 如:loading、toast等
  • 调起native功能类 如:分享、埋点、定位等

协议约定:

  1. native封装模块宏CST***Component到NativeModules下

  2. 在模块宏CST***Component下声明函数宏 CST–Handler

  3. 函数固定传参两个,第一个是协议交互的所有参数param(jsonString类型),第二个固定传入callback函数

  4. 参数param格式

    param = { action, params };
    也是固定两个参数
    action:唯一确定调起的native组件,都是以CST开头的 如:action = "CST***Web"表示RN跳转H5
    params:协议交互参数,每个协议都有不同的参数,具体协议的参数和native约定 如:
    跳转H5协议传参(具体参数根据业务来制定)
    let params = {url, //h5链接...
    };
    
  5. 回调函数

    CST***Handler的第二个参数就是协议的回调函数,传入function类型
    固定接收两个参数
    (error, event) => {第一个参数error是一个错误对象(没有发生错误的时候为 null)第二个参数event是native返回给前端的具体回调数据(jsonString类型)
    }
    
  6. 根据以上规则 前端统一封装工业务方调用的API接口

3.4、RN页面开发

在上面我们大概了解了RN APP中的启动流程和交互方式,那么如何应用要我们的日常开发中能,下面来介绍一下前端的UI的开发。

3.4.1、本地开发流程

为保证RN版本的匹配,和一些代码规范的统一,在开发自己项目时需要克隆RN种子工程

在开发过程中需要使用到本地调试,下面我们以iOS端为例看看如何进行页面调试

3.4.2、本地调试

1、iOS模拟器启动页面:

2、启动Chrome浏览器调试:

command+D弹出模拟器工具类 选择选项Debug Js Remotely

3、浏览器自动打开链接http://localhost:8081/debugger-ui/

这时能在浏览器上查看所有前端js代码了

4、断点调试

打开目的js文件,找到要调试的函数,直接打断点,当执行该函数时就直接断点拦截了

服务端开发设计

服务端在整个RNAPP中承担的角色,就是为APP提供基本的数据接口服务和提供RN项目资源信息和下载地址;

此处就讲一下RN项目下载更新流程

服务端接口返回数据模型:

{"respData": {"h5Url": "","business": {"version": "90","remoteUrl": "https://***/10021_90_android_business.tgz"},"resource": {"version": "90","remoteUrl": "https://***/10021_90_android_assets.tgz"},"bundleId": "10021","unpacking": true,"downNow": false},"respCode": 0
}

服务端流程如下:

热更新平台设计

5.1、热更新流程

​ 在传统的web开发中,我们修改完js之后在浏览器上就能直接看到效果,JavaScript本身就是一门动态语言,并不需要编译,浏览器每次刷新都拉取新的js文件;针对web应用最简单也最有效的优化就是缓存,当js没有更新,浏览器就不需要下载新的js文件;

​ 在RN实现动态更新也是同样的思路,RN中前端JS代码最终都会打包成jsbundle文件,我们在需求更新时,在应用中从远程下载这个文件,并重新加载,就可以完成动态更新同时无需通过App Store重新发布;

APP RN资源更新流程:

1、APP启动时:

2、启动项目时:

所有前面的更新流程都会依赖于前端的RN资源,那么下面我们来看一下如何把一个项目在平台上录入、编译打包和上线的

5.2、平台资源录入

在项目开发完成,提交到公司Git代码仓库,就可以使用RN资源管理平台录入资源了;

平台功能如下:

项目录入:

在填写完信息后,平台会根据填写的git地址,把当前项目代码下载到服务器,并npm install安装当前项目需要的所有依赖;这个过程因为需要安装项目依赖,所以时间比较长,项目初始化完成就可以对项目编译打包了;

信息录入时,会为每个项目分配一个唯一的ID,也是客户端区分项目的唯一标识。

5.3、打包编译流程

RN项目编译打包流程

打包产物jsbundle

打包之后JSBundle文件的结构,基本分为3部分:

  • 头部:全局定义,主要是define,require等全局模块的定义;
  • 中间:模块定义,RN框架和业务的各个模块定义;
  • 尾部:引擎初始化和入口函数执行;

在RN打包过程中,解析依赖关系,为每个模块添加一个id

1、需求

​ 在实际的RN业务开发中,我们会涉及到很多个业务,这些业务基本上也不会耦合,这时我们就需要创建多个RN项目,每个项目编译打包成独立的bundle;

​ 对于RN APP来说,即使只有一个helloworld页面,在使用官方命令react-native bundle打出来的jsbundle文件大约为530KB以上,RN依赖模块本身就占了99%以上;

​ 如果更新的话,需要从网络上拉取整个包下载时间长,还会海鸥飞用户流量,每次进入RN页面还都要执行RN基础模块的定义;

​ 在RN项目开发中基础库react和react-native是不变的,我们可以抽离这两个依赖打成common.bundle内置于APP中;

2、目标
  • 抽离react和react-native打包成common.bundle
  • 减小线上下发业务bundle体积,减少下载时间、节省用户流量
  • 可预加载common.bundle,提升打开页面速度
3、分析
  • 通过分析bundle结构和依赖查找,最终可以通过标记法进行分包
  • 打包bundle时,根据entryFile进行深度遍历依赖分析,模块id不断递增,即越早引用的模块,id越小
  • 在分析依赖时标记哪些模块属于common.bundle,哪些模块属于业务bundle
  • 打包时先引入base.js保证common.bundle的模块id都在前面,先收集common.bundle的模块
  • 在遍历进行依赖收集,输出业务bundle
//base.js
import React, { Component } from "react";
import {} from "react-native";
4、拆分打包流程

编译打包之后本地项目打包结果如下:

iOS端:

Android端:

5、总结

优点:

  • 一次性打包输出common.bundle和业务bundle,效率高
  • 用户只需下载业务bundle,减少流量消耗和下载时间

缺点:

  • 直接引用react-native作为基础,common中可能会引入一些用不到的模块

总体上利大于弊,开发中也不可预知需要用到react-native哪些模块,直接打包一个全集也未尝不可。

6、展望

理论上我们还可以指定规则,解耦业务,根据不同的业务模块,划分出更多的bundle,每个bundle的模块id按照某个值开始,避免重复,类似android插件化处理资源id策略,按需加载业务bundle。

5.4、项目提测、上线

项目提测流程:

项目上线流程:

5.4、项目回滚

​ 在日常开发中,纵然有多轮测试,也避免不了发布到线上不会存在问题,我们传统的解决方案就是定位问题,找出原因,解决完之后重新发布上线;如果是一个流量很大的需求,同时又出现了线上不容易解决的问题,此时线上就会出现长时间的功能无法使用的情况;这是我们就可以考虑到回滚,先把项目回滚到一个可用的版本,然后再来解决自己的问题。

RN项目回滚流程如下:

React Native开发总结(二)相关推荐

  1. 从 Android 到 React Native 开发(四、打包流程解析和发布为 Maven 库 )

    1.从 Android 到 React Native 开发(一.入门) 2.从 Android 到 React Native 开发(二.通信与模块实现) 3.从 Android 到 React Nat ...

  2. React Native开发错误警告处理总结(已解决 !持续更新)

    注:本文是我在开发过程中遇到问题解决方法的总结,之后会持续更新,希望帮助到更多的学习者.文中有不妥的地方希望指出共同学习,同时欢迎大神补充.(之后我会放出自己开发整理的笔记和GithubDemo地址, ...

  3. React Native开发之——Webstorm开发RN配置

    前言 前文React Native开发之--Webstorm快捷开发介绍了使用Webstorm快捷开发React Native, 本文介绍Webstorm开发RN配置. Webstorm开发RN配置 ...

  4. 在windows上搭建React Native开发环境

    最近要学习React Native,但是在window上搭建开发环境的时候遇到了些问题,以至于一直没有搭建好开发环境. React Native相关项目及文档: react-native的GitHub ...

  5. React Native开发(一)

    本React Native讲解专题:主要讲解了React Native开发,由基础环境搭建配置入门,基础,进阶相关讲解. 关于React Native各种疑难杂症,问题深坑总结方案请点击查看: Mac ...

  6. React Native开发规范(非官方,自己定义的)

    React Native开发规范 一.命名规范 二.代码格式 三.注释规约 四.样式规约 五.Redux 相关操作 六.桥接规约 七.JSX 规约 八.组件规约 九.npm 规约 十.性能优化 一.命 ...

  7. 【转】【React Native开发】

    [React Native开发]React Native控件之ListView组件讲解以及最齐全实例(19)  [React Native开发]React Native控件之Touchable*系列组 ...

  8. windows 下配置 react native 开发环境

    windows 下配置 react native 开发环境 安装nvm 由于react native 需要使用 NodeJs 4.0以上版本,为了方便切换NodeJs,首先我们需要安装nvm. 你可以 ...

  9. React Native开发之必备React基础

    为了帮助大家快速上手React Native开发,在这本节中将向大家介绍开发React Native所需要的一些React必备基础知识. 概述 本节课将从React的特点.如何使用React.JSX语 ...

  10. Windows环境下安装React Native开发环境----记一次填坑过程

    前言 集成React Native开发环境遇到各个坑,调试了很久出现过找不到设备,百度上个别人的资料有误被绕来绕去耽误了很多时间,下载慢等待时间过长等问题,最后多方查阅资料,电脑重启等操作终于部署好了 ...

最新文章

  1. nowcoder119E A Simple Problem
  2. C#程序代码行号设置
  3. 拾遗:不用使 sizeof 获取数组大小
  4. 鼠标动效html,5种纯CSS3鼠标hover按钮动画效果
  5. Java程序员须知:分布式微服务为什么很难?
  6. How does JdkRegexpMethodPointcut work
  7. 长假首日全国热门景区出炉 西湖、天安门、广州塔位列前三
  8. 日志分析(shell脚本)
  9. 使用jQuery快速高效制作网页交互特效(1)
  10. 怎么维护 SQLite
  11. 【手写数字识别】基于matlab GUI知识库手写数字识别(写字板+图片)【含Matlab源码 1227期】
  12. oracle 创建表同时添加注释
  13. Java 3D期末复习第三章——Java 3D 基本图形功能
  14. 中子射线照相检测技术
  15. 东家冲~石池高速公路一阶段施工图设计--长沙理工大学继续教育学院自考道路毕业设计
  16. 流媒体/流媒体文件格式详解
  17. 6个让你10T硬盘立马爆掉的资源网站,再也不需要去百度上找资源了
  18. 《数字图像处理(第三版)》 第二章 数字图像基础 笔记1(视觉与电磁波谱)
  19. 吃鸡服务器维护7月5号,绝地求生7月5日维护到几点 7月5日吃鸡更新维护公告
  20. 案例 | 沃尔玛 x 腾讯云 Serverless 应用实践,全力保障消费者购物体验

热门文章

  1. c程序100例第3题
  2. pandas之dataframe去掉冗余行以及左连接合并dataframe
  3. WPF Path.Data 后台代码赋值
  4. 笔记16(shell编程)
  5. Android开发之路--(2)--Android四大组件
  6. 8天学通MongoDB——第四天 索引操作
  7. 附录-系统环境、系统属性
  8. Java线程池(2) - 线程池的功能需求、设计、实现
  9. java源代码1000_Java源代码
  10. linux mac time machine,用 Ubuntu 10.10 构建 Time Machine 备份服务器