Android中WebView與原生通信

在Android原生開發(fā)中砌左,應該80%的都會遇到原生與Js的混合調用淆两,網(wǎng)上有很多示例住闯,都可以實現(xiàn)需求瓜浸,但是基本是表層實現(xiàn),當然也有一些也寫的非常不錯比原,但是不知為什么就沒有更新了插佛,然后工程還缺少文件。其實我們在WebView和原生相互調用量窘,無非就以下幾個問題:

  • 原生調用Js雇寇,Js如何異步回調給原生,同一個調用多次回調呢蚌铜,一次回調锨侯、兩次回調、三次......呢冬殃?
  • Js調用原生囚痴,原生如何異步回調給Js,同一個調用多次回調呢审葬,一次回調深滚、兩次回調奕谭、三次......呢?不通過WebView的loadUrl執(zhí)行js進行回調呢痴荐?
  • 我想在寫Js時候這樣操作呢血柳?
  JsBridge.nativeDeleteCallback("調用原生方法后刪除回調",function(result){
        alert(JSON.stringify(result))
    },function(error){
        alert(JSON.stringify(result))
  });

針對上面問題,本文也相應的解決了這寫問題蹬昌,參考Demo ,也可以先下載Demo運行之后一目了然混驰。

SDK支持

  • Js調用原生方法并支持異步回調和同步回調
  • 原生調用Js方法并支持異步回調
  • Js調用名稱空間可自由配置,統(tǒng)一管理命名空間
  • 支持Js調用原生方法多次回調皂贩,如果不想多次回調可以刪除回調方法
  • 支持部分Js框架中window并非頂級window

API介紹

callJsFunction(function: String)
原生調用Js的方法栖榨,不支持傳遞參數(shù)和回調

參數(shù):
function:調用Js的方法名稱

callJsFunction(function: String, callback: JsCallback?)
原生調用Js的方法,不支持傳遞參數(shù)但支持回調

參數(shù)
function:調用Js的方法名稱
callback:回調函數(shù)

callJsFunction(function: String, data: String?)
原生調用Js的方法明刷,支持傳遞參數(shù)婴栽,但不支持回調

參數(shù)
function:調用Js的方法名稱
data:字符串,傳遞給Js的參數(shù)

callJsFunction(function: String, data: String?, callback: JsCallback?)
原生調用Js的方法辈末,支持傳遞參數(shù)和回調

參數(shù)
function:調用Js的方法名稱
data:字符串愚争,傳遞給Js的參數(shù)
callback:回調函數(shù)

jsCallName()
Js調用原生的API命名空間,SDK統(tǒng)一了命名空間挤聘,默認為JsBridge轰枝,整個Js調用中只會使用這個命名,當然组去,如果是你不喜歡這個命名鞍陨,或者需要根據(jù)項目更改為項目有關的命名,可以自定義WebView繼承至BaseWebView重寫該方法从隆。

getWindow()
Js中獲取window的方法诚撵,建議不要隨意修改。在特殊的Js框架中键闺,獲取系統(tǒng)的window需要window.window才能獲取到寿烟,所以這時候可以自定義WebView繼承至BaseWebView重寫該方法。

如何使用

依賴引入

Step 1.先在 build.gradle(Project:XXX) 的 repositories 添加:

allprojects {
  repositories {
  ...
  maven { url "https://jitpack.io" }
  }
}

Step 2. 然后在 build.gradle(Module:XXX) 的 dependencies 添加:

dependencies {
          implementation 'com.github.ChinaLike:JsBridge:0.0.2'
}

新建Js調用原生方法的類辛燥,參考:JsBridgeToast

package com.like.jsbridge

import android.content.Context
import android.os.Handler
import android.util.Log
import android.webkit.JavascriptInterface
import android.widget.Toast
import com.core.web.Callback
import com.core.web.CallbackBean

class JsBridgeToast(private val context: Context)  {

    @JavascriptInterface
    fun nativeNoArgAndNoCallback(){
        Toast.makeText(context,"調用原生無參數(shù)無回調方法",Toast.LENGTH_SHORT).show()
    }

    @JavascriptInterface
    fun nativeNoArgAndCallback(callback: Callback){
        callback.success()
    }

    @JavascriptInterface
    fun nativeArgAndNoCallback(params:String){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
    }

    @JavascriptInterface
    fun nativeArgAndCallback(params:String,callback: Callback):Boolean{
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success()
        return false
    }

    @JavascriptInterface
    fun nativeDeleteCallback(params:String,callback: Callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success(isDelete = true)
        Handler().postDelayed(Runnable {
            callback.error(1,"錯誤回調")
        },3000)
    }

    @JavascriptInterface
    fun nativeNoDeleteCallback(params:String,callback: Callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success(isDelete = false)
        Handler().postDelayed(Runnable {
            callback.error(1,"錯誤回調")
        },3000)
    }

    @JavascriptInterface
    fun nativeSyncCallback():String{
        return "原生同步回調"
    }
}

新建MainActivity和xml文件,參考:MainActivityKotlinactivity_main

  • 在xml文件中引入JsBridgeWebView
