Android#JSBridge踩坑問(wèn)題記錄

最新公司新啟動(dòng)了一個(gè)項(xiàng)目仰泻,大致架構(gòu)就是,原生客戶端相當(dāng)于一個(gè)殼篮愉,通過(guò)WebView嵌套著含有主要內(nèi)容的H5般眉,客戶端對(duì)數(shù)據(jù)進(jìn)行管理,如數(shù)據(jù)緩存或數(shù)據(jù)接口請(qǐng)求潜支,然后將數(shù)據(jù)處理好傳給前端,而前端要做的就是將數(shù)據(jù)以各種方式顯示出來(lái)柿汛,有點(diǎn)MVP中V層和M層的意思冗酿。

由于整個(gè)項(xiàng)目涉及到大量和H5的交互邏輯埠对,所以很自然的,我們使用上了JSBridge裁替。很不幸项玛,在用的過(guò)程中我們發(fā)現(xiàn)了不少問(wèn)題,也踩了很多坑弱判。所以在這里總結(jié)一下襟沮,希望可以幫助到遇到這些問(wèn)題的人。

1昌腰、異步問(wèn)題

在native和前端在互相調(diào)用事件的過(guò)程中需保證雙方的注冊(cè)時(shí)機(jī)以及生命周期开伏,即調(diào)用方在調(diào)用的時(shí)候需保證注冊(cè)方已經(jīng)注冊(cè)好。道理很簡(jiǎn)單遭商,沒(méi)有注冊(cè)好固灵,何談?wù){(diào)用。所以在某些異步事件情況下劫流,應(yīng)該保證數(shù)據(jù)管理方是調(diào)用者巫玻,接收數(shù)據(jù)端是注冊(cè)方。因?yàn)楫惒綌?shù)據(jù)何時(shí)下載/請(qǐng)求好祠汇,只有數(shù)據(jù)管理方知道仍秤,也就能確定合適的調(diào)用時(shí)機(jī),而注冊(cè)方要做的是—盡量早的注冊(cè)在可很,在我們這次項(xiàng)目里诗力,native app就是調(diào)用方,而前端是注冊(cè)方根穷。

例如姜骡,在webview初始化的時(shí)候,客戶端調(diào)用前端的方法時(shí)應(yīng)保證前端的事件已經(jīng)全部注冊(cè)好的情況下屿良,即webview加載完成的時(shí)候圈澈。

//webview加載完畢
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
   //傳遞數(shù)據(jù)給前端
  webView.callHandler("setData", json, new CallBackFunction() {
      @Override
      public void onCallBack(String data) {
      }
  });
}
2、嚴(yán)格模式下的數(shù)據(jù)問(wèn)題

前端在嚴(yán)格模式下調(diào)用natvie方法并傳過(guò)來(lái)的數(shù)據(jù)json串可能會(huì)在每個(gè)字段和數(shù)據(jù)帶上 " " ",或“ / ”尘惧,這樣我們?cè)诮馕龀蓪?shí)體bean對(duì)象的時(shí)候會(huì)報(bào)解析錯(cuò)誤而閃退康栈。

所以穩(wěn)妥起見(jiàn),native在使用前端傳過(guò)來(lái)的數(shù)據(jù)的第一步要做的就是過(guò)濾(需根據(jù)數(shù)據(jù)本身定好過(guò)濾規(guī)則):

webView.registerHandler("getData", new BridgeHandler() {
   @Override
    public void handler(String data, CallBackFunction function) {
         data.replace("\"", "").replace("\\", "");
    }
 });
3喷橙、子線程無(wú)法調(diào)用問(wèn)題

native調(diào)前端的方法(callHandler)在子線程調(diào)不到啥么,換句話說(shuō)就是,本地調(diào)前端的方法時(shí)需保證在主線程贰逾。

即 runOnMainThread() 或使用RxJava的
.observeOn(AndroidSchedulers.mainThread())
來(lái)調(diào)度線程悬荣。

