资深架构师、技术创业家。两者共同的特点是“够牛X”。正因此,很多奋战在第一线的程序师们会将他们定位为自己的目标,并期望可以向他们学习、取经。针对这个广泛存在的诉求,一场别开生面的京、广、杭三城“ 极客 & 创客大宴 ”悄然展开—— 9 月 19 日,又拍云 Open Talk 同时登陆北京、广州、杭州,一场三地联办的大型技术主题沙龙拉开帷幕。

这场名为“技术的三城形态”的实战分享会力邀了新浪、七乐康、河狸家、海蜜、贝贝网、图普科技、甘果移动、爱拍、淘粉吧的技术负责人、企业掌门人“压阵”,好东西自不会少。慕名而来的三地开发者们聆听了一场干货满满的技术与创业讲堂。杭州活动的主题为《实效的技术架构与开发模式》,淘粉吧无线技术架构负责人 沈寅在活动上做了题为《 应用动态化之 Native API  》。

image.png

大家好!很高兴接受又拍云的邀请,跟大家分享一下淘粉吧无线技术团队的一些技术实践。

《应用动态化之 Native API 》看起来还是稍微有点费解,那么,我下面的副主题是“客户端与 H5 如何优雅的互动”。

首先看一下场景,如果应用里面也H5的互动,大概会分几个场景:

image.png

实线说明是客户端本身 Native 里面,虚线表明的是 wap 页面。可能有一个场景,就是 web 页面里有分享按钮,点了分享。其实 web 里面做分享比较麻烦,所以大多数会选择调用客户端的分享功能,然后直接把客户端的分享功能放下来,有微信、微博或者 QQ,分享完了之后,同时到 web 页面,分享成功,其实这是比较通用的H5桥接交互。

image.png
Native 有很多类目,比如说今天有一个比较热门的关键词或者发现一件比较热门的事情,想配置一些新的活动,这时候需要在后台里配置活动,本身 Native 可能是一个商品的浏览页面或者是商品的列表,这时候往下滑,到某个触点的时候会告诉你目前有某个活动,要在 web 页面点击开始,然后进入到相应的活动流程。在实际开发过程中发现,虽然 H5 桥接是技术比较低的方案,但真正做的时候比较耗时,因为前端团队和客户端的团队、架构师的团队都要介入,所以整个流程比较麻烦,而且我们每次客户端迭代的功能比较多,有时候H5的桥接功能就被边缘化,以上的 H5 可能还是有 bug 的。

这时候我们就把 Native 的桥接重新做了一次定义,这个 8 月份已经上线了,线上已经运行了一个多月,整体的感觉还不错。由于我们想把 H5 在本身应用里的体验做到极致,所以我们会做一些非常高度化的定制。

大家看到的是海狐全球购,也是海购的产品线,在产品应用初级,会有很多产品设计交互上的迭代,所以我们选择了H5的页面做一些尝试。在H5页面里,圈出来就是 Native API,它已经可以承载,可以动态改变,右侧的按钮可以驱动创建,混合了整个导航栏上面的返回、×或者安卓手机上的硬返回。中间还画了一个圈,这是一个很简单的功能,点了这个会有商品详情的大图。在做这个需求的时候,其实在客户端本来已经有了,点了可以放大缩小,长按可以保存到相册,基于这样的场景,我们在 Native API 上做了一层延展,让 H5 页面可以不用发版本,唤起 Native 已有的功能。

image.png
这个 Native API 的实际图,实际上设计思想和微信的 JS 和 SDK 差不多,也是把 Native 做成一个底层 sever,H5 页面相当于有两个 serve 的概念,一个是 Native,一个是真正的 serve,这个 serve 会通过 serve 的代理服务器做请求。一开始也是一样,H5 页面会请求 Native 进行授权,我们会根据一些域名绑定对H5的当前页面授权。一旦授权完成之后,Native 就会返回当前 Native 可用的 API 里面。收集过程完成之后,H5 页面就可以开始请求 Native 的 ability,就是本地 Native 的一些能力,比如说可以 put 一个任意的页面或者 put 一个弹窗,或者 Native 的一些数据,可以帮真正的 several 去解析,因为有一些用户信息或者客户端信息,在客户端本来就已经有了,H5页面不需要再请求了。

当然 Native 里面会有很成熟的加密或者签名的方法,如果 proxy 里面涉及到收银台或者是订单结算等这些安全性比较高的,可以代理给 Native,让Native 向 server 做请求。server 请求返回之后,Native 会判断这时候会不会需要 call back,要 call back 的话会通知 H5 页面,把相应的结果反馈给成员。当然 Native 请求客户端的时候,有可能会有一些新的功能想安插进去,这时候我们会以 push wap 的方式再次接入这个流程。

image.png

看一下 API 的原型,这是一个本地弹窗的 API,它的名字叫 alert,inputs 就是 title、message,cancelButton、confirmButton 是左右按钮,红线后面是返回参数,H5 页面到底按的是左边按钮还是右边的按钮,红线后面到底是哪个 Native 里实现的,这个是我们的开放接口。这个开放接口是怎么定义的?就是我们会做一些评估,然后会把比较有效的,可以焕发的功能预先植入到 Native 里面。

image.png

如果我们点了商品之后,想看商品的浏览,这时候其实 Native 已经有方法了,我们会做一次 Native 业务方法的分装,大致结构是一致的,区别就是前面会有一个平台,NI 或者是 IOS,NA 是安卓,后面是当前在 Native 里面的方法。区别比较大的就是 inputs,因为 Native 是强类型,所以我们要做类型的转换才能真正很好的把 Native 本身的 H5 调起来。现在支持的基本类型就是 Int、Long、Float、Double、Bool,复杂类型就是 String,Any 是任何类型,[]是数字,{}是字典,{自定义}是自定义的类型比,就是自定义类型。

