第05课:使用 WebView 和运营页通讯

知识点:

  • 创建一个浏览网页的组件
  • 注入 JS 并和网页通讯

RN 默认提供了一个 WebView 组件,可以使用这个组件在 App 内打开一个网页,就像在微信里做的那样。

但是电商 App 其实需要这个页面有很多和 App 的交互,比如打开商品详情页、加入购物车、分享等操作,这里就需要使用自定义 App 和 WebView 通讯协议的手段了。

网页浏览页

在 home 下新建一个 browser.js 文件,项目中只要是打开网页的都会跳转到这里,需要注意一下,变量不要使用 url,在有些情况会发生错误。

将传入的 webPath 参数放入 state 中,根据参数加载网页,这里要注意中文的问题,同时给网页加一个时间戳,禁止网页缓存在手机上。

``` javascript let urls = decodeURIComponent(this.props.navigation.state.params.webPath || ''); if (urls.indexOf('?') > 0) { urls += '&t=' + Date.now(); } else { urls += '?t=' + Date.now(); } this.state = { webpath: urls, title: '' }

设置 webview 的一些属性,注意安卓要启用 js 功能,iOS 中要注意兼容网页的 http 和 https 请求。

javascript <WebView //添加一个引用 ref="webview" //设置浏览地址 source={{ uri: this.state.webpath }} //启用安卓的js功能 javaScriptEnabled={true} //正常的滚动停止速度 decelerationRate="normal" //允许https和http一起使用 mixedContentMode="always" //显示loading动画 startInLoadingState={true} //开启缩放 scalesPageToFit={true} //网页互动消息通知 onMessage={(t) => this.onMessage(t)} onLoad={(e) => { this.loaded() log('网页加载成功', e.nativeEvent) }} onError={(e) => { log('网页加载失败', e.nativeEvent) }} />

修改首页的 2 个入口,将入口的位置调整 html 修改为跳转刚才写好的页面。

点击快捷入口的人气排行就能看到打开的网页了,这里注意不要打开姐拼了这个入口,它的里面有用户验证,不验证就是一个白屏。

![enter image description here](http://images.gitbook.cn/c9379c80-2069-11e8-8d07-7f10cb77068c)

监听 webview 的跳转事件,通过网页反馈的 title 设置当前页面的标题`onNavigationStateChange={(e) => this.webChange(e)}`。

注意去掉非标题的字符,让本身的标题看起来更好看一些。

javascript if (!event || !event.title) return; if (event.title.indexOf("http") < 0 && event.title.indexOf("about:") < 0) { this.setState({ title: event.title }); }

### 添加互动能力

RN 的 webview 通过监听 postMessage 发送的消息来达到和网页互相传递消息的功能,这里我们就利用这个方法来做网页和 App 之间的互动。

当网页加载完成之后,我们在网页中插入几个自定义的 js 方法,然后通过 possMessage 的方法按照订好的协议将消息回传给 App,这样就实现了网页和 App 的互动。通过因为所有实现方法都是后注入的,对于调用的人来说是非常方便的,不管后期有什么变化,js 的接口是不会变的。

javascript javascript=window.postMessage("测试消息") //网页加载成功之后 loaded() { this.refs.webview.injectJavaScript(this.javascript); } //网页回调消息到APP onMessage(t) { try { let data = t.nativeEvent.data; log(data) } catch (e) { logWarm(e.message) } }

注意:我们使用的是在网页加载完之后再注入 JS,网页加载完成之前注入会有很多不可定的因素,所以要先注入,不过这个注入不能太多,太多就会不生效。如果 JS 非常多,请把逻辑写在 JS 文件中,然后让需要使用的网页去引用,你只需要注入启动的逻辑就好了。

### 通讯协议

我们这里强制要求所有通讯协议都是 JSON 格式转化的字符串,JSON 中必须是一个数组,第一个数组即是方法名,后面的就是方法的参数。

这里强调一下兼容问题,WebView 在低版本的手机上会遇到兼容问题,比如不支持 ES 6、使用的是严格模式等等,所以需要在写 JS 的时候非常的严格,不能写新的东西,同时还要兼容几个低版本手机。

这里在注入 JS 的时候将本身提供的几个方法循环注入,可以节省很多代码,同时也将 App 自身的一些信息也注入到 JS 中,这样网页中的 JS 就可以非常方便的调用到 App 中的信息了,如果你愿意,甚至可以模仿微信的形式来做这些。

![enter image description here](http://images.gitbook.cn/6e9b5520-207b-11e8-9097-1b883a62cf10)

在 JS 注入之后加载网页的 ready 方法和事件,同时兼容到 JS 提前加载和正常延迟加载的情况。

我们这里使用的是将字符串转化成 JSON 对象的形式来做消息通讯,`window.postMessage(JSON.stringify(data));`。

在接受到消息之后通过格式化字符串,我们就得到了一个完整的方法名 + 参数的数组对象,这里通过类似反射的形式得到当前需要执行的方法,使用 App 中的 this 作为方法内部的 this 来调用方法。

javascript //网页回调消息到APP onMessage(t) { try { let data = t.nativeEvent.data; if (data) { let args = JSON.parse(data); let name = args.shift(); if (this[name]) this[name].call(this, …args) } } catch (e) { logWarm(e.message) } }

这里我们简单的实现几个网页需要调用的方法,在初始化的 SDK 中有一个简单的发布订阅模式,具体的实现方式在网页中,有兴趣的可以看看。

javascript /** * 打开详情页 * @param {*} id */ openDetail(id) { if (/^[0-9]+$/.test(id + '')) { this.props.navigation.navigate('Goods', { id: id }); } else { this.props.navigation.navigate('Goods', { sku: id }); } } setShareInfo(title, desc, shareList, img, viewurl) { this.setState({ title: title, }); } ```

网页中的 SDK 兼容了非 App 环境下的一些东西,并且实现了一个简单的事件监听触发,可以通过这个小方法去监听一些事件,然后在 App 中使用插入 emit 的方式触发事件,比如分享的回调、支付的回调等等。

enter image description here

正式环境下只需要保证 SDK 存在,并且可以判断到是否在 App 环境下即可。

评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页