4、無(wú)法收到回調(diào)

native調(diào)前端的方法疙剑,前端會(huì)回傳給native一個(gè)回調(diào)告訴native是否有調(diào)到這個(gè)方法氯迂,即onCallBack方法践叠。但如果想要在這個(gè)方法的內(nèi)部進(jìn)行一些邏輯處理,它可能會(huì)讓你失望嚼蚀,因?yàn)檫@個(gè)回調(diào)有些不穩(wěn)定禁灼,所以有時(shí)我們根本不知道前端到底有沒(méi)有調(diào)到我們的方法,總之轿曙,不是萬(wàn)不得已就不要在原生回調(diào)里寫上邏輯處理弄捕。如果一定需要:

解決辦法是本地再注冊(cè)一個(gè)方法,當(dāng)native調(diào)到前端的方法的時(shí)候导帝,和前端協(xié)商好讓前端立馬再調(diào)一下native的一個(gè)方法守谓,native的方法被調(diào)到即說(shuō)明 natvie已經(jīng)成功調(diào)到前端的方法,而不要使用方法本身的回調(diào)舟扎。

webView.callHandler("test", "", new CallBackFunction() {
   @Override
   public void onCallBack(String data) {
      LogUtil.i("test");
   }

});
webView.registerHandler("testBack", new BridgeHandler() {
   @Override
   public void handler(String data, CallBackFunction function) {
     LogUtil.i("testBack");
  }
});

和前端協(xié)商好分飞,當(dāng)我們調(diào)用“test”方法的時(shí)候,讓前端調(diào)用我們注冊(cè)的“testBack”睹限,當(dāng)testBack被調(diào)用的時(shí)候譬猫,我們就認(rèn)為test方法有被前端調(diào)用,這樣就可以規(guī)避onCallBack的不穩(wěn)定的問(wèn)題羡疗。

5染服、不要通過(guò)Gradle遠(yuǎn)程依賴,盡量使用module本地依賴

最重要的一條叨恨,不要通過(guò)gradle遠(yuǎn)程依賴JsBridge柳刮,不要通過(guò)gradle遠(yuǎn)程依賴JsBridge,不要通過(guò)gradle遠(yuǎn)程依賴JsBridge痒钝,重要的事情說(shuō)三遍

implementation'com.github.lzyzsd:jsbridge:1.0.4'

這會(huì)導(dǎo)致callHandler的方法在某些場(chǎng)景下的調(diào)用不穩(wěn)定秉颗,即有時(shí)候可以調(diào)到有時(shí)候調(diào)不到。

webView.callHandler("test", "", new CallBackFunction() {
  @Override
  public void onCallBack(String data) {

  }

});

解決辦法有兩點(diǎn):
解決方案一: 將庫(kù)下載到本地直接以module的形式依賴送矩。

沒(méi)了蚕甥。。栋荸。
這樣解決了call前端方法不穩(wěn)定的問(wèn)題菇怀,甚至解決了onCallBack回調(diào)不穩(wěn)定的問(wèn)題。
答案應(yīng)該是如issue上所說(shuō)晌块。
坦白說(shuō)爱沟,翻了眾多issue,看到這條issue的時(shí)候我的內(nèi)心是崩潰的匆背,一直以為是native和前端的聯(lián)調(diào)出了問(wèn)題呼伸。

image

雖然這樣貌似可以解決問(wèn)題但是我們還有方案二

解決方案二: callHandler()方法在某些場(chǎng)景下的低概率不穩(wěn)定問(wèn)題影響太不好了,以至于我們?cè)谟梅桨敢唤鉀Q問(wèn)題后還是不放心钝尸,于是就加上了另外一套容錯(cuò)機(jī)制:

