登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 68|回复: 0

演讲实录——使用Taro玩转多端应用

[复制链接]

179

主题

164

帖子

6294

安币

管理员

Rank: 9Rank: 9Rank: 9

发表于 2019-5-14 10:25:01 | 显示全部楼层 |阅读模式
如果对本篇文章感兴趣,请前往,原文地址:http://www.apkbus.com/blog-900274-80049.html


本文来自2019安卓巴士开发者大会现场实录,由于录入匆忙,内容可能存在偏差,欢迎大家扫描文末二维码查看现场实录视频和下载大会完整PPT。演讲人:陈嘉健、程帅



陈嘉健:


大家好!我是陈嘉健。今天我将和我的同事程帅一起来分享一下怎样使用Taro这个框架去玩转多端应用的开发。


我们团队从去年5月开始对外推出了Taro这个平台。我从Taro项目立项就加入到其中的开发,一直随着Taro学习与成长。现在主要负责Taro框架小程序端的适配。


今天的分享将会围绕以下五个点,首先介绍一下为什么我们要开发Taro,接下来是怎么样使用Taro进行开发,然后是我们一开始设计Taro的总体思想以及对应到各端的适配原理,最后是Taro的规划。


首先是对Taro框架的背景介绍。在过去一两年业界推出了很多小程序平台,加上原本前端负责的WEB端和RN端,前端需要负责的端变得越来越多。另一方面,产品经理总是什么都想要,入口越多越好,每推出一个平台,难道我们就需要把原来的事情重复做一遍吗?





多端开发的痛点可以归纳为以下三点:研发成本成倍增加,代码维护困难,以及业务落地慢人一步。


因此我们推出了一套多端统一开发框架Taro,目前Taro支持6个端。从去年6月份以来Taro收获了业界很多关注,同时我们也在不断地进行迭代和优化。


Taro的特性在于一份代码多端运行、配套的CLI工具使我们的开发流程更加现代化和自动化、其采用统一语法规范,支持书写JSX,令到我们的代码更具变现性、同时它还提供了代码智能检测和智能补全功能,有助于提高开发者的开发体验。





介绍完为什么我们要开发Taro,以及Taro的一些特性之后,接下来我会带大家了解一下怎么使用Taro进行开发。主要是怎么快速开始一个Taro项目、开始编码前对项目的一些配置,最后是编码时需要关注的一些点。


首先来了解一下怎样去创建一个Taro项目,开发者只需要从NPM上面下载Taro CLI工具,然后运行 taro init 命令,就可以创建一个Taro项目。打开刚创建好的项目,我们可以看到我们比较推荐的项目结构,在这个目录下面有一个配置目录config,是对整个项目的配置。和config平级的是src目录,src里存放着项目的源码。src下面是pages文件夹,它包括了项目的所有页面。和pages文件夹平行的是app.js和app.scss,它们分别对应着项目的入口文件和总通用样式。





下面介绍一下Taro入口文件的目录结构,首先需要把Taro和Taro.component引入进来,同时还需要把首页和项目总通用样式引用进来。然后是App类,它里面有一个属性config,对应的是项目总体的一些配置项,我们可以在类里使用App的生命周期方法,最后是一个render函数,它返回了首页组件。


再看一下一份页面文件的结构。同样地也需要把Taro和Taro.component引入进来,然后组件使用到的内置组件也需要引入进来,还需要引入首页的样式文件。然后是Page类,它里面也有一个config属性,对应了一些页面级别的配置,我们可以在类里使用Page的生命周期方法,最后的render函数用于描述页面的结构。


了解完怎么去创建一个Taro项目,以及Taro代码的结构之后,开发者只需要运行taro build --type [平台] 命令,就可以把项目跑起来了。


在编码之前开发者可能需要对项目做一些配置。在config文件夹里面可以找到所有关于当前项目的配置项。今天主要介绍其中一个配置项config.designWidth。在不同的平台中他们的样式单位都有一些区别,因此Taro需要对用户编写的px单位进行换算,而换算基准就是designWidth。它的默认值是750,意思是如果开发者拿到的设计稿为750px,那么直接按设计稿上测量出的尺寸书写即可。但如果开发者拿到的是640px的设计稿,就需要配置这个designWidth配置项,把它改成640。





接下来介绍一些在开发项目时,Taro给我们提供的一些帮助。


在Taro里面提供了很多生命周期方法,它们以React的生命周期为基准,再加上小程序特定的生命周期作为补充。


