成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

H5與Native交互之JSBridge技術(shù)

zacklee / 1866人閱讀

摘要:一原理篇下面分別介紹和與的底層交互原理在講解原理之前,首先來了解下的組件,先來看一下蘋果官方的介紹上面的意思是說是一個可加載網(wǎng)頁的對象,它有瀏覽記錄功能,且對加載的網(wǎng)頁內(nèi)容是可編程的。

做過混合開發(fā)的很多人都知道Ionic和PhoneGap之類的框架,這些框架在web基礎(chǔ)上包了一層Native,然后通過Bridge技術(shù)使得js可以調(diào)用視頻、位置、音頻等功能。本文就是介紹這層Bridge的交互原理,通過閱讀本文你可以了解到j(luò)s與ios及android底層的通訊原理及JSBridge的封裝技術(shù)及調(diào)試方法。

一、原理篇

下面分別介紹IOS和Android與Javascript的底層交互原理

IOS

在講解原理之前,首先來了解下iOS的UIWebView組件,先來看一下蘋果官方的介紹:

You can use the UIWebView class to embed web content in your application. To do so, you simply create a UIWebView object, attach it to a window, and send it a request to load web content. You can also use this class to move back and forward in the history of webpages, and you can even set some web content properties programmatically.

上面的意思是說UIWebView是一個可加載網(wǎng)頁的對象,它有瀏覽記錄功能,且對加載的網(wǎng)頁內(nèi)容是可編程的。說白了UIWebView有類似瀏覽器的功能,我們使用可以它來打開頁面,并做一些定制化的功能,如可以讓js調(diào)某個方法可以取到手機的GPS信息。

但需要注意的是,Safari瀏覽器使用的瀏覽器控件和UIwebView組件并不是同一個,兩者在性能上有很大的差距。幸運的是,蘋果發(fā)布iOS8的時候,新增了一個WKWebView組件,如果你的APP只考慮支持iOS8及以上版本,那么你就可以使用這個新的瀏覽器控件了。

原生的UIWebView類提供了下面一些屬性和方法

屬性:

loading:是否處于加載中

canGoBack:A Boolean value indicating whether the receiver can move backward. (只讀)

canGoForward:A Boolean value indicating whether the receiver can move forward. (只讀)

request:The URL request identifying the location of the content to load. (read-only)

方法:

loadData:Sets the main page contents, MIME type, content encoding, and base URL.

loadRequest:加載網(wǎng)絡(luò)內(nèi)容

loadHTMLString:加載本地HTML文件

stopLoading:停止加載

goBack:后退

goForward:前進

reload:重新加載

stringByEvaluatingJavaScriptFromString:執(zhí)行一段js腳本,并且返回執(zhí)行結(jié)果

Native(Objective-C或Swift)調(diào)用Javascript方法

Native調(diào)用Javascript語言,是通過UIWebView組件的stringByEvaluatingJavaScriptFromString方法來實現(xiàn)的,該方法返回js腳本的執(zhí)行結(jié)果。

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

從上面代碼可以看出它其實就是調(diào)用了window下的一個對象,如果我們要讓native來調(diào)用我們js寫的方法,那這個方法就要在window下能訪問到。但從全局考慮,我們只要暴露一個對象如JSBridge對native調(diào)用就好了,所以在這里可以對native的代碼做一個簡單的封裝:

//下面為偽代碼
webview.setDataToJs(somedata);
webview.setDataToJs = function(data) {
 webview.stringByEvaluatingJavaScriptFromString("JSBridge.trigger(event, data)")
}
Javascript調(diào)用Native(Objective-C或Swift)方法

反過來,Javascript調(diào)用Native,并沒有現(xiàn)成的API可以直接拿來用,而是需要間接地通過一些方法來實現(xiàn)。UIWebView有個特性:在UIWebView內(nèi)發(fā)起的所有網(wǎng)絡(luò)請求,都可以通過delegate函數(shù)在Native層得到通知。這樣,我們就可以在UIWebView內(nèi)發(fā)起一個自定義的網(wǎng)絡(luò)請求,通常是這樣的格式:jsbridge://methodName?param1=value1¶m2=value2

于是在UIWebView的delegate函數(shù)中,我們只要發(fā)現(xiàn)是jsbridge://開頭的地址,就不進行內(nèi)容的加載,轉(zhuǎn)而執(zhí)行相應(yīng)的調(diào)用邏輯。

發(fā)起這樣一個網(wǎng)絡(luò)請求有兩種方式:1. 通過localtion.href;2. 通過iframe方式;
通過location.href有個問題,就是如果我們連續(xù)多次修改window.location.href的值,在Native層只能接收到最后一次請求,前面的請求都會被忽略掉。

使用iframe方式,以喚起Native APP的分享組件為例,簡單的封閉如下:

var url = "jsbridge://doAction?title=分享標(biāo)題&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);

