之前介绍了HarmonyOS的Web组件的简单使用和离线包方案,本篇文章主要说的是Web组件的白屏检测的方案
APP白屏问题简介
Web
白屏问题通常是在客户端上经常遇到的一种常见问题,尤其是对于Android来说,多个版本的碎片化导致用户有多种不同版本的chrome内核,那么对于HarmonyOS来说也是一样的,一般来说Web
白屏有以下几种原因
- Web组件配置问题,对于APP来说,这种可能性很小,主要是开发阶段遇到,比如没有开启网络权限、JavaScript未启用、缓存问题等
- 网络问题,如果设备网络条件不好,尝试加载网络内容时可能导致白屏,这个可以考虑离线包方案解决可以参考之前那篇文章
- SSL证书问题 如果WebView加载的内容涉及到HTTPS,SSL证书验证失败可能导致页面无法加载。
- HTML、JavaScript语法兼容问题,由于前端这几年发展迅速,导致语法变更快,很多框架比如vue、react等在构建的时候,ES语法不兼容在客户端上经常见到,这种大多都是兼容性问题,比如只在某些低版本机型可见,此类问题比较难以感知,只有用户反馈过来才能去响应
总体来说Web白屏问题是没发根治的,只能通过合理的线上监控,去发现解决一些疑难的白屏问题,因此对于客户端APP来说白屏检测基本上是必有功能,既可以去做白屏监控,也能通过检测来统计用户前段加载页面时所需要的白屏时间,为Web秒开优化做有效数据验证。
白屏检测方案
在Android和iOS端白屏检测方案比较成熟,我们参考字节的方案来简单讲一下判断白屏的先觉条件把
字节方案原文如下:
...我们把 WebView 截图的图片进行缩小到原图的 1/6,遍历检测图片的像素点,当非白色的像素点大于 5% 的时候我们就认为是非白屏的情况,可以相对高效检测准确得出详情页是否发生了白屏。
参考 https://www.toutiao.com/article/6871177699826598403/?wid=1702706377614
首先先对Web组件进行截图,但如果按照图片整个大小来遍历像素点,这耗费的时间和性能在客户端上时不太现实的,我们一般把图片缩小,然后在对图片进行抽样检测例,抽样一般都是按照小区域来划分,判断这些小区域的点位的白屏信息,来判断页面的白屏情况,采样点越细,判断的越精确,但同时性能损耗页越大,采样方案 如下图所示
HarmonyOS Web组件白屏检测
话不多说,我们开干,
1. 首先,我们先对web组件进行截图,
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Web({ src: this.url, controller: this.webviewController }) .layoutWeight(1) .width("100%") .id("web-view") ... ... ...
componentSnapshot.get("web-view", (error: Error, pixmap: image.PixelMap) => { pixmap.getImageInfo().then((info) => { console.info("image info: width=" + info.size.width + ",height=" + info.size.height + ",density=" + info.density); }) })
|
2. 定义白屏采样参数
1 2 3 4 5 6 7 8
| declare class CheckParam { imageMap: image.PixelMap compressRatio: number; threshold: number; pointNum: number; regionSize: number; color: number; }
|
参数解释
- imageMap,采样图片
- compressRatio,采样图片压缩倍数
- threshold,白屏采样阈值,单位:百分比
- pointNum,白屏采样点数 = n*n
- regionSize,采样区域大小
- color,采样白屏对比颜色,一般为白色,如果是黑色背景就是黑色,按照Web组件的背景色来判1断
3. 白屏检测具体实现
首先定义白屏检测的异步方法,参数是 Promise
1 2 3
| function checkWhiteScreen(param: CheckParam): Promise<boolean> { ... }
|
按照param.compressRatio 的,来压缩图片的大小再通过getImageInfo解析图片的具体信息
1 2 3 4
| param.imageMap.scale(1 / param.compressRatio, 1 / param.compressRatio) .then(() => { return param.imageMap.getImageInfo(); })
|
根据上一步得到的info信息来把图片按照采样区域生成ArrayBuffer数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| then(info => { let width = info.size.width; let height = info.size.height; let size = param.regionSize; let xStep = Math.floor(width / param.pointNum); let yStep = Math.floor(height / param.pointNum); let promiseArr = [] as Promise<ArrayBuffer>[]; for (let i = 0; i < param.pointNum; i++) { for (let j = 0; j < param.pointNum; j++) { let x = i * xStep; let y = j * yStep; const buffer = new ArrayBuffer(size * size * 4); promiseArr.push(param.imageMap.readPixels({ pixels: buffer, offset: 0, stride: size * 4, region: { x: x, y: y, size: { width: size, height: size } } }).then(() => { return buffer })); } } return Promise.all(promiseArr); })
|
遍历数组然后判断每一个像素点的信息统计后判断白屏率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| then(buffers=>{ let whitePointNum = 0; let cr = param.color >> 16 & 0xff; let cg = param.color >> 8 & 0xff; let cb = param.color & 0xff; let ca = param.color >> 24 & 0xff; for (let i = 0; i < buffers.length; i++) { let buffer = buffers[i]; let dataView = new DataView(buffer); for (let j = 0; j < buffer.byteLength; j += 4) { let r = dataView.getUint8(j); let g = dataView.getUint8(j + 1); let b = dataView.getUint8(j + 2); let a = dataView.getUint8(j + 3); if (r === cr && g === cg && b === cb && a === ca) { whitePointNum++; } } } let whitePointPercent = whitePointNum / (param.pointNum * param.pointNum * param.regionSize * param.regionSize) * 100; console.info("白屏检测耗时:" + (Date.now() - time) + "ms"); if (whitePointPercent >= param.threshold) { console.info("白屏" + whitePointPercent + "%"); return true; } else { console.info("非白屏" + whitePointPercent + "%"); return false; } })
|
完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| import image from '@ohos.multimedia.image'; declare class CheckParam { imageMap: image.PixelMap compressRatio: number; threshold: number; pointNum: number; regionSize: number; color: number; } function checkWhiteScreen(param: CheckParam): Promise<boolean> { const time = Date.now(); return param.imageMap.scale(1 / param.compressRatio, 1 / param.compressRatio) .then(() => { return param.imageMap.getImageInfo(); }).then(info => { let width = info.size.width; let height = info.size.height; let size = param.regionSize; let xStep = Math.floor(width / param.pointNum); let yStep = Math.floor(height / param.pointNum); let promiseArr = [] as Promise<ArrayBuffer>[]; for (let i = 0; i < param.pointNum; i++) { for (let j = 0; j < param.pointNum; j++) { let x = i * xStep; let y = j * yStep; const buffer = new ArrayBuffer(size * size * 4); promiseArr.push(param.imageMap.readPixels({ pixels: buffer, offset: 0, stride: size * 4, region: { x: x, y: y, size: { width: size, height: size } } }).then(() => { return buffer })); } } return Promise.all(promiseArr); }).then(buffers=>{ let whitePointNum = 0; let cr = param.color >> 16 & 0xff; let cg = param.color >> 8 & 0xff; let cb = param.color & 0xff; let ca = param.color >> 24 & 0xff; for (let i = 0; i < buffers.length; i++) { let buffer = buffers[i]; let dataView = new DataView(buffer); for (let j = 0; j < buffer.byteLength; j += 4) { let r = dataView.getUint8(j); let g = dataView.getUint8(j + 1); let b = dataView.getUint8(j + 2); let a = dataView.getUint8(j + 3); if (r === cr && g === cg && b === cb && a === ca) { whitePointNum++; } } } let whitePointPercent = whitePointNum / (param.pointNum * param.pointNum * param.regionSize * param.regionSize) * 100; console.info("白屏检测耗时:" + (Date.now() - time) + "ms"); if (whitePointPercent >= param.threshold) { console.info("白屏" + whitePointPercent + "%"); return true; } else { console.info("非白屏" + whitePointPercent + "%"); return false; } }) } export { checkWhiteScreen }
|
总结
在本文中,我们深入探讨了HarmonyOS中Web组件的白屏问题及其检测方案。
文章重点介绍了一种基于字节的白屏检测方案,通过对WebView截图、压缩和采样像素点的方式,遍历检测小区域的非白色像素点数量,从而判断是否出现白屏问题。方案考虑了压缩比、采样阈值、采样点数、采样区域大小和颜色等参数,使得检测更加灵活和精准。
在HarmonyOS中的具体实现中,使用了PixelMap和相关的图像处理API,通过异步方法和Promise链式调用的方式,实现了对Web组件的白屏检测。通过该方案,开发者能够在应用中及时发现白屏问题,提高应用的稳定性和用户体验。
总体而言,白屏问题作为移动应用中常见的用户体验难题,需要综合考虑多个因素,结合合适的检测方案。本文所介绍的HarmonyOS Web组件白屏检测方案提供了一种实用的思路和代码实现,对于开发者优化应用性能、提升用户体验具有积极意义。