<com.core.web.JsBridgeWebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

當然筛武,如果沒有特殊需要使用JsBridgeWebView就可以了,如果有定制WebView挎塌,則引入自己定制那個WebView就可以了畅铭,但是自定義的WebView需要繼承BaseWebView

  • 在Activity中調用addJavascriptInterface添加
import com.core.web.JsBridgeWebView;

class MainActivityKotlin : AppCompatActivity() {
    private var webView: JsBridgeWebView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        webView = findViewById(R.id.webView)
        webView?.addJavascriptInterface(JsBridgeToast(this))
        webView?.loadUrl("file:///android_asset/test.html")
}

注意:webView的addJavascriptInterface方法可以多次調用,開發(fā)時可以根據(jù)業(yè)務功能進行解耦勃蜘,addJavascriptInterface方法支持傳遞一個或兩個參數(shù),傳遞兩個參數(shù)時第二個參數(shù)無效假残。

在Js中調用原生方法缭贡,參考:test.html

  • Js調用原生無參無回調方法

    • Kotlin代碼
    @JavascriptInterface
    fun nativeNoArgAndNoCallback(){
        Toast.makeText(context,"調用原生無參數(shù)無回調方法",Toast.LENGTH_SHORT).show()
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeNoArgAndNoCallback(){
        Toast.makeText(context,"調用原生無參數(shù)無回調方法",Toast.LENGTH_SHORT).show();
    }
    
    • Js代碼
    JsBridge.nativeNoArgAndNoCallback();
    
  • Js調用原生無參有回調方法

    • Kotlin代碼
    @JavascriptInterface
    fun nativeNoArgAndCallback(callback: Callback){
        callback.success()
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeNoArgAndCallback(Callback callback){
        callback.success();
    }
    
    • Js代碼
    JsBridge.nativeNoArgAndCallback(function(result){
        alert(JSON.stringify(result));
    });
    
  • Js調用原生有參無回調方法

    • Kotlin代碼
    @JavascriptInterface
    fun nativeArgAndNoCallback(params:String){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeArgAndNoCallback(String params){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show();
    }
    
    • Js代碼
    JsBridge.nativeArgAndNoCallback("調用原生有參數(shù)無回調方法");
    
  • Js調用原生有參有回調方法

    • Kotlin代碼
    @JavascriptInterface
    fun nativeArgAndCallback(params:String,callback: Callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success()
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeArgAndCallback(String params,Callback callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show();
        callback.success();
    }
    
    • Js代碼
    JsBridge.nativeArgAndCallback("調用原生有參數(shù)有回調方法",function(result){
        alert(JSON.stringify(result))
    });
    
  • Js調用原生有參有回調方法炉擅,且只能回調一次

    • Kotlin代碼
    @JavascriptInterface
    fun nativeDeleteCallback(params:String,callback: Callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success(true)
        Handler().postDelayed(Runnable {
            callback.error(1,"錯誤回調")
        },3000)
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeDeleteCallback(String params,Callback callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show();
        callback.success(true);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                callback.error(1,"錯誤回調");
            }
        },3000);
    }
    
    • Js代碼
    JsBridge.nativeDeleteCallback("調用原生方法后刪除回調",function(result){
        alert(JSON.stringify(result))
    },function(error){
        alert(JSON.stringify(result))
    });
    
  • Js調用原生有參有回調方法飘弧,且能回調多次

    • Kotlin代碼
    @JavascriptInterface
    fun nativeNoDeleteCallback(params:String,callback: Callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show()
        callback.success(false)
        Handler().postDelayed(Runnable {
            callback.error(1,"錯誤回調")
        },3000)
    }
    
    • Java代碼
    @JavascriptInterface
    public void nativeNoDeleteCallback(String params,Callback callback){
        Toast.makeText(context,params,Toast.LENGTH_SHORT).show();
        callback.success(false);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                callback.error(1,"錯誤回調");
            }
        },3000);
    }
    
    • Js代碼
    JsBridge.nativeNoDeleteCallback("調用原生方法后不刪除回調",function(result){
        alert(JSON.stringify(result))
    },function(error){
        alert(JSON.stringify(error))
    });
    
  • Js調用原生同步回調數(shù)據(jù)

    • Kotlin代碼
    @JavascriptInterface
    fun nativeSyncCallback():String{
        return "原生同步回調"
    }
    
    • Java代碼
    @JavascriptInterface
    public String nativeSyncCallback(){
        return "原生同步回調";
    }
    
    • Js代碼
    var  result = JsBridge.nativeSyncCallback();
    alert(result)
    

注意:@JavascriptInterface注解的方法谷扣,只支持最多兩個參數(shù)泣矛,不論順序测蹲。無參數(shù):代表Js不傳遞參數(shù)過來也不回調骤竹;一個參數(shù):可以是傳遞過來的參數(shù)或回調猜谚;兩個參數(shù):一個為參數(shù)雕薪,一個是回調曙博。