Observable observable = Observable.interval(0, 1, TimeUnit.SECONDS);
//”test“方法有失敗的概率 寫個(gè)2秒循環(huán)的定時(shí)器重試括享,成功調(diào)用后退出并釋放定時(shí)器(經(jīng)過(guò)測(cè)試在不穩(wěn)定的時(shí)候連續(xù)調(diào)用2-3次就能重試成功)闽铐。
mObserver =new DisposableObserver() {
  @Override
  public void onNext(@NonNull Long aLong) {
    webView.callHandler("test", json, new CallBackFunction() {
      @Override
      public void onCallBack(String data) {
           //使用本地module依賴的方式貌似是解決了onCallBack不穩(wěn)定的問(wèn)題。
           //走到這里說(shuō)明調(diào)用到了奶浦,結(jié)束循環(huán)。
            dispose();
          }
      });
    }
};observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mObserver);

以上的邏輯就是:如果第一次調(diào)用callHandler踢星,如果1秒鐘之后還沒(méi)有收到回調(diào)我們會(huì)再次進(jìn)行重試澳叉,知道成功為止。觀察情況是沐悦,如果有出現(xiàn)異常成洗,大概在重復(fù)調(diào)用第2-3次的時(shí)候可以成功,成功之后跳出并釋放計(jì)時(shí)器藏否。不過(guò)經(jīng)過(guò)大量的測(cè)試瓶殃,我們發(fā)現(xiàn),在使用了方案一的情況下副签,幾乎已經(jīng)沒(méi)有會(huì)使用到方案二的情況遥椿,不過(guò)為了容錯(cuò),我們依然保留淆储。

結(jié)語(yǔ):
以上就是使用JSBridge踩過(guò)的坑冠场,可以說(shuō)不穩(wěn)定的這種偶現(xiàn)問(wèn)題實(shí)在是太頭疼了,如果以后還有在使用JSBridge開(kāi)發(fā)一些復(fù)雜場(chǎng)景的話本砰,希望大家能基于這幾條原則(問(wèn)題)碴裙,除了以上說(shuō)的,個(gè)人還有一些反思:
一点额、遇到一些開(kāi)源庫(kù)的問(wèn)題舔株,多去翻翻issue上前人提過(guò)的問(wèn)題,說(shuō)不定會(huì)有意外收獲还棱,issue也沒(méi)有的話再去看看源碼實(shí)現(xiàn)载慈。
二、遇到問(wèn)題诱贿,適當(dāng)?shù)某鋈プ咦咄拗祝粑粑迈r空氣,腦袋清醒的時(shí)候珠十,發(fā)現(xiàn)很多問(wèn)題其實(shí)不是問(wèn)題料扰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市焙蹭,隨后出現(xiàn)的幾起案子晒杈,更是在濱河造成了極大的恐慌,老刑警劉巖孔厉,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拯钻,死亡現(xiàn)場(chǎng)離奇詭異帖努,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)粪般,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門拼余,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人亩歹,你說(shuō)我怎么就攤上這事匙监。” “怎么了小作?”我有些...
    開(kāi)封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵亭姥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我顾稀,道長(zhǎng)达罗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任静秆,我火速辦了婚禮粮揉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诡宗。我一直安慰自己滔蝉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布塔沃。 她就那樣靜靜地躺著蝠引,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛀柴。 梳的紋絲不亂的頭發(fā)上螃概,一...
    開(kāi)封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音鸽疾,去河邊找鬼吊洼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛制肮,可吹牛的內(nèi)容都是我干的冒窍。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼豺鼻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼综液!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起儒飒,我...
    開(kāi)封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谬莹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體附帽,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埠戳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蕉扮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片整胃。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖喳钟,靈堂內(nèi)的尸體忽然破棺而出爪模,到底是詐尸還是另有隱情,我是刑警寧澤荚藻,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站洁段,受9級(jí)特大地震影響应狱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祠丝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一疾呻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧写半,春花似錦岸蜗、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至悔捶,卻和暖如春铃慷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜕该。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工犁柜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人堂淡。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓馋缅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親绢淀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萤悴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361