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

資訊專欄INFORMATION COLUMN

(轉(zhuǎn))iOS- JSBridge的原理

txgcwm / 2024人閱讀

摘要:作者心葉時(shí)間原理概述簡(jiǎn)介是代碼與代碼的通信橋梁。目前的一種統(tǒng)一方案是觸發(fā)捕獲原生分析執(zhí)行原生調(diào)用。另外調(diào)用時(shí)處理完畢后一定要及時(shí)通知進(jìn)行回調(diào)要不然這個(gè)回調(diào)函數(shù)不會(huì)自動(dòng)銷(xiāo)毀多了后會(huì)引發(fā)內(nèi)存泄漏。

作者:心葉
時(shí)間:2019-03-25 10:18

原理概述 簡(jiǎn)介

JSBridge是Native代碼與JS代碼的通信橋梁。目前的一種統(tǒng)一方案是:H5觸發(fā)url scheme->Native捕獲url scheme->原生分析,執(zhí)行->原生調(diào)用h5。如下圖:

url scheme介紹

上圖中有提到url scheme這個(gè)概念,那這到底是什么呢?

url scheme是一種類似于url的鏈接,是為了方便app直接互相調(diào)用設(shè)計(jì)的

具體為,可以用系統(tǒng)的OpenURI打開(kāi)一個(gè)類似于url的鏈接(可拼入?yún)?shù)),然后系統(tǒng)會(huì)進(jìn)行判斷,如果是系統(tǒng)的url scheme,則打開(kāi)系統(tǒng)應(yīng)用,否則找看是否有app注冊(cè)這種scheme,打開(kāi)對(duì)應(yīng)app

需要注意的是,這種scheme必須原生app注冊(cè)后才會(huì)生效,如微信的scheme為(weixin://)

而本文JSBridge中的url scheme則是仿照上述的形式的一種方式

具體為,app不會(huì)注冊(cè)對(duì)應(yīng)的scheme,而是由前端頁(yè)面通過(guò)某種方式觸發(fā)scheme(如用iframe.src),然后Native用某種方法捕獲對(duì)應(yīng)的url觸發(fā)事件,然后拿到當(dāng)前的觸發(fā)url,根據(jù)定義好的協(xié)議,分析當(dāng)前觸發(fā)了那種方法,然后根據(jù)定義來(lái)執(zhí)行等

注意,iOS10以后,urlscheme必須符合url規(guī)范,否則會(huì)報(bào)錯(cuò)

實(shí)現(xiàn)流程

基于上述的基本原理,現(xiàn)在開(kāi)始設(shè)計(jì)一種JSBridge的實(shí)現(xiàn)

實(shí)現(xiàn)思路

要實(shí)現(xiàn)JSBridge,我們可以進(jìn)行關(guān)鍵步驟分析

第一步:設(shè)計(jì)出一個(gè)Native與JS交互的全局橋?qū)ο?/p>

第二步:JS如何調(diào)用Native

第三步:Native如何得知api被調(diào)用

第四步:分析url-參數(shù)和回調(diào)的格式

第五步:Native如何調(diào)用JS

第六步:H5中api方法的注冊(cè)以及格式

如下圖:

第一步:設(shè)計(jì)出一個(gè)Native與JS交互的全局橋?qū)ο?/b>

我們規(guī)定,JS和Native之間的通信必須通過(guò)一個(gè)H5全局對(duì)象JSbridge來(lái)實(shí)現(xiàn),該對(duì)象有如下特點(diǎn)

該對(duì)象名為"JSBridge",是H5頁(yè)面中全局對(duì)象window的一個(gè)屬性

var JSBridge = window.JSBridge || (window.JSBridge = {});

該對(duì)象有如下方法

- registerHandler(String,Function) H5調(diào)用,注冊(cè)本地JS方法,注冊(cè)后Native可通過(guò)JSBridge調(diào)用。調(diào)用后會(huì)將方法注冊(cè)到本地變量messageHandlers 中

- callHandler(String,JSON,Function) H5調(diào)用,調(diào)用原生開(kāi)放的api,調(diào)用后實(shí)際上還是本地通過(guò)url scheme觸發(fā)。調(diào)用時(shí)會(huì)將回調(diào)id存放到本地變量responseCallbacks中

