一、背景
为了节约开发成本,有时也为了可以和小程序开发同步,移动端的一些业务常常交给网页端的同学去做,原生则负责为网页端同学提供一个稳定,可靠的WebView环境,必要时,还要给网页端同学提供一些接口,用于调用原生能力。
相信大家对于这种混合开发的场景都十分常见。
现如今,随着实时音视频通信的流行,WebRTC技术也会常常被用到。有时我们希望直接在H5页面中使用WebRTC(使用自部署的stun/turn服务),往往会遇到哪些挑战?
- 系统WebView内核在不同的机器上表现不一致,常常带来适配噩梦,甚至无法支持
- 权限问题坑较多
二、抹平设备差异
TBS内核方案
即便不是为了解决WebRTC环境问题,我们也应该考虑为H5同学去尽量抹平WebView内核带来的差异。如果我们有WebView sdk团队,可以使用自研的WebView内核。但除了大厂以外,很难有这方面的资源。
所以目前我们只能借助一些免费的第三方sdk,如腾讯TBS(以前叫X5内核)
TBS免费版内核是基于chromium m89版本的,且在多年前的623xx版本就实现了对WebRTC的支持,这有助于我们隔离不同设备的系统WebView内核差异。
但是,我要说但是了,免费版还是有免费版的问题。
无法稳定下发的动态部署
TBS的内核是动态部署的,内核文件由腾讯的服务器下发。既然是动态下发的,那就有千千万万种可能会下发失败。如果下发失败,TBS会降级到系统内核。虽然系统内核也是可以继续用的,但就无法达到抹平设备差异的目的了。
最常见的内核下载错误是-134等,官方文档给出的解释是“命中流控”。按照我们监控的线上数据,普通时段失败率在3%左右,而且到了周末会激增,因为周五周六(18:00-21:00)属于服务器维护期,不支持下载。
尽管动态部署的稳定性不可控,但TBS官方也并不提供免费的静态部署的方案。当然,可能存在某些手段绕过官方下发,但不在本文讨论范畴。
还记得大明湖畔的 bugly OTA 功能吗?
去年bugly就有过关停了免费OTA业务的先例,而今年TBS也开始推商业版了。虽然TBS已经免费了多年,但还是不排除什么时候TBS也会关停免费版,毕竟腾讯的产品,不氪金你能变强吗?
以下仍然基于TBS方案来完成实现
尽管以上有这么多的风险预警,因为没有找到更为可靠的平替方案,所以以下实现仍然抛砖引玉的基于TBS方案。
如果大家有更好的方案也可以在评论区说下哦~
三、权限控制
权限动态申请
众所周知,Android 6.0后推出了权限的动态申请。WebRTC作为一种需要用到相机和麦克风的技术,自然逃不过权限申请。
对于系统WebView内核,来自H5的权限申请一般在WebChromeClient中回调。
webview.setWebChromeClient(new WebChromeClient(){
// Need to accept permissions to use the camera
@Override public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources()); }
}
);
但TBS拦截了原始的WebChromeClient中onPermissionRequest回调,而是通过IX5WebChromeClientExtension的onPermissionRequest来重新封装了来自H5的权限申请回调
webview.setWebChromeClientExtension(new IX5WebChromeClientExtension() {
// ....... 省略其他方法实现
@Override public boolean onPermissionRequest(String s, long l, MediaAccessPermissionsCallback mediaAccessPermissionsCallback) {
long allowed = 0;
allowed = allowed | MediaAccessPermissionsCallback.ALLOW_AUDIO_CAPTURE;
boolean retain = true;
mediaAccessPermissionsCallback.invoke(s, allowed, retain);
return true;
}
});
其中,对于MediaAccessPermissionsCallback.invoke()
/**
* @params origin 请求权限的网页地址
* @params resouorces 请求的权限类型,位操作识别
* @params retain 是否缓存结果,缓存后,同一个origin申请同一权限都返回此结果而不会再次回调
*/
public void invoke(String origin, long allow, boolean retain);
扩展实现
当然,出于安全合规考虑,回调中还可以做一些扩展实现:
- 对origin进行鉴权,对于不在白名单的网址,一律直接拒绝权限
- 动态申请权限时,弹窗告知用户申请权限的具体用途,避免合规风险
权限静态申请
处理完动态申请的权限后,发现在一些设备上,H5端与音频相关的初始化仍然会失败,最终发现是以下权限需要静态添加到AndroidManifest
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
三、WebRTC功能测试
完成了配置,就需要测试下以上措施是否奏效,以下提供了两个快速验证的线上工具:
ZEGO webrtc测试
地址: zegodev.gitee.io/zego-expres…
测试方法很简单,点击“开始测试”即可,测试完后,页面会告知每一项的测试结果。
Janus WebRTC Server VideoCall
地址:janus.conf.meetecho.com/videocallte…
可通过这个demo验证网页端的WebRTC视频通话
总结
本文介绍了基于TBS为网页端同学提供一个完整的WebRTC支持的实践方案,并在实际业务中落地。诚然TBS为这个方案提供了支撑,也成为了这个方案中最大的风险,但苦于没有好的平替方案,又希望能为用户提供更可靠的服务,最终我们选择了默默充钱氪金[doge]。
如果本文对你有帮助,记得点个赞哦~