然后Webview就可以攔截這個請求,并且解析出相應(yīng)的方法和參數(shù)。如下代碼所示:

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

在android中,native與js的通訊方式與ios類似,ios中的通過schema方式在android中也是支持的。

javascript調(diào)用native方式

目前在android中有三種調(diào)用native的方式:

1.通過schema方式,使用shouldOverrideUrlLoading方法對url協(xié)議進行解析。這種js的調(diào)用方式與ios的一樣,使用iframe來調(diào)用native代碼。
2.通過在webview頁面里直接注入原生js代碼方式,使用addJavascriptInterface方法來實現(xiàn)。
在android里實現(xiàn)如下:

class JSInterface {
    @JavascriptInterface //注意這個代碼一定要加上
    public String getUserData() {
        return "UserData";
    }
}
webView.addJavascriptInterface(new JSInterface(), "AndroidJS");

上面的代碼就是在頁面的window對象里注入了AndroidJS對象。在js里可以直接調(diào)用

alert(AndroidJS.getUserData()) //UserDate

3.使用prompt,console.log,alert方式,這三個方法對js里是屬性原生的,在android webview這一層是可以重寫這三個方法的。一般我們使用prompt,因為這個在js里使用的不多,用來和native通訊副作用比較少。

class YouzanWebChromeClient extends WebChromeClient {
    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        // 這里就可以對js的prompt進行處理,通過result返回結(jié)果
    }
    @Override
    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {

    }
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

    }

}
Native調(diào)用javascript方式

在android里是使用webview的loadUrl進行調(diào)用的,如:

// 調(diào)用js中的JSBridge.trigger方法
webView.loadUrl("javascript:JSBridge.trigger("webviewReady")");
二、庫的封裝 js調(diào)用native的封裝

上面我們了解了js與native通訊的底層原理,所以我們可以封裝一個基礎(chǔ)的通訊方法doCall來屏蔽android與ios的差異。

YouzanJsBridge = {
    doCall: function(functionName, data, callback) {
        var _this = this;
        // 解決連續(xù)調(diào)用問題
        if (this.lastCallTime && (Date.now() - this.lastCallTime) < 100) {
            setTimeout(function() {
                _this.doCall(functionName, data, callback);
            }, 100);
            return;
        }
        this.lastCallTime = Date.now();
    
        data = data || {};
        if (callback) {
            $.extend(data, { callback: callback });
        }
    
        if (UA.isIOS()) {
            $.each(data, function(key, value) {
                if ($.isPlainObject(value) || $.isArray(value)) {
                    data[key] = JSON.stringify(value);
                }
            });
            var url = Args.addParameter("youzanjs://" + functionName, data);
            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);
        } else if (UA.isAndroid()) {
            window.androidJS && window.androidJS[functionName] && window.androidJS[functionName](JSON.stringify(data));
        } else {
            console.error("未獲取platform信息,調(diào)取api失敗");
        }
    }
}

上面android端我們使用了addJavascriptInterface方法來注入一個AndroidJS對象。

項目通用方法抽象

在項目的實踐中,我們逐漸抽象出一些通用的方法,這些方法基本上都是可以滿足項目的需求。如下所示:

1.getData(datatype, callback, extra) H5從Native APP獲取數(shù)據(jù)

使用場景:H5需要從Native APP獲取某些數(shù)據(jù)的時候,可以調(diào)用這個方法。

參數(shù) 類型 是否必須 示例值 說明
datatype String userInfo 數(shù)據(jù)類型
callback Function 回調(diào)函數(shù)
extra Object 傳遞給Native APP的數(shù)據(jù)對象

示例代碼:

JSBridge.getData("userInfo",function(data) {
    console.log(data);
});
2.putData(datatype, data) H5告訴Native APP一些數(shù)據(jù)

使用場景:H5告訴Native APP一些數(shù)據(jù),可以調(diào)用這個方法。

參數(shù) 類型 是否必須 示例值 說明
datatype String userInfo 數(shù)據(jù)類型
data Object { username: "zhangsan", age: 20 } 傳遞給Native APP的數(shù)據(jù)對象

示例代碼:

JSBridge.putData("userInfo", {
    username: "zhangsan",
    age: 20
});
3.gotoWebview(url, page, data) Native APP新開一個Webview窗口,并打開相應(yīng)網(wǎng)頁
參數(shù) 類型 是否必須 示例值 說明
url String http://www.youzan.com 網(wǎng)頁鏈接地址,一般都只要傳遞URL參數(shù)就可以了
page String web 網(wǎng)頁page類型,默認(rèn)為web
data Object 額外參數(shù)對象

示例代碼:

// 示例1:打開一個網(wǎng)頁
JSBridge.gotoWebview("http://www.youzan.com");