另外Taro实现了以微信小程序API为标准的API库,同时还对这些API做了Promise化,方便开发者使用。


在编写代码的时候,Taro提供一个代码实时检测功能,在编写生命周期方法、组件的属性或者使用一些API的时候,可以处处得到使用提示与自动补全。


但是世界并不是那么美好的,小程序与React底层存在很多差异,有一些JSX语法在小程序上面找不到对应实现。因此只能对这些语法进行限制。开发者在开发的时候只需要打开编辑器的ESLint检测,就可以得到对这些限制语法的提示。





Taro帮我们解决了很多底层适配的问题,有一些涉及到业务逻辑的适配,还是需要开发者自己去处理的。假设开发者需要根据不同的平台去引用不同依赖,或者根据不同的平台使用不同的组件,就需要开发者手动做处理和适配。


因此Taro提供了一个环境变量process.env.TARO_ENV,它的取值是Taro目前支持6个端。开发者在开发的时候只需要对此环境变量进行判断,就可以得知目前运行的端平台,然后根据不同的平台采取不同的逻辑。


在v1.2.17版本Taro推出了一种更加优雅的解决方式:条件文件编译功能。假设现在有个test组件,需要有不同的版本,开发者可以根据不同的平台来组织代码。不同平台组织的代码实现对外有一个统一的接口,接受同样的参数,只是对内,在不同平台上面有不同的实现而已。开发者在引用时不需要带上平台名称,只要带上文件名即可。在编译的时候,Taro会根据当前的平台对路径进行补充,这样就可以在不同的平台使用不同的组件了。





接下来说一下Taro目前的开发生态,在React语法生态里面一些比较优秀的框架在Taro中都是可以使用的。同时Taro也提供了一套多端UI组件库Taro-UI,它能帮助我们快速构建多端应用。


接下来介绍一下Taro框架的总体设计思想。


我们的目标是要使用一套代码去开发多端的应用。根据我们团队的技术栈,我们当时选择了React做为DSL。


而各端在基础框架、组件库、API库上都存在着大大小小的差异。


因此我们首先需要订立一个规范,DSL采用React语法,组件库与API库则采用微信小程序作为标准。


我们可以把这个问题分为两部分进行解决,第一部分是对代码进行转换,让代码可以运行在不同的端上。第二部分是在运行时做适配,以抹平各个端上的差异。





下面说一下代码转换,也称为编译时的思路。我们可以把源代码进行词法分析和语法分析得到抽象语法树AST,再进行语义分析,判断程序的正确性,然后操作AST,对其进行一系列的转换,最后输出一个目标代码。


我们可以借助BABEL的力量帮助我们完成一些事情。首先使用babel-core对代码解析。生成AST。然后利用babel-traverse与babel-types对代码进行转换、转换完成之后,可以利用babel-generator生成目标代码。


在生产环境里,JSX可能是相当复杂的,因此转换需要考虑很多情况,具体的转换逻辑也是很复杂的。我们需要处理条件语句、循环语句、属性计算等等,他们在生产环境里还可以是排列组合,所以有非常多的情况需要去考虑。





最后说一下Taro总体的架构,首先可以把源代码编译成各个端可以运行的代码。然后配合上Taro运行时框架以及组件库和API库,最后这份代码就可以在各个端上面完美运行起来。


接下来再讲解一下Taro对于各个端的适配原理。


首先是小程序端,小程序端的主要差异在于基础框架的差异,在这里主要做四点适配原理的介绍:第一是生命周期,第二是Props系统,第三是render函数的处理,第四是事件语法的处理。


虽然React的生命周期和小程序的生命周期语法上完全不相同,但我们仍然可以把触发时机接近的生命周期互相对应。而例如微信小程序上面的onShow和onHide这些找不到对应的生命周期方法,则需要在非小程序端补全这两个生命周期方法。React的生命周期和小程序的生命周期的并集,构成Taro生命周期的集合。





Taro的props系统依赖于小程序自定义组件的properties特性来实现,因为properties特性不支持传函数,所以非函数props和函数props有不同的实现。


非函数props的实现如下,在编译时给子组件传一个内置属性__trigger,它的值为布尔值。由于properties特性要求props使用前先定义,编译时还需要把子组件所有用到的props收集起来,供运行时使用。运行时首先会把内置属性__trigger、编译时收集的所有props在properties属性上定义好,这时小程序的父组件就能成功传递这些属性给子组件。每次父组件更新时,会改变内置属性__trigger的值,然后触发porperties.__trigger的监听函数以更新子组件。子组件的更新流程首先是计算最新的props,然后依次触发生命周期方法,最后调用小程序的setData方法更新视图。