- _handleMessageFromNative(JSON) Native調(diào)用,原生調(diào)用H5頁(yè)面注冊(cè)的方法,或者通知H5頁(yè)面執(zhí)行回調(diào)方法

如圖

第二步:JS如何調(diào)用Native

在第一步中,我們定義好了全局橋?qū)ο?可以我們是通過(guò)它的callHandler方法來(lái)調(diào)用原生的,那么它內(nèi)部經(jīng)歷了一個(gè)怎么樣的過(guò)程呢?如下:

callHandler函數(shù)內(nèi)部實(shí)現(xiàn)過(guò)程

在執(zhí)行callHandler時(shí),內(nèi)部經(jīng)歷了以下步驟:

(1)判斷是否有回調(diào)函數(shù),如果有,生成一個(gè)回調(diào)函數(shù)id,并將id和對(duì)應(yīng)回調(diào)添加進(jìn)入回調(diào)函數(shù)集合responseCallbacks中

(2)通過(guò)特定的參數(shù)轉(zhuǎn)換方法,將傳入的數(shù)據(jù),方法名一起,拼接成一個(gè)url scheme

//url scheme的格式如
//基本有用信息就是后面的callbackId,handlerName與data
//原生捕獲到這個(gè)scheme后會(huì)進(jìn)行分析
var uri = CUSTOM_PROTOCOL_SCHEME://API_Name:callbackId/handlerName?data

(3)使用內(nèi)部早就創(chuàng)建好的一個(gè)隱藏iframe來(lái)觸發(fā)scheme

//創(chuàng)建隱藏iframe過(guò)程
var messagingIframe = document.createElement("iframe");
messagingIframe.style.display = "none";
document.documentElement.appendChild(messagingIframe);

//觸發(fā)scheme
messagingIframe.src = uri;

注意點(diǎn)

注意,正常來(lái)說(shuō)是可以通過(guò)window.location.href達(dá)到發(fā)起網(wǎng)絡(luò)請(qǐng)求的效果的,但是有一個(gè)很?chē)?yán)重的問(wèn)題,就是如果我們連續(xù)多次修改window.location.href的值,在Native層只能接收到最后一次請(qǐng)求,前面的請(qǐng)求都會(huì)被忽略掉。所以JS端發(fā)起網(wǎng)絡(luò)請(qǐng)求的時(shí)候,需要使用iframe,這樣就可以避免這個(gè)問(wèn)題。
第三步:Native如何得知api被調(diào)用

在上一步中,我們已經(jīng)成功在H5頁(yè)面中觸發(fā)scheme,那么Native如何捕獲scheme被觸發(fā)呢?

根據(jù)系統(tǒng)不同,Android和iOS分別有自己的處理方式

Android捕獲url scheme

在Android中(WebViewClient里),通過(guò)shouldoverrideurlloading可以捕獲到url scheme的觸發(fā)

public boolean shouldOverrideUrlLoading(WebView view, String url){
    //讀取到url后自行進(jìn)行分析處理

    //如果返回false,則WebView處理鏈接url,如果返回true,代表WebView根據(jù)程序來(lái)執(zhí)行url
    return true;
}

另外,Android中也可以不通過(guò)iframe.src來(lái)觸發(fā)scheme,android中可以通過(guò)window.prompt(uri, "");來(lái)觸發(fā)scheme,然后Native中通過(guò)重寫(xiě)WebViewClient的onJsPrompt來(lái)獲取uri

iOS捕獲url scheme

iOS中,UIWebView有個(gè)特性:在UIWebView內(nèi)發(fā)起的所有網(wǎng)絡(luò)請(qǐng)求,都可以通過(guò)delegate函數(shù)在Native層得到通知。這樣,我們可以在webview中捕獲url scheme的觸發(fā)(原理是利用 shouldStartLoadWithRequest)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];

    NSString *requestString = [[request URL] absoluteString];
    //獲取利潤(rùn)url scheme后自行進(jìn)行處理
   return YES;
}

之后Native捕獲到了JS調(diào)用的url scheme,接下來(lái)就該到下一步分析url了

第四步:分析url-參數(shù)和回調(diào)的格式

