大厂经验(2):多端可视化埋点解决方案

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上一篇文章我介绍我所在团队的"},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/7e3d056b0bd3e4ce6d70b86a9?from=message","title":""},"content":[{"type":"text","text":"Web自动曝光埋点的方案经验"}]},{"type":"text","text":",今天想继续就"},{"type":"text","marks":[{"type":"strong"}],"text":"埋点"},{"type":"text","text":"话题来介绍一下我们的多端可视化埋点解决方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"团队经过一年探索,已经实现了"},{"type":"text","marks":[{"type":"strong"}],"text":"多终端可视化埋点方案"},{"type":"text","text":",包含 Web / App / 小程序等终端,基本操作流程就是将原运行在终端的应用,映射到PC浏览器上,通过浏览器做配置埋点,相较于H5,App终端因技术栈及访问环境等条件不同,在界面投屏及元素识别上有一定的难度,下面分享我们实现的像素识别方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"埋点"},{"type":"text","text":",简单说就是对指定位置埋上指定的值,以便监控到该位置是否做了点击、曝光、跳转等操作,从而得到数据以做分析使用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"该数据通常被PD、运营等同学使用,但埋点却由编码的开发同学完成,且埋点的值还会不定时的更新,增加开发人员工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以此为诉求,团队着手实现可视化埋点方案,可视化埋点核心在于 如何以平台的形式不经开发人员来对页面埋点,比如由制定埋点规划、使用埋点数据的PD人员来操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可视化埋点 从使用终端及技术栈上可划分为两类,"},{"type":"text","marks":[{"type":"strong"}],"text":"native"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"strong"}],"text":"web"},{"type":"text","text":",而weex、小程序则两端都覆盖。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0c/0c1782788025f90b27d09591601076ef.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开发完全不参与,当然是非常理想,实际上难以操作。简单来说做埋点管理的平台通常是在web端,而PD很难通过web平台来操作native app的页面元素。相比之下web端的埋点可视化因终端及技术的一致性,我们已经实现。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"退而求其次,由开发人员在代码中标明需要埋点的位置,由PD来配置、更新需埋点的值,也可以很大程度上减少开发人员工作,提升工作效率,我们就以这种思路来实际App可视化埋点。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面主要分享下,如何在PC平台对App实现可视化埋点解析,实际的实现行为更复杂,这里精要讲下思路、流程。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#40A9FF","name":"user"}}],"text":"方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"web端的可视化埋点,用户可以通过js实现对html操作,从而直接在PC上对web页面做元素的圈选、分析。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而web不具备操作native的能力,通过埋点规范、Native截屏、解析约定等,共同实现了一套完整的方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先Native开发人员做硬编码向需要埋点的元素定义id,native接入sdk,以识别此类元素,截应用图,并将图元素绘制在对应位置,保存为RGB色值的png图像,如下图:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2d/2d7fdee10ec5ae3d9d05f646f6903072.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上图中带黑色边框的蓝色正方形的区块,标明了需要埋点的元素及ID都隐藏这个区块里。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们放大该区块"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0f/0f0b02c31489c4707b9e919aa1a0e2c9.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到黑框内的左上角,有一些彩色像素,这些像素就是用来标识埋点元素的位置及id。"},{"type":"text","marks":[{"type":"strong"}],"text":"web端的工作重点就是解析这张图片的Data。"},{"type":"text","text":"web端下载该图并得到其像素数据:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"const canvas = document.canvas;\nconst ctx = canvas.getContext('2d');\nconst img = new Image();\nimg.setAttribute(\"crossOrigin\", \"anonymous\");\nimg.crossOrigin = \"Anonymous\"\nimg.src = src;\nimg.onload = function() {\n ctx.drawImage(img, 0, 0);\n let imageData = ctx.getImageData(0, 0, this.width, this.height); // imageData即 该图片的所有像素点 \n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"得到所有像素点,如"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"[255, 144, 0, 255, 255, 144, 0, 255, 255, 144, 0, 255, 255,...]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们知道,一个像素点,由四个值组成,分别为RGBA,如第一个像素点:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"255 - R"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"144 - G"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"0 - B"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"255 - A"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过这套数据,四个一组 来筛选找到 web与native 约定好的起始点(即 [97, 117, 116, 255, 111, 116, 114, 255, 97, 99, 107, 255]) ,找到后,再取56"},{"type":"text","marks":[{"type":"italic"}],"text":"56px的区块,且该区块外有 2"},{"type":"text","text":"2px的黑色边框,符合这个条件的,即是双方约定标识的有效区域,如下图示意:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/48/48665e409361e5f62ba3e1babb8832a2.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如我们在第10000个像素找到了符合条件的区块,经过简单计算我们可以得到每个像素在图片上的位置:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"const pi = 10000; //如对第10000个像素点 \nconst width = 1000; //该图片的宽度为1000 \nconst pos = { \n height: pi*width,\n width: parseInt(i / width, 10)\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"得到有效区域后,再分析该区域像素数据,可以得出,如下像素值"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"[ \n97, 117, 116, 255, #起始标识 a,u,t \n111, 116, 114, 255, #起始标识 o,t,r \n97, 99, 107, 255, #起始标识 a,c,k \n0, 0, 27, 255, #id 长度 27 \n97, 50, 49, 255, #id值 a,2,1 \n52, 49, 46, 255, #id值 4,1,. \n49, 46, 115, 255, #id值 1,.,s \n101, 97, 114, 255, #id值 e,a,r \n99, 104, 98, 255, #id值 c,h,b \n97, 114, 46, 255, #id值 a,r,. \n115, 101, 97, 255, #id值 s,e,a \n114, 99, 104, 255, #id值 r,c,h \n98, 111, 120, 255, #id值 b,o,x 0, 0, \n255, 255, 0, 0, \n255, 255, 0, 0, \n255, 255, 0, 0, \n255, 255, 0, 0, \n255, 255, 0, 0, \n255 ...\n]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前三个像素表起始标识,第四个像素表id的长度值,即27个字符。根据这个长度读取后面的字符并将每个像素点除第四位外的其它值解析成asc码"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"String.fromCharCode(97)//=> aString.fromCharCode(117)//=> u"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/30/30d1aa4e6af0fb0caa0786a0186b257c.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们即可得出其表示的数据含义:前三个像素的表起始标识,解析为 autotrack,据第四像素指定长度(27)字符,解析后面的code为 a2141.1.searchbar.searchbox。再显示到图像上,效果如下:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/59/59a225259d88e62d1b9d2c0d490167f4.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为显示友好对 \"a2141.1.searchbar.searchbox\",只显示了最后一段。这样我们即得到了该元素的位置,又得到了其id。用户在该图上的点击操作,即可轻松选中埋点区域并得到其id,为该id绑定配置需要的参数值。生成配置文档并打包到该App中,通过sdk解析该份配置,通过id将配置与页面元素对应上,就大功告成了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章