函数props则是通过小程序自定义组件间事件通信机制triggerEvent来实现,开发者调用父组件函数如this.props.onClick()在编译时其实会被编译成this.triggerEvent('click')的形式。


但目前的props系统强依赖于properties特性,而properties的限制又比较多,因此Taro的props系统也会处处受限。例如props需要先定义再使用,那么就不能使用结构的语法、properties不能传函数则不能打印父函数,也拿不到父函数的返回值,因此我们近期对props系统进行了改造。思路是把一个props放到props manager里面。子组件在初始化或需要更新的时候,在props manager里面取回它的props。这一套运行系统完全运行在小程序的逻辑层,避免了逻辑层与视图层间通讯时数据被序列化的问题,因此刚刚谈到的限制都不复存在了。





接下来介绍对render函数的处理。JSX中渲染数据与页面模板结构都在同一份JS文件中,而小程序中渲染数据在JS文件中,模板结构则在WXML中,因此需要对JSX的render函数分为两部分来处理。首先是把render函数return之前的部分抽离到组件编译后的JS文件里的createData函数,此函数用于返回渲染数据。然后需要把return里的结构编译成小程序的WXML模版。完成这两步后模版数据和模板结构都已经就绪,就可以去成功渲染出页面。


最后介绍一下Taro里面的事件机制。在Taro里面遵循的是React的事件语法,我们在编译时要把它编译成小程序的事件语法。运行时小程序触发事件时,则会调用包装后的回调函数。此包装后的回调函数主要做了以下事情:调整参数、调整this指针的指向,最后是调用用户声明的回调函数。





接下来说一下网页端的适配。网页端H5端主要的差异在于组件库和API库。


可以看到小程序的组件封装程度比较高,提供的特性更加多。因此我们需要在H5端把小程序的基础组件都实现一遍。如果有些特性在h5端无法实现,则需要在文档提示开发者。


小程序端API和H5端API有很多差异,我们需要按照微信小程序的API标准,在H5端对应实现这些API。


接下来由我的同事程帅来给大家介绍一下怎么样对RN端进行适配。




程帅:


接下来由我来给大家介绍一下 Taro 的 RN 端实现,因为考虑到在座大部分都是移动端的开发者,所以我们适当的增加了多端适配原理中, RN 端部分的比重。





为什么我们移动端的实现,最后选择了 React Native,在前面的多端适配原理中我们提到了 H5 端和小程序端。我们都知道,H5 端的核心是前端三剑客 :HTML/CSS/JS ,分别对应 页面、样式和逻辑。同样,各平台小程序虽然文件后缀和部分写法略有差异,但本质上还是前端体系这一套东西。


小程序最近热度不减,各种小程序的框架也如雨后春笋一样层出不穷。接下来我们来看一个表格,这个表格是当前一篇很火的《小程序多端框架全面评测》文章里截取的。里面有各种框架的详细对比。可以看到,这些多端框架尽管在实现上存在一些差异,但是在移动端容器这里,要么选择 Weex,要么选择React Native。为什么?因为市面上主流的基于前端体系的移动端框架,就这两种,而 Taro 的 DSL 是 React,所以这里我们选择 React Native 就变得理所应当的。





我们来看一下 Taro React Native 端整体的一个流程图,整个 React Native 端 实现原理的讲解,也会按照这张图的流程来。在下图可以看到,首先,我们通过编译,将 Taro 代码转换为 React Native 代码,这一步转换完成之后,其实就得到了 React Native 的原生工程代码;然后,转换后的代码需要一些 运行时的依赖 才能正常运行,这些运行时的依赖包括但不限于:组件、API、路由和状态管理;接下来,我们将转换后得到的 React Native 工程打包成 js bundle,同时在 8081 端口启动一个 Server 方便应用访问,这部分是基于原生的 React Native 实现的;然后大家就可以在 集成了 React Native 的  iOS/Android 应用上访问 8081 端口来加载 js 并渲染页面了。


结合刚才的流程图,我们来回顾一下前面提到的 多端设计思想,前面提到的多端设计思想主要分为代码转换:让 Taro 代码可以运行在不同端,运行时适配:抹平各端表现的差异。Taro RN 端也是基于这套设计思想实现的。


在代码转换部分,这部分也叫编译时,主要包括两大类: JS 的转换和样式的转换。