在前面的步驟中,Native已經(jīng)接收到了JS調(diào)用的方法,那么接下來(lái),原生就應(yīng)該按照定義好的數(shù)據(jù)格式來(lái)解析數(shù)據(jù)了

url scheme的格式,前面已經(jīng)提到。Native接收到Url后,可以按照這種格式將回調(diào)參數(shù)id、api名、參數(shù)提取出來(lái),然后按如下步驟進(jìn)行

(1)根據(jù)api名,在本地找尋對(duì)應(yīng)的api方法,并且記錄該方法執(zhí)行完后的回調(diào)函數(shù)id

(2)根據(jù)提取出來(lái)的參數(shù),根據(jù)定義好的參數(shù)進(jìn)行轉(zhuǎn)化

如果是JSON格式需要手動(dòng)轉(zhuǎn)換,如果是String格式直接可以使用

(3)原生本地執(zhí)行對(duì)應(yīng)的api功能方法

(4)功能執(zhí)行完畢后,找到這次api調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)id,然后連同需要傳遞的參數(shù)信息,組裝成一個(gè)JSON格式的參數(shù)

回調(diào)的JSON格式為:{responseId:回調(diào)id,responseData:回調(diào)數(shù)據(jù)}

responseId String型 H5頁(yè)面中對(duì)應(yīng)需要執(zhí)行的回調(diào)函數(shù)的id,在H5中生成url scheme時(shí)就已經(jīng)產(chǎn)生

responseData JSON型 Native需要傳遞給H5的回調(diào)數(shù)據(jù),是一個(gè)JSON格式: {code:(整型,調(diào)用是否成功,1成功,0失敗),result:具體需要傳遞的結(jié)果信息,可以為任意類型,msg:一些其它信息,如調(diào)用錯(cuò)誤時(shí)的錯(cuò)誤信息}

(5)通過(guò)JSBridge通知H5頁(yè)面回調(diào)

參考 第五步Native如何調(diào)用JS

第五步:Native如何調(diào)用JS

到了這一步,就該Native通過(guò)JSBridge調(diào)用H5的JS方法或者通知H5進(jìn)行回調(diào)了,具體如下

//將回調(diào)信息傳給H5
JSBridge._handleMessageFromNative(messageJSON);

如上,實(shí)際上是通過(guò)JSBridge的_handleMessageFromNative傳遞數(shù)據(jù)給H5,其中的messageJSON數(shù)據(jù)格式根據(jù)兩種不同的類型,有所區(qū)別,如下

Native通知H5頁(yè)面進(jìn)行回調(diào)

數(shù)據(jù)格式為:上文中的回調(diào)的JSON格式

Native主動(dòng)調(diào)用H5方法

Native主動(dòng)調(diào)用H5方法時(shí),數(shù)據(jù)格式是:{handlerName:api名,data:數(shù)據(jù),callbackId:回調(diào)id}

handlerName String型 需要調(diào)用的,h5中開(kāi)放的api的名稱

data JSON型 需要傳遞的數(shù)據(jù),固定為JSON格式(因?yàn)槲覀児潭℉5中注冊(cè)的方法接收的第一個(gè)參數(shù)必須是JSON,第二個(gè)是回調(diào)函數(shù))

注意,這一步中,如果Native調(diào)用的api是h5沒(méi)有注冊(cè)的,h5頁(yè)面上會(huì)有對(duì)應(yīng)的錯(cuò)誤提示。

另外,H5調(diào)用Native時(shí),Native處理完畢后一定要及時(shí)通知H5進(jìn)行回調(diào),要不然這個(gè)回調(diào)函數(shù)不會(huì)自動(dòng)銷(xiāo)毀,多了后會(huì)引發(fā)內(nèi)存泄漏。

第六步:H5中api方法的注冊(cè)以及格式

前面有提到Native主動(dòng)調(diào)用H5中注冊(cè)的api方法,那么h5中怎么注冊(cè)供原生調(diào)用的api方法呢?格式又是什么呢?如下

H5中注冊(cè)供原生調(diào)用的API

//注冊(cè)一個(gè)測(cè)試函數(shù)
JSBridge.registerHandler("testH5Func",function(data,callback){
    alert("測(cè)試函數(shù)接收到數(shù)據(jù):"+JSON.stringify(data));
    callback&&callback("測(cè)試回傳數(shù)據(jù)...");
});

