# H5与Native的交互原理

# 介绍

大部分App开发过程中,都会采用Hybrid App模式进行开发,入比较流行的Cordova技术,WX App,阿里Weex,React Native,这些app 部分都嵌入了H5页面,由于H5Native采用不同的开发技术,那么就涉及到2者之间进行如何通信交互的问题。

# IOS与H5通信

iOS 有2种webview, ios8以上推出了WKWwevView,低于ios8 用的是UIWebView,WKWebView性能上高于UIWebView

# iOS调用H5

Native调用JavaScript语言,是通过UIWebview组件的stringByEvaluatingJavaScriptFromString方法实现,该方法返回js脚本的执行结果。

// Swift
webview.stringByEvaluatingJavaScriptFromSring("Math.random()");

// OC
[webView stringByEvaluatingJavaScriptFromString:@"Math.random();"];

# H5调用iOS

JavaScript调用Native,并没有现成的API可以使用,需要借助iframe实现,原理是在UIWebView内发起的所有网络请求,都可以通过delegate函数在Native层得到通知,所以只需要劫持UIWebView的所有请求

// JS 端关键代码
var url = 'jsbridge://doAction?title=分享标题&desc=分享描述&link=http%3A%2F%2Fwww.baidu.com';
var iframe = document.createElement('iframe');
iframe.style.width = '1px';
iframe.style.height = '1px';
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
setTimeout(function() {
    iframe.remove();
}, 100);

// OC端关键代码
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    print("shouldStartLoadWithRequest")
    let url = request.URL
    let scheme = url?.scheme
    let method = url?.host
    let query = url?.query

    if url != nil && scheme == "jsbridge" {
        print("scheme == \(scheme)")
        print("method == \(method)")
        print("query == \(query)")

        switch method! {
            case "getData":
                self.getData()
            case "putData":
                self.putData()
            case "gotoWebview":
                self.gotoWebview()
            case "gotoNative":
                self.gotoNative()
            case "doAction":
                self.doAction()
            case "configNative":
                self.configNative()
            default:
                print("default")
        }

        return false
    } else {
        return true
    }
}

# Android与H5通信

# Android调用H5

在Android 使用WebView的loadUrl方法调用JS 代码字符串

// 调用js中的JSBridge.trigger() 方法
webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");

# H5调用Android

有2种比较好的方式:

  • 和iOS一样,通过iframe(Android 端通过shouldOverrideUrlLoading方法对url协议进行解析)
  • WebView页面里注入原生js代码,使用addJavaScriptInterFace方法实现

// JAVA 代码
class JSInterface{

    @JavascriptInterface 
    public String getUserData(){
        return "UserData";
    }
}

webView.addJavascriptInterface(new JSInterface(),"AndroidJS")  //浏览器window环境中注入了AndroidJS全局对象

// JS 代码
AndroidJS.getUserData()    // UserData

# 总结

Native 调用 H5 方式

  • 【Android】 通过webView.loadUrl("javascript:JSBridge.trigger('webviewReady')")
  • 【Android】往WebView页面里注入原生js代码,使用addJavaScriptInterFace方法实现
  • 【iOS】 通过webview.stringByEvaluatingJavaScriptFromSring("Math.random()");

H5 调用 Native 方式

  • 【Android】 H5通过iframe 发起网络请求协议,Andriod 端通过shouldOverrideUrlLoading 方法拦截
  • 【Android】 通过addJavaScriptInterFace 方式忘WebView注入全局window 对象
  • 【iOS】 通过iframe 协议拦截形式处理对应逻辑