在编译时的JS部分中,因为 Taro 和 React Native 都是 JSX,所以在 JS 转换这一步相对于小程序要轻松很多。


这里会挑几个主要的模块来讲解,首先是应用入口 app.js,大家可以看看标记的部分,这些就是代码转换的重点。




这是应用入口的编译前代码的对比。主要包括运行时API 的替换,应用的配置和路由的处理。小程序我个人觉得它虽然开发上偏向于前端,但是在使用上更偏向移动端,因为它是一个完整的闭环的应用。


接下来我们来看看页面入口文件,这里需要关注的主要是是样式的处理。对比 render 函数里内容可以看到,样式的部分由由 React 的 className 变成了 React Native 的 style 的写法,我们都知道,JSX是一种JavaScript 的语法扩展,因此, className 属性的值可能是对象以及各种表达式,所以这里在编译的时候都采用了*穷举*的办法来一一处理。


最后是 React Native Module 的入口:index.js,这个文件是在编译完成之后生成的,写过 React Native 的同学对这个文件应该很熟悉,这里引入了 app.js 然后进行 Module 注册。





React Native 的样式基于开源的跨平台布局引擎 Yoga ,样式基本上是 CSS 的一个子集,但是属性名不完全一致,具体的内容及相关差异可以查看 React Native  官方文档,Taro React Native 端样式文件的处理,主要可以分为如图的几步。


这两张图展现了样式文件 index.scss 编译前和编译后的内容,大家可以看到,在样式编译后,CSS 样式转换为 React Native Stylesheet Objects,大部分情况下,样式的转换只是写法的差异,比如:样式属性改成小驼峰的写法,属性的值改为字符串、单位去掉 px 等,但是问题真的会这么简单吗?





前面我们提到过,React Native 的样式基本上是实现了 CSS 的一个子集,我们要从一个子集转换到全集,肯定会有诸多限制。最大的两个限制如下。第一个是不支持/部分支持的样式,如 backgroud-image、list-style-type,transition 等样式属性。第二个是各种不支持的选择器,包括但不限于:标签选择器、ID 选择器、伪类选择器及各种组合器,然后 React Native 也没有像 CSS 一样的样式继承的特性。这两点也是我们目前为止碰到的最大的阻碍。


但是无论如何,问题还是得解决。但我们无法更改 React Native 的跨平台布局引擎 Yoga,所以我们只能从代码规范方面下手。


作为一个不轻易造轮子的团队,我们直接将 React Native 源码里面的 StyleSheetValidation 剥离出来,整合到编译过程中,这样在代码校验的过程就有多重校验了。


到这里,Taro React Native 编译的核心部分就讲完了,接下来看一看运行时。Taro React Native 的运行时主要包括四大方面:路由、组件、API、状态管理。首先我们来看看路由,前面有提到 *Taro 各端的 组件/API 规范是微信小程序为规范来实现的*,React Native 也是如此。Taro React Native  端路由是基于业内成熟的开源库:React Navigation 实现的,大家可以看看下面表格对比,二者的 API 还是有一些相似的。同样的,React Native 端组件的包为:@tarojs/components-rn,是使用原生的 React Native 组件按照微信小程序的组件规范实现了一遍,Taro React Native 端 的API 也是如此。





尽管如此,还有有很多复杂的场景的 组件/API 光靠原生的 React Native 组件/API 是满足不的。例如地图,或者是媒体的处理,还有图片和文件之类的。但是这些能力对于一个独立的应用来说,又是比较重要的,所以我们要想办法实现。


最开始我们选择了Expo,首先它是 React Native 官方推荐的,提供了非常的丰富的组件API,基本上覆盖了应用开发的方方面面,其次,使用它可以不用考虑原生代码和原生开发环境,这个对于前端来说,有很大的吸引力。并且它本身有一套完善的工作流,从开发调式到发布更新等,全面覆盖。


但事实上有这么美好吗?在尝试之后,我们发现它还是存在一些问题,有些地方不太符合国情。首先它提供的地图是苹果和谷歌的,而国内更多的使用百度或高德;然后分享的 API,Expo 官方只提供了分享到 Twitter 或 Facebook,而国内要考虑的是微信、豆瓣、知乎、新浪微博等;并且常规的 Expo 工程并不支持 Android /iOS 原生代码,且整个开发流程和自己的工作流及生态深度绑定,这意味着如果有团队使用它来开发应用的话,很难集成到自己的原生应用;最后,使用它还得科学上网。





