1. 程式人生 > >Hybrid APP 混合開發模式的選擇之路(五:原生和H5的互動原理)

Hybrid APP 混合開發模式的選擇之路(五:原生和H5的互動原理)

原文出處:http://www.cnblogs.com/dailc/p/5931322.html

在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)

//非同步執行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的程式碼

//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互動的一個很大特點就是便於拓展,而且沒有重大的安全性問題,所以也就是為什麼它廣為流行