IOS、Android与H5通信-JsBridge原理(总结)

H5和原生app(ios,android)交互的载体基本都是基于Webview,可以把Webview看作是一个性能打八折的移动浏览器。

ios调用Javascript

简单说下这几种:WKWebView 、UIWebView、JavaScriptCore

WKWebView:苹果在ios8之后也引入了专门负责处理网页视图的框架WebKit,Webkit是啥,接触过H5、chrome的肯定都知道。chrome使用的也是基于webkit内核的Chromium引擎。WKWebView优点很多,支持更多H5特性,刷新效率及内置手势等,更加强大,性能也更优,不一一列举,如果大家app不需要兼容7及以下版本,不需要拦截一些请求,直接解析本地一些文件,建议使用WKWebView。

UIWebView:较老webview,第一代。其中stringByEvaluatingJavaScriptFromString方法提供了OC与js交互的能力。

JavaScriptCore(ios7及以后版本)。JavaScriptCore框架是webkit重要组成部分,主要是对JS进行解析和提供执行环境,Javascript的虚拟机,有点类似v8引擎,我自己这么理解:)正是它为ios提供了执行JavaScript代码的能力。ReactNative应该都是通过JavaScriptCore去解析的(自己猜测)。

微信小程序的逻辑层也是由JavaScriptCore作为运行环境。

Javascript 调用 ios(oc、swift)原理:

目前兼顾兼容性、比较成熟的方案还是通过拦截URL的方式。

UIWebView的特性,在UIWebView内发起的所有网络请求,都可以在Native层被捕捉到。

利用这一特性,就可以在UIWebView内发起一个自定义的网络请求,一般格式:jsbridge://method?参数1=value1&参数2=value2

于是在UIWebView中,只要发现是jsbridge://开头的url,就不进行内容的加载,而是执行相应的逻辑处理。

嵌入webview的h5中的js一般是通过动态创建隐藏iframe标签,赋值上文提到的链接给src,iframe不会引起页面调转、刷新。

主要代码:

var src= 'jsbridge://method?参数1=value1&参数2=value2';

var iframe = document.createElement('iframe');

.style.display = 'none';

.src = src;

document.body.appendChild(iframe);

//再删除

iframesetTimeout(function() {

.remove();

}, 50);

Android和Javascript互相调用

Android WebView也是基于WebKit引擎的一个组件,Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。

这个组件功能非常强大,除了具有一般View的属性和设置外,还可以对url请求、页面加载、渲染、页面交互进行强大的处理。

Android调用JS代码的方法主要有2种:

1、WebView的loadUrl

2、WebView的evaluateJavascript

JS调用Android代码的方法主要有3种:

1、WebView的addJavascriptInterface进行对象映射(低版本Android4以下好像有一些安全问题,本人没有验证)

2、WebViewClient 的 shouldOverrideUrlLoading 方法回调拦截 url

3、WebChromeClient 的onJsAlert、onJsConfirm、onJsPrompt方法回调拦截JS对话框alert()、confirm()、prompt() 消息

一般常用onJsPrompt、prompt进行回调拦截

JSBridge是Native代码与JS代码的通信桥梁

设计一个jsbridge主要分几大步骤:

第一步:设计出一个Native与JS交互的全局中间对象

第二步:JS如何调用Native

第三步:Native如何得知api被调用

第四步:分析url-参数和回调的格式

第五步:Native如何调用JS

第六步:H5中api方法的注册以及格式

 

结合场景运用:

运用场景描述:在H5端点击页面的发送按钮通知APP打开微信分享功能,交互写在发送事件函数中,调起微信分享功能由app端操作

//给到app的json参数
let jsonData = {
    reload: this.$route.query.no_reload ? false : true, //true需要重新加载返回列表页,false不需要(根据需求定)
    title: '上门试驾邀请', // 分享标题
    desc: '邀请您试驾体验xxxx', // 分享描述
    link: 'https://xxxxx', // 分享链接
    imgUrl:  '', // 分享图标
}

 判断设备

device() {
  let u = window.navigator.userAgent;
  //android终端
  let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
  //ios终端
  let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  return {android: isAndroid, ios: isiOS}
},

JS与IOS交互方式一:WKScriptMessageHandler

WKWebView有一个内容交互控制器,该对象提供了通过JS向WKWebView发送消息的途径。需要设置MessageHandler,大家把这个功能简称为MessageHandler。

IOS具体实现参考:链接

这里只说js调用

/ window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
// 这个name就是设置MessageHandler的第一个参数,与IOS约定的方法名
// messageBody 必须是json格式,为空时传null
window.webkit.messageHandlers.ShareContract.postMessage(jsonData);

JS与IOS交互方式二:WebViewJavascriptBridge交互 拦截url做事件处理,如果要传参数,不建议用这种

//模拟 h5页面在app端的跳转 
let data = '{"type": "basisTongji", "url":"' + "https://xxxx/basisTongji.html" + "}";
window.WebViewJavascriptBridge.javaScrpitRresponseJson(data);

Android端交互

h5js交互 ios ios与h5交互原理_Android

 

冒号前面区分是什么功能,冒号后面是接收的参数

window.location.href = "ShareContract:" + JSON.stringify(jsonData);

运用场景二:登录失效的情况下,通知APP端,需要跳转到登录页面

  • exit:true是和安卓约定的功能名及参数
  • logout 是和IOS约定的方法名,注意当值为空的时候,需要传null,不能什么都不写,不然会走代理。。。
let deviceP = device()
if (deviceP.android) {
  window.location.href = "exit:true"
}
if (deviceP.ios) {
  //ios 交互
  window.webkit.messageHandlers.logout.postMessage(null);
}