因此在经过最初的试水之后,我们还是抛弃了 Expo,并尝试从京东内部寻找解决方案。JDReact 是基于 React Native 的多端的开发框架,已经在京东商城、京东金融等各种业务有深度使用,所以我们 JDReact 团队合作,让他们来给我们提供一套 SDK 补充 原生 组件/API 的不足。整个开发流程就变为: Taro 代码经过编译后,得到原生的 React Native工程,开发者可以在工程上进行原生代码整合、修改等。如果需要用到比较复杂的组件或API,开发者就需要自行集成对应的 SDK。


Taro 现在已支持主流的状态管理工具,如 Mobx ,Redux。
Taro 在运行 taro build —type rn —watch 命令后,会先进行编译,编译完之后,会调用 React Native 的命令,在 8081 启动一个 Metro Bundle Server,同时会 watch 编译后的代码并实时打包成 js bundle。
然后你可以在应用中自行集成 React Native,然后访问 8081 端口获取 js bundle,也可以使用官方提供的应用壳子 NervJS/taro-native-shell。右图是小程序官方示例 Demo 在 iOS端和 Android 端的表现。





前面提到过 ,Taro 代码编译完之后是原生的 React Native 代码,可以完全复用 React Native 的生态以及各种调试工具。


至于 构建/发布/热更新 ,当前 与 React Native 一致 ,未来 会借助 JDReact 生态,将这些流程自动化。


这里也简单提一下 Taro React Native 端 开发的一些局限性,首当其冲的就是样式,样式灵活度是H5 > 小程序 > RN 。也就是说,对齐短板为多端样式的统一,也就是要以 React Native 的约束来管理样式,核心为三点:


•        使用 Flex 布局
•        基于 BEM 写样式
•        使用 React Native 支持 的样式


再举一个典型例子:文本截断。React Native 不支持 text-overflow,而是提供原生支持 (Text 组件传入 numberOfLines={num} 属性),但是 H5/小程序端又是通过 text-overflow 样式实现的, 因此你得在text里面加上 numberOfLines 属性,且在样式里使特殊的注释包裹住 text-overflow 样式,这样在在RN端样式编译时就会忽略到这一行。


其次就是免不了要写一些跨端代码,比如说常见的登录功能,微信小程序里面直接调用平台特有的 API 就可以了,但是 React Native 端还是需要自己实现。如下图所示,你得再 user-login.js 里面 import ‘/auth’,然后再按照文件后缀写对应端的逻辑代码,Taro 在编译时会自动引入当前编译端的代码。在 React Native 端的代码中,你可以像原生 React Native 一样,基于  Native Modules 调用 iOS/Android 平台的原生代码。





这里是一个多端应用展示,是社区网友使用 Taro 开发的开源的、仿网易严选的应用,已经适配了小程序/H5/RN端。


Taro 从去年6月开源至今,已经取得了一定的成就,在小程序多端框架中名列前茅。接下来的规划重点主要是:优化开发体验,完善多端适配、建设社区生态。即将发布的 1.3 版本带来了更多全新特性,欢迎大家尝鲜。


在社区生态建设方面,Taro 社区已发布,大家可以在里面提问或技术交流。同时,大家可以在 Taro 物料市场发布或搜索 Taro 组件、API 或各种插件,提升开发效率。还有可视化开发工具正在开发中,这个工具可以进行页面的可视化编辑,并且会覆盖从开发调试到打包、应用、构建,到上线全部的开发流程。


最后,还是希望有兴趣的同学可以体验一下使用 Taro 开发的乐趣,同时,也欢迎大家积极参与社区共建。


谢谢大家!



项目地址:https://github.com/NervJS/taro
欢迎关注京东凹凸实验室公众号




现场PPT分享:
      关注【安卓巴士Android开发者门户】公众号,后台回复“420”获取讲师完整PPT。



大会现场视频小程序:





欢迎前往安卓巴士博客区投稿,技术成长于分享

期待巴友留言,共同探讨学习



[img=202px,265]http://www.apkbus.com/https://mmbiz.qpic.cn/mmbiz_gif/jE32KtUXy6H1HPUGLwqCbJAepU4oMVE9pz7rHanP1z3rsoWAcwMhMqCamDXxibicQxONBCqgH9hN9iasLIVY4LibOw/640?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1[/img]


  继续阅读全文



想在安卓巴士找到更多优质博文,可移步博客区

如果对本篇文章感兴趣,请前往,
原文地址:
http://www.apkbus.com/blog-900274-80049.html
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表