// 示例2:打開一個網(wǎng)頁,并且傳遞額外的參數(shù)給Native APP
JSBridge.gotoWebview("http://www.youzan.com", "goodsDetail", {
    goods_id: 10000,
    title: "這是商品的標(biāo)題",
    desc: "這是商品的描述"
});
4.gotoNative(page, data) 從H5頁面跳轉(zhuǎn)到Native APP的某個原生界面
參數(shù) 類型 是否必須 示例值 說明
page String loginPage Native頁面標(biāo)示符,例如loginPage
data Object { username: "zhangsan", age: 20 } 額外參數(shù)對象

示例代碼:

// 示例1:打開Native APP登錄頁面
JSBridge.gotoNative("loginPage");

// 示例2:打開Native APP登錄頁面,并且傳遞用戶名給Native APP
JSBridge.gotoNative("loginPage", {
    username: "張三"
});
5.doAction(action, data) 功能上的一些操作
參數(shù) 類型 是否必須 示例值 說明
action String copy 操作功能類型,例如分享、復(fù)制
data Object { content: "這是要復(fù)制的內(nèi)容" } 額外參數(shù)

示例代碼:

// 示例1:調(diào)用Native APP復(fù)制一段文本到剪切板
JSBridge.doAction("copy", {
    content: "這是要復(fù)制的內(nèi)容"
});

// 示例2:調(diào)用Native APP的分享組件,分享當(dāng)前網(wǎng)頁到微信
JSBridge.doAction("share", {
    title: "分享標(biāo)題",
    desc: "分享描述",
    link: "http://www.youzan.com",
    imgs_url: "http://wap.koudaitong.com/v2/common/url/create?type=homepage&index%2Findex=&kdt_id=63077&alias=63077"
});
三、調(diào)試篇 使用Safari進行UIWebView的調(diào)試

(1)首先需要打開Safari的調(diào)試模式,在Safari的菜單中,選擇“Safari”→“Preference”→“Advanced”,勾選上“Show Develop menu in menu bar”選項,如下圖所示。

(2)打開真機或iPhone模擬器的調(diào)試模式,在真機或iPhone模擬器中打開設(shè)置界面,選擇“Safari”→“高級”→“Web檢查器”,選擇開啟即可,如下圖所示。

(3)將真機通過USB連上電腦,或者開啟模擬器,Safari的“Develop”菜單下便會多出相應(yīng)的菜單項,如圖所示。

(4)Safari連接上UIWebView之后,我們就可以直接在Safari中直接修改HTML、CSS,以及調(diào)試Javascript。

四、參考鏈接

UIWebView Class Reference

WKWebView Class Reference

https://github.com/marcuswestin/WebViewJavascriptBridge

本文由 @kk @勁風(fēng) 共同創(chuàng)作,首發(fā)于有贊技術(shù)博客: http://tech.youzan.com/jsbridge/

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/84341.html

相關(guān)文章

  • 原生Appjavascript交互JSBridge接口原理、設(shè)計實現(xiàn)

    摘要:相關(guān)參考中與之間相互調(diào)用的實現(xiàn)實現(xiàn)了與相同的機制的對象注入漏洞解決方案存在的意義 前期調(diào)研 調(diào)研對象:支付寶,微信,云之家 調(diào)研文檔:Android中JS與Java的極簡交互庫 SimpleJavaJsBridge 設(shè)計需求 閱讀類型的業(yè)務(wù)功能頁面需要由前端H5實現(xiàn),需要做到服務(wù)端可控; 頁面界面更改減少重新發(fā)布新版本的頻率; 功能頁面部分原型需求無法實現(xiàn),需要原生功能支持; 對未來...

    Lyux 評論0 收藏0
  • 跨平臺技術(shù)演進

    摘要:接下來,我將從原理優(yōu)缺點等方面為大家分享跨平臺技術(shù)演進。小程序年是微信小程序飛速發(fā)展的一年,年,各大廠商快速跟進,已經(jīng)有了很大的影響力。下面,我們以微信小程序為例,分析小程序的技術(shù)架構(gòu)。 前言 大家好,我是simbawu ,@BooheeFE Team Leader,關(guān)于這篇文章,有問題歡迎來這里討論。 隨著移動互聯(lián)網(wǎng)的普及和快速發(fā)展,手機成了互聯(lián)網(wǎng)行業(yè)最大的流量分發(fā)入口。以及隨著5G...

    魏憲會 評論0 收藏0
  • 跨平臺技術(shù)演進

    摘要:接下來,我將從原理優(yōu)缺點等方面為大家分享跨平臺技術(shù)演進。小程序年是微信小程序飛速發(fā)展的一年,年,各大廠商快速跟進,已經(jīng)有了很大的影響力。下面,我們以微信小程序為例,分析小程序的技術(shù)架構(gòu)。 前言 大家好,我是simbawu ,@BooheeFE Team Leader,關(guān)于這篇文章,有問題歡迎來這里討論。 隨著移動互聯(lián)網(wǎng)的普及和快速發(fā)展,手機成了互聯(lián)網(wǎng)行業(yè)最大的流量分發(fā)入口。以及隨著5G...

    MasonEast 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<