如上述代碼為注冊(cè)一個(gè)供原生調(diào)用的api

H5中注冊(cè)的API格式注意

如上代碼,注冊(cè)的api參數(shù)是(data,callback)

其中第一個(gè)data即原生傳過(guò)來(lái)的數(shù)據(jù),第二個(gè)callback是內(nèi)部封裝過(guò)一次的,執(zhí)行callback后會(huì)觸發(fā)url scheme,通知原生獲取回調(diào)信息

思路

大致思路就是

h5調(diào)用Native的關(guān)鍵步驟進(jìn)行拆分,由以前的直接傳遞url scheme變?yōu)閭鬟f一個(gè)統(tǒng)一的url scheme,然后Native主動(dòng)獲取傳遞的參數(shù)

完善以前: H5調(diào)用Native->將所有參數(shù)組裝成為url scheme->原生捕獲scheme,進(jìn)行分析

完善以后: H5調(diào)用Native->將所有參數(shù)存入本地?cái)?shù)組->觸發(fā)一個(gè)固定的url scheme->原生捕獲scheme->原生通過(guò)JSBridge主動(dòng)獲取參數(shù)->進(jìn)行分析

實(shí)現(xiàn)

這種完善后的流程和以前有所區(qū)別,如下

JSBridge對(duì)象圖解

JSBridge實(shí)現(xiàn)完整流程

注意
由于這次完善的核心是:Native主動(dòng)調(diào)用JS函數(shù),并獲取返回值。而在Android4.4以前,Android是沒(méi)有這個(gè)功能的,所以并不完全適用于Android

所以一般會(huì)進(jìn)行一個(gè)兼容處理,Android中采用以前的scheme傳法,iOS使用完善后的方案(也便于4.4普及后后續(xù)的完善)

完整的JSBridge

上述分析了JSBridge的實(shí)現(xiàn)流程,那么實(shí)際項(xiàng)目中,我們就應(yīng)該結(jié)合上述兩種,針對(duì)Android和iOS的不同情況,統(tǒng)一出一種完整的方案,如下

完整調(diào)用流程圖

例子
基于上面的思想,個(gè)人在github上維護(hù)了一個(gè)用于學(xué)習(xí)的項(xiàng)目(非轉(zhuǎn)載內(nèi)容):https://github.com/yelloxing/...
不采用url scheme方式

前面提到的JSBridge都是基于url scheme的,但其實(shí)如果不考慮Android4.2以下,iOS7以下,其實(shí)也可以用另一套方案的,如下:

Native調(diào)用JS的方法不變

JS調(diào)用Native是不再通過(guò)觸發(fā)url scheme,而是采用自帶的交互,比如

Android中,原生通過(guò) addJavascriptInterface開(kāi)放一個(gè)統(tǒng)一的api給JS調(diào)用,然后將觸發(fā)url scheme步驟變?yōu)檎{(diào)用這個(gè)api,其余步驟不變(相當(dāng)于以前是url接收參數(shù),現(xiàn)在變?yōu)閍pi函數(shù)接收參數(shù))

iOS中,原生通過(guò)JavaScriptCore里面的方法來(lái)注冊(cè)一個(gè)統(tǒng)一api,其余和Android中一樣(這里就不需要主動(dòng)獲取參數(shù)了,因?yàn)閰?shù)可以直接由這個(gè)函數(shù)統(tǒng)一接收)

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

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

相關(guān)文章

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

    摘要:一原理篇下面分別介紹和與的底層交互原理在講解原理之前,首先來(lái)了解下的組件,先來(lái)看一下蘋(píng)果官方的介紹上面的意思是說(shuō)是一個(gè)可加載網(wǎng)頁(yè)的對(duì)象,它有瀏覽記錄功能,且對(duì)加載的網(wǎng)頁(yè)內(nèi)容是可編程的。 做過(guò)混合開(kāi)發(fā)的很多人都知道Ionic和PhoneGap之類的框架,這些框架在web基礎(chǔ)上包了一層Native,然后通過(guò)Bridge技術(shù)使得js可以調(diào)用視頻、位置、音頻等功能。本文就是介紹這層Bridge...

    zacklee 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

txgcwm

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<