Hybrid APP基礎篇(三)->Hybrid APP之Native和H5頁面交互原理

本文已經不維護,新地址:

http://www.cnblogs.com/dailc/p/8097598.htmljavascript

說明

Hybrid模式原生和H5交互原理html

目錄

前言

參考來源

前人栽樹,後臺乘涼,本文參考瞭如下來源java

前置技術要求

閱讀本文前,建議先閱讀如下文章web

楔子

Hybrid APP的關鍵是原生頁面與H5頁面直接的交互,本文作簡單介紹api

Android、iOS原生和H5的基本通訊機制

在Hybrid APP中,原生與H5的交互方式在Android和iOS上的實現是有異同的,緣由是Android、iOS的通訊機制有所區別,下面介紹原生和H5相互調用的方法安全

Android端

Native調JS

4.4版本以前架構

// mWebView = new WebView(this); //即當前webview對象			
mWebView.loadUrl("javascript: 方法名('參數,須要轉爲字符串')"); 

//ui線程中運行
 runOnUiThread(new Runnable() {  
        @Override  
        public void run() {  
            mWebView.loadUrl("javascript: 方法名('參數,須要轉爲字符串')");  
            Toast.makeText(Activity名.this, "調用方法...", Toast.LENGTH_SHORT).show();  
        }  
});  
			

4.4之後(包括4.4)app

//異步執行JS代碼,並獲取返回值	
mWebView.evaluateJavascript("javascript: 方法名('參數,須要轉爲字符串')", new ValueCallback() {
        @Override
        public void onReceiveValue(String value) {
    		//這裏的value即爲對應JS方法的返回值
        }
});
			

如上所示,Native用H5頁面中的JS方法,有以下特色異步

  • 4.4以前Native經過loadUrl來調用JS方法,只能讓某個JS方法執行,可是沒法獲取該方法的返回值
  • 4.4以後,經過evaluateJavascript異步調用JS方法,而且能在onReceiveValue中拿到返回值
  • 不適合傳輸大量數據(大量數據建議用接口方式獲取)
  • mWebView.loadUrl("javascript: 方法名('參數,須要轉爲字符串')");函數需在UI線程運行,由於mWebView爲UI控件(可是有一個壞處是會阻塞UI線程)

JS調Native

 WebSettings webSettings = mWebView.getSettings();  
 //Android容器容許JS腳本,必需要
webSettings.setJavaScriptEnabled(true);
//Android容器設置僑連對象
mWebView.addJavascriptInterface(getJSBridge(), "JSBridge");
			

Android中JSBridge的代碼ide

//Android4.2版本以上,本地方法要加上註解@JavascriptInterface,不然會找不到方法。
private Object getJSBridge(){  
    Object insertObj = new Object(){  
    	@JavascriptInterface
        public String foo(){  
            return "foo";  
        }  
        
        @JavascriptInterface
        public String foo2(final String param){  
            return "foo2:" + param;  
        }  
          
    };  
    return insertObj;  
}  
			

Html中JS調用原生的代碼

//調用方法一
window.JSBridge.foo(); //返回:'foo'
//調用方法二
window.JSBridge.foo2('test');//返回:'foo2:test'
			

如上所示,Native中經過addJavascriptInterface添加暴露出來的JS橋對象,而後再該對象內部聲明對應的API方法,有以下特色:

  • 在Android4.2以上(api17後),暴露的api要加上註解@JavascriptInterface,不然會找不到方法。
  • 在api17之前,addJavascriptInterface有風險,hacker能夠經過反編譯獲取Native註冊的Js對象,而後在頁面經過反射Java的內置 靜態類,獲取一些敏感的信息和破壞

    因此,也就是爲何Android中也會使用JSBridge來進行交互,而不是addJavascriptInterface直接暴露api

  • JS能調用到已經暴露的api,而且能獲得相應返回值

iOS端

Native調JS

//能夠取得JS函數執行的返回值
//方法必須是Html頁面綁定在最頂層的window上對象的
//如window.top.foo
//Swift
webview.stringByEvaluatingJavaScriptFromString("方法名(參數)")
//OC
[webView stringByEvaluatingJavaScriptFromString:@"方法名(參數);"];
			

如上所示,Native經過stringByEvaluatingJavaScriptFromString調用Html綁定在window上的函數,有以下特色

  • Native調用JS方法時,能拿到JS方法的返回值
  • 不適合傳輸大量數據(大量數據建議用接口方式獲取)

JS調Native

引入官方的庫文件

#import <JavaScriptCore/JavaScriptCore.h>

Native註冊api函數(OC)

//webview加載完畢後設置一些js接口
-(void)webViewDidFinishLoad:(UIWebView *)webView{
    [self hideProgress];
    [self setJSInterface];
}

-(void)setJSInterface{
    
    JSContext *context =[_wv valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    // 註冊名爲foo的api方法
    context[@"foo"] = ^() {
    	
    	//獲取參數
        NSArray *args = [JSContext currentArguments];
        NSString *title = [NSString stringWithFormat:@"%@",[args objectAtIndex:0]];
        //作一些本身的邏輯
        //返回一個值  'foo:'+title
        return [NSString stringWithFormat:@"foo:%@", title];
    };
    

    
}				
			

Html中JS調用原生的代碼

//調用方法,用top是確保調用到最頂級,由於iframe要用top才能拿到頂級
window.top.foo('test'); //返回:'foo:test'
			

如上所示,Native中經過引入官方提供的JavaScriptCore庫(iOS7中出現的),而後能夠將api綁定到JSContext上(而後Html中JS默認經過window.top.***可調用)。有以下特色

  • iOS7纔出現這種方式,在這以前,js沒法直接調用Native,只能經過JSBridge方式簡介調用
  • JS能調用到已經暴露的api,而且能獲得相應返回值
  • iOS原生自己是沒法被JS調用的,可是經過引入官方提供的第三方"JavaScriptCore",便可開放api給JS調用

原生和H5的另外一種通信方式:JSBridge

實際上,Native與H5通訊,除了前面提到的用基本方法外,還有一種廣爲流行的方法:JSBridge

什麼是JSBridge

JSBridge是廣爲流行的Hybrid開發中JS和Native一種通訊方式,各大公司的應用中都有用到這種方法

簡單的說,JSBridge就是定義Native和JS的通訊,Native只經過一個固定的橋對象調用JS,JS也只經過固定的橋對象調用Native,基本原理是:

H5->經過某種方式觸發一個url->Native捕獲到url,進行分析->原生作處理->Native調用H5的JSBridge對象傳遞迴調。以下圖

上圖簡單的介紹了下JSBridge的核心原理,具體詳細實現請參考後面詳解。

爲何要用JSBridge

在上文中咱們有提到Native和原生之間的基本通訊,既然Native和原生已經可以實現通訊了,那爲何還要這種經過url scheme的JSBridge方式呢,緣由大體以下

  • Android4.2如下,addJavascriptInterface方式有安全漏掉
  • iOS7如下,JS沒法調用Native
  • url scheme交互方式是一套現有的成熟方案,能夠完美兼容各類版本,不存在上述問題

另外,請注意,能夠理解爲JSBridge是一種交互理念,而上述的url scheme則是其中的一種實現,因此也就是說,就算後面實現變爲了addJavascriptInterface,JavaScriptCore,也同樣是JSBridge交互

JSBridge交互的一個很大特色就是便於拓展,並且沒有重大的安全性問題,因此也就是爲何它廣爲流行

JSBridge原理以及實現

JSBridge的原理和實現請參考 JSBridge實現原理