干货 | 快应用之vivo商城开发实践

前些日子,快应用标准启动发布会落下圆满序幕。关于快应用,vivo开发者有些话要说,开发者们总结了商城快应用中一些比较好的开发实践案例,以及实际碰到的问题,踩过的坑,同时也给开发者们输出一些好的开发总结 。

1.快应用是什么?

3月20号,由小米、华为、OPPO、vivo等十家手机厂商在北京联合召开快应用标准启动发布会。自此快应用正式进入了对外公测阶段。

在标准启动发布会上,厂商代表们也分别从 “用户场景与需求”,“开放平台”,“技术实现”,“流量规划”等几个方面非常详细的给大家介绍了快应用。比如说轻量化,免安装,使用高效的前端技术栈,完整的原生应用体验,丰富的多入口场景等等。

正如快应用的官方网站:(https://www.quickapp.cn/)上说的那样:

  • 快应用是基于手机硬件平台的新型应用形态,标准是由主流手机厂商组成的快应用联盟联合制定;
  • 快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台,以平台化的生态模式对个人开发者和企业开发者全品类开放;
  • 快应用具备传统APP完整的应用体验,无需安装、即点即用。

2.vivo商城快应用

作为手机厂商之一的vivo,在快应用方面是非常重视的,也投入了很多的开发人力,而笔者也有幸能够参与到快应用引擎的标准讨论制定和开发中。

今天我们要说的不是快应用引擎标准,而是站在开发者角度上来说一说开发一款快应用是种怎样的体验。 在快应用的内测阶段,我们需要真刀实枪的开发一款快应用来检验我们快应用引擎的能力。我们需要的是页面尽量复杂,功能齐全,能够尽量多的使用和检验到快应用组件以及接口能力的这么一个产品。

vivo商城无疑是非常合适的。考虑到商品详情页都是比较复杂,交互比较多的,并且商城同时会有账号系统和支付系统,正好可以检验我们的引擎和多系统之间的联调。

好了,既然方向确定了,那么我们就开搞吧。

  • 2.1 开发环境

首先我们来搭建开发环境,按照官方文档:(https://doc.quickapp.cn/)上的步骤很快就可以搞定。装好nodejs,然后执行命令"npm install -g hap-toolkit"安装快应用的开发者工具。

"hap-toolkit"通过命令"hap init <ProjectName>"可以非常方便的创建快应用工程,同时支持"hap update"命令来升级工程。同时,我们需要在手机上安装一个 快应用调试器的apk,用来调试我们的快应用。关于调试器的使用方式可参看官方文档。

(介绍说明:https://doc.quickapp.cn/tools/debugging-tools.html)

等以上准备工作搞定后,我们快应用的开发环境就装好了,是不是很简单呢?

  • 2.2 思考几个问题

初始化好快应用项目后,想必大家都想跃跃欲试了,不过我们先不用急着撸码,我们可以先来想下这几个问题。

1. 快应用开发采用的是类似vue风格的编码方式,快应用跟前端web里单页应用有哪些相同点,又有哪些不一样呢?

2. 如何能够在页面布局上做到统一的交互控制呢,比如说页面的加载效果,加载错误页,网络错误页等等?

3. 是否需要封装网络请求,来做到统一的数据加载交互?

接着我们来一起探讨上面这几个问题。

问题1: 首先快应用跟web中的单页应用有什么异同点呢?

我们先从快应用的加载渲染机制说起。首先开发者采用前端技术栈开发快应用项目,然后经过webpack打包编译成一个rpk包,接着开发者将rpk包上传到快应用开发者云端。当用户在手机端的入口上打开某个快应用时,快应用引擎会从云端将rpk包拉下来,同时对其进行解压读取和解析,并渲染出对应的原生组件展示给用户,也就是说呈现给用户的其实就是一个原生的app。

跟web中的单页应用一样,快应用也是一开始会下载整个应用包,然后进行渲染。不过由于渲染的宿主容器不同导致了快应用跟web的单页应用还是有很大的区别的。

通过官方文档关于生命周期介绍:(https://doc.quickapp.cn/tutorial/framework/lifecycle.html),我们知道快应用中创建过的页面,只要没有按返回键销毁掉,就都存在app的生命周期内。而浏览器的处理方式是不会保存上一个页面的状态信息的,每次回退都是一次重新加载的过程。

当我们需要页面之间进行通信时,由于快应用存在page栈的概念,所以可以通过快应用中提供了channel通道的能力来做到多个页面之间的通信能力。比如说下面的场景:

在订单结算页中,点击切换收货地址后进入收货地址页,在收货地址页切换收货地址时,我们希望订单结算页的地址能跟着一起发生改变。在快应用中我们只需要在切换时通过channel将消息传递给结算页即能达到切换,而在web端时,我们只能在回到结算页时才去做检测然后再去改变,相比而言体验肯定是没有快应用好的。

问题2:如果能够在页面布局上做到统一的交互控制呢?

为了保证交互和风格统一,每个页面都会有相同加载效果,一样的加载错误页以及网络错误页,当然如果你觉的自带的titlebar不合适,也可以自定义一个titlebar,那同样也是每个页面都需要有的。

那这些共通的展示和交互,我们肯定不希望每个页面都这么写一遍,那后面修改维护起来肯定要骂人的。我们能不能做到统一管理和控制呢?

答案是可以的,不然我也不会这么多废话了... ...

借助于快应用框架对自定义组件的能力支持,我们可以非常方便的将上面提高的共通点都剥离成组件的方式,然后再借助"slot"的能力将这些和各个页面整合到一起来。那么可以整合成如下这样的伪代码:

首先我们搞个布局组件"baselayout.ux",用来控制整个页面的布局以及交互,其中包含的一些共通交互和展示也以组件的方式import进来。

 <import name='titleBar' src='./titleBar'></import> 
 <import name='error' src='./error'></import>        
 <import name='loadingpage' src='../Component/loadingPage'></import> 
<template>
    <div class="page-doc">
      <!-- 通用标题栏 -->
      <titleBar title-config="{{titleConfig}}"></titleBar>  
      <!-- 错误页 -->
      <error if="{{isError}}" @retry="retryEvent"></error> 
      <!-- 加载页 --> 
      <loadingpage if="{{isLoading}}"></loadingpage>       
      <div class="page-content">
           <!-- 各具体业务页面 -->
        <slot></slot>                                      
      </div>
    <div>
</template>

然后在各个页面里中只需要import上面的"baselayout.ux"后,替换掉"slot"插槽部分就可以共用baselayout中的组件啦。

<import name='baselayout' src='../Component/baselayout'></import>
<template>
  <baselayout title-config="{{titleConfig}}" is-error="{{isErrorShow}}" is-loading="{{isLoading}}">
      <div>
        <!-- 具体页面ui -->
        ...
      </div>
  </baselayout>    
<template>

(左右滑动查看)

如此就可以非常好的解决了我们的问题,每个页面只需要负责跟自己相关的ui展示和业务处理,而其他共同方面的内容可以通过组件的方式引入进来,通过传参的方式来加以控制。

大概效果是这样的(动图的画质效果有点差... ...)

问题3: 是否需要封装网络请求,来做到统一的数据加载交互?

目前引擎提供了fetch接口来加载数据,我们看(官方文档:https://doc.quickapp.cn/features/system/fetch.html)关于fetch.fecth接口的介绍是通过success回调的方式来获取数据,非常不方便。同时也不支持cookie,需要手动在header中拼接Cookie字符串。

基于以上原因,我们觉的还是有必要将fetch接口进行二次封装,便于给各个业务页面来调用的。首先我们将回调的方式进行了Promise化,可以使用async, await语法。同步的代码,抒发着异步的情怀... ...(当然,需要引入babel编译)

import nativeFetch from '@system.fetch'
async fetch (options) {
    return new Promise((resolve, reject) => {
        options.success = function (data, code) {
        resolve({ data, code })
      }
      options.fail = function (data, code) {
        resolve({ data, code })
      }
      nativeFetch.fetch(options)
    })
}

接着我们将设置cookie的逻辑封装进fetch接口中,业务方只需要在调用fetch方式时在传参的options中设置auth为true即表明当前的这个fetch请求是需要带上cookie的登录态信息的。

/**
 * 设置登录态
 */
async function setAuth(obj) {
  if (obj.auth) {
       // 获取用户信息
    let accountInfo = await account.getAccountInfo()
    let header = obj.header || {}
    // 在header上设定cookie信息
    if (header.Cookie) {
      let cookieArr = header.Cookie.split(';')
      cookieArr = cookieArr.filter((item) => {
        return item.indexOf('openId') === -1 && item.indexOf('token') === -1
      })
      cookieArr.unshift(` token=${accountInfo.token}`)
      cookieArr.unshift(` openId=${accountInfo.openId}`)
      header.Cookie = cookieArr.join(';')
    } else {
      header.Cookie = `openId=${accountInfo.openId}; token=${accountInfo.token}`
    }
    obj.header = header
  }
}
async function fetch(options) {
    // 设置登录态
  let authRes = await setAuth(obj)
   ...
}

(左右滑动查看)

在解决了上面几个问题后,剩下的工作也就是开始撸各自业务页面上的逻辑啦。想清楚后,再动手往往会事半功倍的哦。

对了,目前快应用是支持webp图片格式的,vivo商城快应用现已全面使用,一来可以减少本地的静态图片大小来进一步缩小rpk包大小,二来也可以加快动态图片的网络加载。

有个可以一键转换多个webp图片的命令行工具"npm i sharp-webp-cli -g"安装后,执行"sharp-webp -i <filepath>"命令进行转换

如果觉得每添加一些图片都要执行一次命令比较麻烦时,也可以跟具体工程关联起来。商城快应用里是写了一个脚本转换工具,会遍历快应用工程中的图片文件,然后转换为webp格式(排除掉package.json中配置的logo图片)。

  • 2.3 系统能力

我们也是需要判断用户的网络环境,那network接口就派上用场了。在无网络情况下,直接显示无网络的错误页,当用户切换到有网络环境时,通过network.subscribe方法可以在回调中立即拿到网络状态,接着我们可以立即重新加载数据来渲染我们的页面,给用户呈现最新的页面状态。这样做的带来的好处是避免了用户的再次点击加载,同样也提高了用户的体验。

大概效果是这样的

快应用添加桌面的功能肯定是开发小伙伴们非常喜欢的,那也只需要调用shortcut接口的install方法即可成功添加,非常的简单便捷。

上面举了几个简单的例子主要想说的是得益于快应用的系统能力,相比H5的web开发,我们能做的更多,做的更好。我们可以为用户提供更好更便捷的交互体验。

  • 2.4 厂商服务

相信有很多开发者小伙伴们都是个人开发者,或是是一些小型的创业公司,那么肯定是没有那么多的时间和精力去为了快应用搞套账户系统、支付系统、push系统,又或者是统计系统的。

但是这些额外的辅助功能对于开发者来说却也是挺重要的,那怎么办呢?

放心,这些问题快应用厂商们都已经想到了,快应用引擎会提供非常贴心的厂商服务。只需要按照厂商提供的文档进行对接,上述说的这些能力就可以非常简便快捷的立即拥有。

在vivo商城快应用中,我们用到了账户系统和支付系统。接入vivo账户系统时,在前端代码开发中,只需要调用"account.authorize"授权方法,成功后,接着调用"account.getProfile"方法即可获取到vivo账户的基本信息。

下面是vivo商城快应用相关页面的截图。

授权页面

授权成功后获取用户信息

对于支付功能而言,在前端代码开发时也只是需要调用一个"pay.pay"方法即可调起vivo支付收银台页面,而vivo收银台提供了 支付宝,微信,银联等多种支付渠道。开发者只需要对接一次vivo支付即可拥有多家支付方式能力,对于开发者来说绝对是大大的福利啊。而这些种种的便捷都依托于快应用引擎的强大,以及厂商们背后的强有力支持。

支付收银台页面

点击更多方式查看更多支付渠道

  • 2.5 我们一起踩过的坑

在商城快应用的开发过程中,肯定会或多或少踩过一些坑,这边也列举一些,开发小伙伴们如果碰到了,尽量去规避吧。当然这些问题肯定会在后续的版本中去优化解决的。

  • 元素border在进行切换时,会导致粗细不一致的问题;
  • router.back回退目前只能回退一个页面,无法回退多个页面;
  • background 渐变对圆角border-radius的支持还不好;
  • css还不支持shadow阴影效果;
  • 提供的checkbox等组件样式无法自定义,input text目前还不支持max-length等;
  • 跟h5相比的话,动画能力支撑偏弱(目前keyframes属性只支持background-color,opacity,width/height,transform这几个值的改变)。

3.开发实践小结

  • 3.1 问题

目前快应用刚刚公测,我这边也列了下目前想到的一些问题。当然,快应用的生态还是需要广大开发者来一同创建,有了友好的生态,这些也都不再是问题了。

  • 目前上传rpk包的大小限制在1M 以内,这样针对一些大型的应用来说 可能是不够的。不过后续这个限制应该也会有所调整;
  • 目前是整个rpk包进行下载解析渲染,而用户可能只使用了其中的一两个页面,造成了资源的浪费,后续需要有分包下载解析的能力;
  • 目前提供的组件和接口的能力是基本能够满足一般的应用开发的,不过还少一些比较重要的组件和能力。比如说地图组件,引擎和webview之间的jsbridge能力缺失;
  • 目前还不支持websocket,在有些场景下websocket还是非常有用的;
  • 目前支持提供自定义组件,可是如果开发者想提供一套组件库供多个项目使用时,引入组件的方式还不太友好。
  • 3.2 优势

相比快应用的优势来说,刚才列的一些问题点也就显的有点无足轻重了。下面结合我们自己的开发实践来具体看看快应用的优势所在吧。

首先快应用的开发成本相比较native来说真的是低了很多,得益于采用了前端技术栈(vue体系风格),学习成本很低,上手快,还可直接复用原有web应用逻辑,迁移、改造过程非常平滑。同时采用强大灵活的flex布局,可以非常方便快速的完成页面的布局,视觉稿的还原度很高。同时快应用引擎也提供了很多原生能力的接口以及账户,支付,统计等非常贴心的厂商服务。

同时,快应用发版非常简单方便,用户即可更新,没有版本碎片化带来的一系列问题,不存在开发者需要同时维护多版本的实际痛点。

在实际开发时,我们的情况大概是这样的:vivo商城快应用第一版共十多个页面,同时还有账户系统和支付系统,而开发时间只用了短短的一周左右的时间,而联调时间也只有一周多而已(快应用、引擎、账户、支付等多系统联调)。

在体验交互方面,相比普通的H5来说加载更快,还原度更高,体验更好。从产品使用上来说基本跟原生应用的体验是一致的。通过vivo商城快应用的开发检验后,我们可以很有信心的说目前的快应用引擎的能力是可以完全应对一款正常的产品开发需求的。

同时现阶段,在厂商大力扶持的背景下,也带来了高曝光,大流量。开发者小伙伴们,下一个流量风口是不是就要来了呢,我们拭目以待吧。

本文分享自微信公众号 - vivo互联网技术(vivoVMIC)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-03-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励