image.png
整个 Native API 的构成其实很简单,只有三个文件,最主要的是 Native 的 Relay,这是一个函数入口,它负责解析 API 的原型,还要解析从H5页面过来的 BRI,解析完了之后会做 Native 的执行。RelayObject 是 Native 原型的存储器,它负责把 API 解析下来的内容进行存储,进行对象和方法的反射。还有 GOR,是全球对象引用器,我们会 hope 整个应用或框架里面需要的一些对象,被 GOR 发现的时候,一旦对象有 log 出来,这时候会动态在GOR里面做应用。因为有些需要调用 Native 本身,其实需要当前 contest 实例,而不是重新创立一个实例。

image.png
Anpi 是普一脚本。anpi 包括三个文件:naan 是最主要的,它会扫描整个工程和整体 Native API 列表相关的动态文件,会在 Native 文件里面生成函数入口。当然我们已经扫描了整个工程,所以顺带也做了一些 Native 的探索,类似 JAVA 的分解,可以帮助我们更高效的做 Native 的开发。Apimap 和 apilist 都是函数原型列表,他们唯一的区别是 apilist 不带后面的 classname,因为 apimap 是给不同平台用的,不同平台生成的方法可能都在不同的类别,所以 IOS 有一个 apimap,安卓也会有一个 apimap,客户端的工程师自己会觉得有某些方法要开放出来,可能会自己做一些尝试,这时候如果一不小心把还没有经过验证的方法公开到 apimap 里,没有关系,因为 apilist 没有注明的话,是不会生成提供给前端团队的 JSlip 的。

通过 naan 做动态化脚本的解析之后会生成两个文件,一个是 lxlib,供给前端团队做 API 调用 JS 库,顺带会生成一个 napi.html 页面,这是帮助本地端工程师测试页面,主要是帮助桥接做结构化的开发,原来可能做开发的时候要测试要提供一个页面,要自己想到怎么传参,调试比较麻烦,我们把整个 H5 开发流程简化,更结构化。

Apimap 的 example

image.png

可能会定义一个 echo 的函数,传回来的是 content,回一个 content,然后在 NativeAbility 文件里面实现。经过 naan 扫描之后动态生成函数入口,会有刚才注明的 content 整个函数,因为有一个回写,会有一个 callback,传进来 callback ID,如果像 echo 这样比较简单的函数,其实不需要加任何代码,下面的 echo-callback 是自动生成的,有一个链接口 echo callback 就好了,但有可能 Native 开放一些复杂的方法,要在固定里面自己去写,但客户端工程师不需要关注到底原来是怎么调过来的,然后应该怎么传出去。

image.png
做完之后,生成之后会形成一个 lip,在前端页面或者是 ××JS 领域,调用一下 L 差,点 echo,然后回调,当前回调 18,回写 content 给 back 出来。

image.png

我们对有关 Native API,本地客户端已经开发过的API或者是系统的API都有调用能力,所以 Native API 能做的事情变得很多。top,push,可以切换到任何 tap 页面,或者 hookback 按钮,或者是 webTitle 或者是 toast,或者可以在网页里面启动摇动事件的监控,或者可以拿下当下的地理位置,或者链接。做完之后,我们的结构图就变成了 Native API,和系统 Framworks 在一层,web View 里面会有一个场景。

image.png
我们想要优化 H5 的桥接开发结构,让 H5 桥接工作变得很简单,让客户端工程师直接做就可以了,脱离架构师和前端工程师,H5 获取客户端已知信息,为 server 做一些减负,H5 做一些后面的操作比较慢,我们会把一些数据签名加解密全部交给客户端做。比较重要的一点是客户端会帮 H5 构建缓存,因为 H5 应用到页面里面,它的缓存不是那么理想,客户端有非常完善第三方框架,可以直接移植进来。H5想要开发的功能,如果客户端已经有了,就不需要 H5 做二次开发。

image.png

我们想要和 ReactNative 一样,可以在线更新,可以动态热补。我问 facebook 的朋友,虽然 ReactNative 已经很火,IOS 和安卓都已经开源出来了,但他们公司内部还没有开始用,只是做了一些边缘化的广告插件,也有一个原因,如果要做动态化,客户端工程师必须去接触另外一个语言,所以语言也有学习成本。我们会做动态化的中间件,用动态脚本映射另一层动态脚本,让整个 Native 工程师对这个动态化脚本全部加工,其实编写的时候还是原生的语言,但可以通过翻译把动态语言翻译成原生语言,在云端把动态语言合起来,传到后端本地的时候,再去解析动态语言,工程师继续开发原来自己所熟悉的 Native 语言。

因为我们做了中间件,所以它在安卓层做的开发和 IOS 做的开发可以互用,一个需求如果评估得好、分析得好,可能都可以把它移开,安卓做一版,IOS 做一版,合起来就是完整的。谢谢!


又拍云 Open Talk 是由又拍云发起的系列主题分享沙龙。秉承又拍云帮助企业提升发展速度的初衷,又拍云 Open Talk 将用全干货的形态,为互联网从业人员呈现以技术为主,同时涵盖产品、营销、融资等各个方面的专业知识,帮助企业成员不断的提升自身专业技能,以推动企业更快的发展。