2016除夕夜,微信除了摇一摇抢红包,同时还带来了另外一个新玩法——红包照片,而据说很多人也都卖命晒出了珍藏多年的照片!
猴年除夕活动已经落下帷幕,回头来看红包照片这一套系统,对于客户端而言,区别于普通的朋友圈图片设计差异是否大?它是否复杂? 客户端都关注些什么?下面我从一个Android客户端开发者的角度出发,来谈谈我的看法。
首先从整体的角度来认识一下红包照片,这是红包照片的相关模块图:
从功能实现角度看,红包照片并不复杂。主要包含图中几个模块,基本就可以实现红包照片这个功能:
如果从单独的简单的每一个模块来看,似乎都不是很难,但我们整个开发过程到发布第一个版本也才不到两个多月的时间,那么对于客户端开发,这两个月意味着什么?
红包照片并不是我们的第一个版本,意思是我们的开发是不断迭代的,产品方案不断变化; 对于客户端而言是,我们的代码要随着产品设计不断的推倒,体验才最终成型;
从抢照片,到照片大冒险,讨红包,红包照片我们的主题,玩法也不断的在变,客户端要适应这种开发方式,起码我们要满足:
对于我们最安全的就是以扩展的方式来写代码;多增加,少修改;而相比其他功能模块,要更多的:
最后,项目在发布之前都还保持着保密的状态,内部的每一次的小规模演练就变得非常重要,抓住每一次演练的机会,进行检验。
估计这是对红包照片印象最深的地方,随机打开一张朋友圈红包照片,每次都会随机显示一个圆圈类型的洞,暴露图片局部的内容;而如果想看完整的照片,必须通过"发红包看照片"来实现,这是红包照片的核心玩法。
模糊图片并不是功能一开始就有的设计,而是一个个demo版本演变来的, 因此一张红包照片和一张普通照片对后台存储来说是没有什么不同的。从模块设计角度来说,一张红包照片的发表/下载流程上和一张普通图片的发表/下载几乎没有差异;那么这些表现出来的差异,模糊、挖洞就得交给客户端来做。
第一次点开朋友圈中的红包照片要经过哪些步骤呢?
这些步骤的处理对Android来说都是很大的性能考验。第一个版本,第一次点击图片,从完成下载、模糊、抠洞、显示看到图片,大概花了大约4s的时间,显然这是不可接受的一个体验。 那我们是怎么做的呢?
模糊一张朋友圈大图需要 1500ms左右,而模糊一张小图只要50ms不到,差不多30倍的差距,拿大图来做模糊其实很不划算。通过调节模糊半径,在确定显示效果ok的情况下,我们选择了用小图来做模糊效果而不是大图。
但我们注意到,在模糊图出现的圆洞区域却是很清晰的画面(小图缩放达不到这种效果),给人感觉整个图片好像就是清晰的样子,这又是怎么实现的呢?
首先,挖洞的位置并不是简单的随机,而是控制有一定的规则,比如说有一定的概率出现在人脸的周围。同样的道理,拿大图来做人脸识别和小图来做人脸识别差距也是非常明显的,至少10倍以上的差距,即便小图识别效果可能没有大图的效果好,但这种换取代价还是非常值得的。因此我们也首先在小图上做人脸识别,记录对应的结果坐标,通过对图片局部解码从大图找到对应的区域,Clip出一个圆圈,画到一个ARGB_8888的面板上,再将边缘进行一定的透明度调整,盖到原始图片上即可!
通过这些过程,最后我们将整体的体验缩减到1s内;
朋友圈的图片是利用HTTP从CDN服务器直接下载,而非使用私有的协议。 同时存储在客户端本地。
朋友圈红包照片跟普通照片并无差异,而HTTP本身就很容易被监听抓包,Android操作系统APP的大数据存储也是存储在公共的存储空间上。功能一旦预演,发布定会有很多的抓包、导出资源的工具等等,破坏朋友圈红包照片的相关玩法。
我们主要关注两点:
选择的方案要保证:
最后我们选择在HTTP中返回加密的数据,而加密的数据必须依赖朋友圈数据中隐藏对应的key来解密,且支持流式加解密。一张图片可以对应一个不同的密钥,允许后台从非加密切换到加密,或者加密切换到非加密。
朋友圈暴露读取文件的接口很多,读小图、读大图、读模糊图、写大图、写小图、检查exif等等都是对图片文件的操作。要考虑密钥怎么传递,减少改动量和修改的复杂度,加密的bitmap怎么解析,怎么和普通的图片数据做到兼容?
可以看下我们最后的方案:
使用者通过路径生成器,来获取路径,如果是红包照片的数据,则将密钥通过一定规则隐藏在Path路径中,密钥变更会使得Path也不同。所有的文件接口聚合到FileOperataion,发现是加密的Path则返回特殊的EncInputStream/EncOutputStream,否则返回普通的InputStream/OuputStream;
EncStream 则拦截了InputStream/OutputStream的 read 和 write 等方法,将数据通过加解密模块处理完再返回应用层;
从整体上来看,我们的改动也只涉及到了蓝色/黄色/红色的区域模块。
实际上,在保证保密/安全的工作上我们还做了很多其他工作。
比如发布的版本,为了使得项目进行保密,资源(String)等都是加密处理的,当然也犯过一些错误,比如1月26号的预热,代码暴露图片路径的接口,使得简单的通过Xposed注入替换路径就可以绕过游戏规则。
朋友圈红包作为今年的一个新的尝试,本身就获取到高度的关注,但我们又缺少历史经验,对于在朋友圈这种环境下如此大型的活动的,一方面要控制朋友圈的质量,一方面可能带来的巨大的流量,甚至很难估算;所有的方案我们都不能保证是万无一失的,如何保证系统的可用性,一方面就是要可控,能够随时调整策略。
发表权限可控,发表人数可控,发表次数可控,所有文案可控,支付金额可控等等;
比如发红包看照片这个按钮:
2016猴年春晚,朋友圈红包照片:
后续我们还会对关于朋友圈照片“性能”,以及“控制”等逻辑做深入剖析文章,敬请期待!