这篇文章将向大家分享团队在小程序 webview 方面的开发心得,以微信小程序为主要环境,介绍在业务开发中处理小程序webview内嵌H5所遇到的问题及解决方案。具体将从小程序平台与H5差异、小程序内嵌webview通信、小程序webview常见问题展开叙述。
二、平台差异下面将浅析并回顾一下小程序和H5在渲染方面的几点差异。2.1 小程序方面以微信小程序为例,相信今天大部分的读者对微信小程序的系统架构都比较熟悉了,总体来讲分为两部分:
- iew 视图端通过小程序的框架,将用户采用 WXML 和 WXSS 描述的UI信息处理成 H5 元素,最终交给 WebView 去渲染;
- 逻辑层运行JS逻辑,并且可以调用具有微信开放能力的 JSAPI。逻辑和视图分离,通过事件和数据彼此之间建立联系。
微信小程序使用 WebView 渲染,与原生客户端的是两套不同的视图渲染体系。一个小程序存在多个界面,所以渲染层存在多个 WebView。逻辑层采用 JSCore 线程运行 JavaScript 脚本。这两个线程间的通信经由小程序 Native 侧中转,逻辑层发送网络请求也经由 Native 侧转发。
如此设计的初衷是为了管控和安全,微信小程序阻止开发者使用一些浏览器提供的,诸如跳转页面、操作 DOM、动态执行脚本的开放性接口。将逻辑层与视图层进行分离,视图层和逻辑层之间只有数据的通信,可以防止开发者随意操作界面,更好地保证了用户数据安全。同时小程序设计一套组件框架—— Exparser ,基于这个框架内置了一套组件,以涵盖小程序的基础功能,便于开发者快速搭建出任何界面,同时也提供了自定义组件的能力,开发者可以自行扩展更多的组件,以实现代码复用。
值得一提的是,内置组件有一部分较复杂组件是用客户端原生渲染的,同时微信团队又通过结合 Flutter 和 LV-CPP,把实现代码收敛在 C 和 Dart 上,进一步简化了基于小程序技术栈实现跨平台业务开发的框架维护成本,以提供更好的性能。
2.2 小程序webview内嵌H5
H5页面投放在小程序WebView,在配置完合法域名后,即可在小程序应用中展示。那么,针对不同厂商小程序,可能法务、厂商合规有所差异,需要H5判断所在的环境,去调用不同 api 方法,展示不同的业务页面。
在携程内部封装了小程序CWX的SDK,小程序端主要采用原生 Taro框架,H5这块主要是NFES(React)和Vue,无论是哪一段端都通过一个CWX来连接,内部封装了各端通用的功能比如登录、发布、支付、个人中心等功能,这些功能都可以直接通过CWX这个中间件进行调用。
并且,H5在检测到当前处于小程序webview环境下时,会根据环境异步加载SDK文件、及其厂商的JS-SDK,初始化小程序版本wx.config。这里的关键点是我们要做个api调用的队列,因为sdk加载异步的过程,如果期间页面内发生了api调用,那肯定得不到正确的响应。因此要做个调用队列,当sdk初始化完毕之后再处理这些调用。其实CWX原理很纯粹,如果你想实现多端适配,那么只需要根据所在的环境去加载不同的sdk就可以了。
> 下面简要列举一下工作中常用的几个小程序环境判断:
使用时的注意事项:
使用前,最好查阅相应小程序的文档,因为各个小程序对API的支持程度不同。引用bridge.js的方式视情况而定,因为 bridge.js 引入JSSDK的方式是 为 head标签添加 script标签,若在 head标签中引入bridge.js,就会报错若打开h5,显示“页面访问受限”之类的提示信息,可尝试下方的操作:(这种情况,一般是打开测试环境的h5 url 时出现)勾选IDE中的“忽略webview域名合法性检查” 和 “忽略request域名合法性检查”。
【快应用相关】
目前Vivo、Oppo、华为三家厂商已支持新版快应用,Vivo、OPPO已上线,华为正在测试中,小米不支持。对于新版快应用,若H5页面需要调用新版快应用JS-SDK中提供的API,需要提前将该H5链接的域名配置到可信任的网址里(应写成正则表达式的形式进行配置)。
【头条相关】
头条小程序的redirectTo、navigateTo 等页面跳转的 api 只支持 url 为 / 开始的绝对路径。
【支付宝相关】
目前的1.0.73版 bridge.js 判断是否处于支付宝小程序的方法,会将h5处于支付宝小程序、h5处于支付宝内置浏览器都判断为处于支付宝小程序内。因此,在调my.XXXX之前,需要先调环境工具函数判断一下,确保确实是处于支付宝小程序内,而非支付宝内置浏览器内。
三、小程序内嵌webview通信3.1 小程序中h5页面onShow和跨页面通信的实现首先想到的是onShow方法的实现,之前有人提议用visibilitychange来实现onShow方法,但调研过后,发现这种方式在ios中表现符合预期,但是在安卓手机里,是不能按预期触发的。
于是就有了下面的方案,这个方案需要h5和小程序的webview都做处理。核心思想:利用webview的hash特性。
- 小程序通过hash传参,页面不会更新(这个和浏览器一样)
- h5可以通过hashchange捕获最新参数,进行自定义逻辑处理
- 最后执行window.history.go(-1)
为什么要执行window.history.go(-1) ? 因为hash变更会导致webview历史栈长度 1,用户需要多一次返回操作。但这一步明显是多余的。同时window.history.go(-1)后,会把webview在hash中添加的参数去掉,还能保证和之前的url一致。
3.2 注意点出于平滑接入的考虑,不能上来搞一刀切,要保证现有页面不再做任何修改的情况下继续访问。新能力要通过额外参数区分,如:检测url中的query部分,带有 __isonshowpro=1 再进行通过hash方式传参。改造原有逻辑,让__isonshowpro=1时,hash处理逻辑优先级最高参数定义,在前面加入了两个下划线,目的是为了区分url中正常的参数。我们来看看h5端的sdk是怎么实现的。