在原生中調用Js方法纲岭,參考:MainActivity

  • 原生調用JS無參數(shù)無回調

    • Js代碼
    function jsNoArgAndNoCallback(){
        alert("原生調用JS無參數(shù)無回調");
    }
    
    • Java代碼
    webView.callJsFunction("jsNoArgAndNoCallback");
    
    • Kotlin代碼
    webView?.callJsFunction("jsNoArgAndNoCallback")
    
  • 原生調用Js無參數(shù)有回調

    • Js代碼
    function jsNoArgAndCallback(callback){
            alert("原生調用JS無參數(shù)有回調");
            callback("我是JS回調數(shù)據(jù)");
    }
    
    • Java代碼
    webView.callJsFunction("jsNoArgAndCallback", callback -> Toast.makeText(this, "" + callback, Toast.LENGTH_SHORT).show());
    
    • Kotlin代碼
    webView?.callJsFunction("jsNoArgAndCallback", object : JsCallback {
            override fun onCallback(callback: Any) {
                Toast.makeText(this@MainActivityKotlin, "$callback", Toast.LENGTH_SHORT).show()
            }
        })
    
  • 原生調用Js有參數(shù)無回調

    • Js代碼
    function jsArgAndNoCallback(params){
            alert(params);
    }
    
    • Java代碼
    webView.callJsFunction("jsArgAndNoCallback", "原生傳遞過來的參數(shù)");
    
    • Kotlin代碼
    webView?.callJsFunction("jsArgAndNoCallback","原生傳遞過來的參數(shù)")
    
  • 原生調用Js有參數(shù)有回調(可回調多次)

    • Js代碼
    function jsArgAndCallback(params,callback){
            alert(params);
            callback("我是JS第一次回調數(shù)據(jù)");
            setTimeout(function() {
                    callback("我是JS第二次回調數(shù)據(jù)");
            }, 500);
    }
    
    • Java代碼
    webView.callJsFunction("jsArgAndCallback", "原生傳遞過來的參數(shù)", callback -> Toast.makeText(this, "" + callback, Toast.LENGTH_SHORT).show());
    
    • Kotlin代碼
    webView?.callJsFunction("jsArgAndCallback","原生傳遞過來的參數(shù)", object : JsCallback {
            override fun onCallback(callback: Any) {
                Toast.makeText(this@MainActivityKotlin, "$callback", Toast.LENGTH_SHORT).show()
            }
        })
    
  • 調用Js有參數(shù)有回調(只能回調一次)

    • Js代碼
    function jsArgAndDeleteCallback(params,callback){
            alert(params);
            callback("我是JS第一次回調數(shù)據(jù)",true);
            setTimeout(function() {
                    callback("我是JS第二次回調數(shù)據(jù)");
            }, 500);
    }
    
    • Java代碼
    webView.callJsFunction("jsArgAndDeleteCallback", "原生傳遞過來的參數(shù)", callback -> Toast.makeText(this, "" + callback, Toast.LENGTH_SHORT).show());
    
    • Kotlin代碼
    webView?.callJsFunction("jsArgAndDeleteCallback","原生傳遞過來的參數(shù)", object : JsCallback {
            override fun onCallback(callback: Any) {
                Toast.makeText(this@MainActivityKotlin, "$callback", Toast.LENGTH_SHORT).show()
            }
        })
    

注意:原生調用Js代碼抹竹,Js的方法最多支持兩個參數(shù),無參數(shù):代表原生不傳遞參數(shù)過來也不用回調給原生止潮; 一個參數(shù):可以是參數(shù)也可以是回調窃判;兩個參數(shù):有序,第一個為參數(shù)喇闸,第二個為回調袄琳,代表原生傳遞過來參數(shù),且需要回調給原生

如有問題歡迎留言 源碼地址

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燃乍,一起剝皮案震驚了整個濱河市唆樊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刻蟹,老刑警劉巖逗旁,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異座咆,居然都是意外死亡痢艺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門介陶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堤舒,“玉大人,你說我怎么就攤上這事哺呜∩噻停” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵某残,是天一觀的道長国撵。 經(jīng)常有香客問我,道長玻墅,這世上最難降的妖魔是什么介牙? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮澳厢,結果婚禮上环础,老公的妹妹穿的比我還像新娘囚似。我一直安慰自己,他們只是感情好线得,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布饶唤。 她就那樣靜靜地躺著,像睡著了一般贯钩。 火紅的嫁衣襯著肌膚如雪募狂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天角雷,我揣著相機與錄音祸穷,去河邊找鬼。 笑死谓罗,一個胖子當著我的面吹牛粱哼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播檩咱,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼揭措,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刻蚯?” 一聲冷哼從身側響起绊含,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炊汹,沒想到半個月后躬充,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡讨便,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年充甚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霸褒。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡伴找,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出废菱,到底是詐尸還是另有隱情技矮,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布殊轴,位于F島的核電站衰倦,受9級特大地震影響,放射性物質發(fā)生泄漏旁理。R本人自食惡果不足惜樊零,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望孽文。 院中可真熱鬧驻襟,春花似錦十性、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楷掉。三九已至厢蒜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烹植,已是汗流浹背斑鸦。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留草雕,地道東北人巷屿。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像墩虹,于是被迫代替她去往敵國和親嘱巾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容