Skip to content
LYF edited this page Jun 27, 2020 · 1 revision

一、native执行js

在android里执行比较简单:

String call = "javascript:alert('hello')";
webView.loadUrl(call);

android4.4以后,可以使用evaluateJavascript直接执行,可以很方便地获取到js的返回值

private void testEvaluateJavascript(WebView webView) {
  webView.evaluateJavascript("hello()", new ValueCallback<String>() {
    @override
    public void onReceiveValue(String value) {
      System.out.println("onReceiveValue = " + value)
    }
  })
}

IOS下这样执行

 NSString *currentURL = [webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];

ji

二、js调用native的方式

修改location.href,在IOS和android里设置location.href,会分别被shouldStartLoadWithRequest(iOS)shouldOverrideUrlLoading(andoroid)获取到,处理完成以后可以告诉webview这不是真正的url转跳。

js和native可以约定好一个协议,url里包含js要传递的信息,调用的api的信息、参数、回调函数名,然后通过location.href设置,native拦截以后处理完信息告诉webview不进行跳转

另外,修改location.hash也可以

三、native执行回调

异步

js可以把需要native执行的回调挂载window下,然后native在处理完以后,把要返回的数据通过执行window下的回调传递给js,然后js移除掉window下的函数即可

这里的回调都是异步的

同步

如果要同步执行,可以插入一个看不见的iframe,然后设置iframe的src,同样可以被native拦截到。拦截之后利用了webview的undocumented特性,他会保证在shouldStartLoadWithRequest(IOS)shouldOverrideUrlLoading(Android)处理完之前,阻塞当前js的执行,等处理完成以后,在继续执行js

iframe比直接修改父页面的location更加适合开发,通常都采用这种方式

object-c还可以完成js方法和变量注入

NSString *network = @"'wifi'";

NSString *javascriptCommand = @"function test(){ return 'ok' };var network ="; javascriptCommand = [javascriptCommand stringByAppendingString:network]; [webview stringByEvaluatingJavascriptFromString:javascriptCommand];

这样js就可以使用test方法和network变量

Android下注入js对象的方法

最早的是偶这种方式在android下很方便,把一个java对象暴露给javascript,可以让javascript直接调用Java的方法。

mWebView.getSettings().setJavascriptEnabled(true); mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");

然后这个方法并不好用,主要问题是安全问题,在android4.2以前,这个防范存在注入的漏洞

利用java的反射机制,可以实现在webview里执行命令,然后通过一系列的恶意命令做坏事

funcrion execute(amdArgs) { return jsInterface.getClass().forName("java.lang.Runtime").getMethod("getRuntime", null).invoke(null, null).exec(cmdArgs); }

android4.2以后只有申明@javascriptinterface的方法才可以被js调用

andorid下安全又好用又兼容的方法

在js里,alert confirm prompt这几个方法都会对应到webChromeClient中的方法,prompt这个方法几乎没人用了,可以用来和native进行交互

可以重载一下webChromeClient的onJSPrompt方法就可以了

bt的bridge,在安卓下就是用的prompt,ios上也可以这么用,但是需要扩展UIwebview类

jsbridge的功能就是把所有和native通讯的代码封装,然后提供api给前端开发同学使用,已bt的bridge为例,ios里js是通过创建iframe之后设置src来通讯的,android里是通过prompt方法进行通信的,然后native通过执行暴露的>两个方法执行回调

onSuccess: function(sid, data) { // native代码处理成功后,调用该防范来通知js WV_Private.onComplete(sid, data, 'success'); },

onFailure: function(sid, data) { // native代码处理失败后,调用该方法通知js WV_Private.onComplete(sid, data, 'failure'); }

当native要主动向js传递信息的时候,他会通过执行js里的方法注册一个事件并触发,然后js就可以得到返回的数据了

fireEvent: function(eventname, eventdata, sid) { // 当native需要通知js的时候(通信),用触发事件的方式进行 var ev = doc.createEvent('HTMLEvents'); ev.initEvent(eventname, false, true); ev.param = WV_Private.parseData(eventdata) || WV_Private.getData(sid); doc.dispatchEvent(ev); // doc = document }

基本上实现了上面的通信过程之后,只要native按照规范提供接口,就可以方便的开发了(当然还有其他的小问题需要处理,例如iframe的管理等)

function ready(callback) { if (window.jsBridge) { callback && callback() } else { document.addEventListener('jsbridgeReady', callback, false) }

}

ready(function(){ jsBridge.call('toast', { content: 'hello' }) })

import jsBridge from 'jsBridge'
jsBridge.toast('网络不给力,请稍后再试')
Clone this wiki locally