前言
提到混合式开发的童鞋,是不是想到是指 React Native
, Weex
,或者流行的 Flutter
, 有意观赏上类分享,那友情提醒误入文章的你,打开控制台输入 history.go(-1)
。 本篇总结的混合式开发,指 原生App 与 H5 的互相传递参数或交互逻辑,场景就是H5嵌套于原生中,通过原生访问H5页面。
至于原生APP为什么采用H5,想必大家可能想到一个原因是,原生APP审核需要一定时间,营销推广活动比较频繁的公司,所以会选择H5开发。
本篇主要带领大家,熟悉了解 H5与原生交互 需求中,H5部门与原生部门这块相关协调工作,让大家有彼此工作大致了解。欢迎提补充建议或是错误指正。
安卓、H5之间传参交互
安卓 与 H5前端 协调工作较为简单,只需要安卓将交互方法注册到window的对象名,提供给H5。然后就是两边的自我代码开发。
安卓方面工作
- 搭建安卓与H5交互通道,定义提供原生通道名,并项目启动时调用。
- 书写安卓、H5,相互传参的方法
- 与H5联调方法,是否正常实现传参或功能逻辑
下面代码片段,通道名设置为 Flight
, 交互方法在 Flight
类实现
@SuppressLint("JavascriptInterface")
private void initWebViewCallBack() {
Log.e(TAG, "initWebViewCallBack: ");
if (flightWv != null) {
flightWv.addJavascriptInterface(new Flight(), "Flight");
}
}
public class Flight {
@JavascriptInterface
public String getVersion() {
H5Besn bean = new H5Besn();
bean.setCity(Cfg.localityCityName);
bean.setLat(Cfg.myLatitude);
bean.setLon(Cfg.myLongitude);
bean.setVersionName(AppUtils.getVersionName(FlightWebAcitvity.this));
String json = GsonUtils.createJsonStr(bean);
return json;
}
}
H5前端工作
在项目入口文件引入,与原生交互代码。当然考虑到与原生操作过多,避免入口文件臃肿,可在入口文件引入专门原生操作的分流的文件命名为 bride.js
。
- 在
bridge.js
区分 IOS,安卓环境,或者其他环境等,便于安卓方法只注册在安卓设备下,避免冗余无用代码 - 安卓方法调用
下面前端代码相关片段:
import store from '@/store'
import { setupWebViewJavascriptBridge } from '@/utils'
// ...
// 判断环境,以下添加了 && u.indexOf('matafyApp') 此类并唯一标识哪个APP标识(找原生开发同学寻要)
const urlParams = urlParamsObj()
const u = navigator.userAgent
const isAndroid = (u.indexOf('Android') > -1 || u.indexOf('Adr') > -1) && u.indexOf('matafyApp') > -1 // Android终端且在原生app内
const isiOS = u.indexOf('iPhone') > -1 && u.indexOf('matafyApp') > -1 // iOS终端且在原生app内 !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
const isMobile = !!u.match(/AppleWebKit.*Mobile.*/) // 是否为移动终端
const isMiniprogram = urlParams['weixinId'] // 微信7.0.0开始,允许userAgent来判断小程序环境,兼容为携带weixinid的路径
// ......
// 判断处于哪个环境下,并存于vuex的store中,不过如果你项目未使用vuex,大可不必使用。
if (isMobile) {
if (isAndroid) {
store.dispatch('app/setDevice', 'android')
} else if (isiOS) {
store.dispatch('app/setDevice', 'ios')
} else if (isMiniprogram || window.__wxjs_environment === 'miniprogram') {
if (isMiniprogram) sessionStorage.setItem('weixinId', isMiniprogram)
store.dispatch('app/setDevice', 'wx_program')
} else {
store.dispatch('app/setDevice', 'mobile')
}
} else {
store.dispatch('app/setDevice', 'mobile')
}
// 原生交互方法
switch (store.getters.device) {
case 'android':
// 获取token
const setToken = (token) => {
store.dispatch('app/setToken', token)
}
// 获取版本号信息
const setVersion = (version) => {
localStorage.setItem('sendVersion', version)
}
window.setVersion = setVersion // 注意:调用方法,定要注册在window对象下
window.setToken = setToken
break;
// ...
}
IOS、H5之间传参交互
IOS 与 H5,不需要像安卓提前告知暴露的对象名。
IOS方面工作
- 安装与H5交互的通道
pod 'WebViewJavascriptBridge', '~> 6.0'
- 以下IOS代码用法:
也可参考github代码,点击链接
- Import the header file and declare an ivar property:
#import "WebViewJavascriptBridge.h"
- Instantiate WebViewJavascriptBridge with a WKWebView, UIWebView (iOS) or WebView (OSX):
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
- Register a handler in ObjC, and call a JS handler:
[self.bridge registerHandler:@"ObjC Echo" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC Echo called with: %@", data);
responseCallback(data);
}];
[self.bridge callHandler:@"JS Echo" data:nil responseCallback:^(id responseData) {
NSLog(@"ObjC received response: %@", responseData);
}];
H5前端工作
前端工作也只有短短两步,第一步,就是将连接webview通道的方法,可存放于函数的文件,便于多么模块调用。第二步,调用通道方法,进行注册原生需要调用方法或主动调用原生方法。
函数库文件 src/utils/index.js
文件部分代码如下:
/**
* @export ios与js建立连接基础方法
* @param {Function} 调用方法的回调
*/
export function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
return callback(window.WebViewJavascriptBridge)
}
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback)
}
window.WVJBCallbacks = [callback]
var WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(() => {
document.documentElement.removeChild(WVJBIframe)
}, 0)
}
项目处理原生文件 src/utils/bridge.js
,需项目入口文件引入,部分代码如下:
import store from '@/store'
import { setupWebViewJavascriptBridge } from '@/utils'
// ...
switch (store.getters.device) {
// ...
case 'ios':
setupWebViewJavascriptBridge((app) => {
app.registerHandler('sendToken', (token, responseCallback) => { // 获取IOS原生APP传递过来的token,存于前端数据池(仓库)
store.dispatch('app/setToken', token)
})
}
break;
// ...
}
常见的H5与原生交互的应用场景
原生与H5交互传参的应用场景,情况分为两类。第一,原生传递H5参数或回调相关操作;第二,H5主动获取原生参数或进行回调相关操作。
各个公司各个项目需求不一致,例如,token传递,经纬度传递,APP版本信息传递,app设备Id的传递,设置原生系统栏的背景色字号色的传递,调用原生方法打开第三方浏览器或者内置浏览器的方法,h5控制原生返回键的逻辑等等