年报项目系列分享之通信篇

年报项目跟我们以往的项目都不太一样,因此我将会写几篇文章总结一下年报项目的特点,分享给各位同事,尤其是没有参与到该项目中的同事们。尽可能多地告诉你们我们做了什么,以及为什么这么做。

项目简介

为了增加公司品牌的影响力,我们今年开始做年报,和支付宝的年报类似,我们年报里总结了用户的基本信息以及这一年来工作情况,比如入职多久了,这一年工作多少天,请假多少天,出差次数,出差次数最多的城市,使用我们系统的情况等。表现为若干张全屏页面,每一屏的信息较少,图像较多,动画较多,每一屏的信息展示完毕以后会自动或需要用户点击进入下一页,最后有一个信息汇总页面,用户点击右上角三个点可以将这一屏信息分享到微信朋友圈。朋友圈的同事也可以扫描截屏上的二维码来查看自己的自己的年报。

年报的访问入口在哪里呢,在我们的APP里的消息里,在元旦后的某一天我们就会给用户推送一条消息,用户点击该消息就能查看自己的年报,不用多说,年报当然非常适合通过网页技术来做,而原生应用作为网页的载体,通过 WebView 来打开网页。这时候我们的网页和原生的 App 就需要互相通信。我们需要传递哪些信息呢?

数据通信

1. App将用户身份信息传递给网页

在我们的产品中,用户信息包含两个部分,一个是租户ID,一个是用户ID。最初我接到这个项目的时候,我以为要把整个年报分享到朋友圈呢,如果是这样的话,就需要生成一个UUID,并把该UUID和租户ID,用户ID一起保存到数据库中,分享到朋友圈时在链接上加上该UUID,在服务器端根据该UUID查询出租户ID和用户ID即可。后来才了解到考虑到隐私的问题,发送到朋友圈的只是一张截图,然后我们就直接传送租户ID和用户ID了。

2. 用户头像从哪里获取?

首先用户登录App时已经获取了用户头像,当然可以传递给年报网页。而网页又根据App传递过来的用户身份信息从后台获取了用户的很多数据,也可以顺便把用户头像传递过来。作为网页,为了尽量保持其接口的简单性,我们最初定义接口时是希望从后端获取。但是后端同事在研究了发现,我们的系统包含两个大版本,每个版本的用户头像保存方式也不尽相同,老系统中还是将头像转成Base64编码的字符串保存到数据库中,而新系统则是将图片保存到阿里云OSS上,仅将图片的访问地址保存到数据库中,这样为了获取用户头像信息,就需要对两种系统编写两套逻辑,划不来。最后我们和App讨论了一下,改为由App提供,由于涉及到老系统中的图片地址是Base64编码的字符串,也不适合和用户身份信息一起放在URL中,所以最后采用脚本注入的方式来做。对于网页来说,就时App给了一个全局变量。

用户分享时的数据通信

前面提到,用户分享到朋友圈的是一张网页截图,App的同事问我要怎么把图片数据给他时,我也毫不犹豫地讲Base64编码的字符串。这很正常,为了截图,我们可以通过Canvas绘制页面,并导出图片,总不能我们把把图片保存到服务器后再给你链接吧,因此肯定是直接把Base64编码的字符串给App。后来和团队里其他同事讨论时才注意难点,我们为了实现全屏动画,以及更好的视觉和动画效果,都是采用了SVG格式的矢量图,使用rem这种相对单位定位,而这个页面要使用Canvas绘制,就要多研究一种技术方案,时间上也怕来不及。所幸我们突然想到手机上有个截屏操作啊,原生App也一定有相应的接口来实现截屏,这样一来我们就简单太多了,这个页面不需要特别处理。后来问了App的同事,果然有这样的接口,并且他们以前也在另一个模块实现过。

很好,让App来截屏。但是什么时候可以截屏,用户怎么知道可以截屏了呢?这里有涉及和原生App的通信了。

我们来捋一下,用户经过一系列的操作,达到了网页的最后一屏,这时候页面标题栏(原生App提供)右侧应该显示三个点,并且页面中出现让用户分享的提示,比如一个抖动着的指向那三个点的小手。当用户点击三个点以后,隐藏分享提示,之后原生App就可以截屏了。

再来着重看一下这中间涉及到的网页和原生App的通信:
1 到了最后一屏,网页通知原生App显示截屏操作入口三个点,同时网页显示出分享提示。
2 异步调用的方式
2.1 用户点击了三个点以后,原生App通知网页隐藏分享提示。
2.2 网页隐藏分享提示,然后通知原生App截屏
3 同步调用的方式
用户点击了三个点以后,原生App调用网页开放的全局方法将分享提示隐藏。

可以看到不管是同步还是异步的操作,要么三次通信,要么开放全局方法加两次通信,都比较复杂。再次分析发现,分享提示的显示和关闭可以交给原生App来做,这样只需要在网页在显示到最后一屏时通知原生App可是显示提示用户分享即可,以后所有的操作都由原生App完成。借此达到不同的团队之间不同的系统之间通信次数最少的目的。

OK,以上就是这个项目中所有的和网页相关的通信了。一方面我们追求在子系统之间的通信简单化,一方面还要考虑各个子系统的实现难度,达到一个最佳平衡。