使用Kotlin:讓Android與JS交互的詳解

先來說說什么是JS交互:
說的俗一點(diǎn)就是通過我們項(xiàng)目中的控件來調(diào)用HTML里的JS代碼,也可以通過JS來調(diào)用項(xiàng)目中的代碼雪情。
Android與JS之間的橋梁就是WebView了,我們是通過WebView來實(shí)現(xiàn)他們的相互調(diào)用你辣。
Android調(diào)用Js代碼:
Android調(diào)用Js代碼有兩種方式
1)通過WebView的loadUrl ()調(diào)用
2)通過WebView的evaluateJavascript ()調(diào)用
Js調(diào)用Android代碼:
Js調(diào)用Android代碼有三種方式
1)通過WebView的addJavascriptInterface ()進(jìn)行對(duì)象映射
2)通過WebViewClient的shouldOverrideUrlLoading()來攔截Url調(diào)用代

3)通過WebChromeClient 的onJsAlert()巡通、onJsConfirm()、
onJsPrompt()攔截JS中的對(duì)話框alert() / confirm() / prompt()


用Kotlin實(shí)現(xiàn)Android與JS交互


一舍哄、Android通過 loadUrl ()調(diào)用JS代碼

1.把需要調(diào)用的JS代碼以.Html的格式放到src/main/assets文件夾中宴凉,沒有的新建一個(gè)

    <html>
      <head>
        <meta charset="utf-8" />
        <title>Android與Js交互</title>
      </head>
    <body>
               //JS的代碼
        <script type="text/javascript">
              //無(wú)參方法
            function clickJS(){
                document.getElementById("zi").innerHTML = "Android調(diào)用了JS代碼"
            }
             //有參方法
            function clickJSTwo(x){
                document.getElementById("zi").innerHTML = x
            }
        //與Android交互的方法 
            function clickAndroid(){
                var result = prompt("js://webview?arg1=111&arg2=222")
                alert("demo" + result)
            }
        </script>

        <button type="button" onclick="clickAndroid()">我是一個(gè)按鈕</button>

        <p id="zi">在這里改變代碼</p>

         </body>
    </html>

2.在Android中用WebView調(diào)用Js代碼
//activity_main.xml布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

        <TextView
            android:id="@+id/android_js"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />

        <Button
            android:text="調(diào)用JS代碼"
            android:id="@+id/android_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <WebView
            android:id="@+id/android_web"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        </WebView>
    </LinearLayout>

//MainActivity.kt

class MainActivity : AppCompatActivity() {
  
  @SuppressLint("SetJavaScriptEnabled")
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val settings = android_web.settings
    //        設(shè)置WebView可以與JS交互 這里必須設(shè)置
    settings.javaScriptEnabled = true
//        設(shè)置允許JS中的彈窗
    settings.javaScriptCanOpenWindowsAutomatically = true

//        然后加載JS代碼
    android_web.loadUrl("file:///android_asset/index.html")
//        調(diào)用JS無(wú)參方法
    android_btn.setOnClickListener {
      android_web.post {
        run {
          //第一種方法 通過loadUrl調(diào)用JS代碼
          //調(diào)用無(wú)參JS方法
          android_web.loadUrl("javascript:clickJS()")
          //調(diào)用有參JS方法
          // androidWeb.loadUrl("javascript:clickJS('我調(diào)用了JS的方法')")
        }
      }
    }
  }
}
富江原創(chuàng).gif

Android通過evaluateJavascript ()調(diào)用JS代碼

先來說說使用這個(gè)方法的優(yōu)點(diǎn)

 使用這個(gè)方法不會(huì)刷新頁(yè)面,如果使用第一種方法則會(huì)刷新頁(yè)面
 *注意 這個(gè)方法只能在Android4.4之后使用

使用方式
1.將minSdkVersion最低版本改為19
build.gradle----minSdkVersion
2.直接替換第一種方式

androidWeb.evaluateJavascript("javascript:clickJS()",object : ValueCallback<String>{
                    override fun onReceiveValue(value: String?) {
//                            這里返回JS的結(jié)果
                    }
                })

兩種方式的區(qū)別

1.loadUrl() 
 使用起來方便簡(jiǎn)潔蠢熄。
 但是他是在沒有返回的情況下使用跪解。
 效率比較低,獲取返回值的時(shí)候很麻煩签孔。
 并且調(diào)用的時(shí)候會(huì)刷新WebView
2.evaluateJavascript ()
 效率比loadUrl ()高很多
 雖然效率高但是只支持Android4.4以上
 在獲取返回值時(shí)候很方便
 調(diào)用時(shí)候不刷新WebView

根據(jù)情況使用兩種方式
我們可以根據(jù)當(dāng)前項(xiàng)目開發(fā)的需求選擇相應(yīng)的使用方式
我們可以直接判斷版本號(hào)來區(qū)分使用方式

if (Build.VERSION.SDK_INT< 18) {
  android_web.loadUrl("javascript:clickJS()")
} else {
  android_web.evaluateJavascript("javascript:clickJS()") {
    //返回JS方法中的返回值叉讥,我們沒有寫返回值所以為null
  }
}

二、JS調(diào)用Android代碼


1.使用WebView的addJavascriptInterface()進(jìn)行對(duì)象映射

android_web.addJavascriptInterface(JsObject(),"android")

inner class JsObject {
    @JavascriptInterface
    fun jsAndroid(msg : String){
      //點(diǎn)擊html的Button調(diào)用Android的Toast代碼
      //我這里讓Toast居中顯示了
      val makeText = Toast.makeText(this@MainActivity, msg,Toast.LENGTH_LONG)
      makeText.setGravity(Gravity.CENTER,0,0)
      makeText.show()
    }
  }

2.JS的方法

<script type="text/javascript">
    function clickAndroid(){
        //用androids.調(diào)用映射的對(duì)象    這里的androids是addJavascriptInterface()的第二個(gè)參數(shù)
        androids.jsAndroid("我是JS,我調(diào)用了Android的方法")
    }
</script>

來看看效果圖


富江原創(chuàng)3.gif

2.使用WebViewClient ()的shouldOverrideUrlLoading ()方法攔截Url調(diào)用Android代碼

使用這個(gè)方式需要定義一個(gè)協(xié)議進(jìn)行攔截

<script type="text/javascript">
    function clickAndroid(){
        //定義url協(xié)議
        document.location = "js://webview?name=zhangsan&age=20&sex=0"
    }   
</script>

代碼中這樣寫

android_web.webViewClient = MyWebViewClient()

inner class MyWebViewClient : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
//      獲取Uri  這里的URL是我們?cè)贘S方法中寫的URL協(xié)議"js://webview?name=zhangsan&age=20&sex=0"
      val uri = Uri.parse(url)
      if (uri.scheme == "js") {
        if (uri.authority == "webview") {
          val makeText = Toast.makeText(this@MainActivity, url, Toast.LENGTH_LONG)
          makeText.setGravity(Gravity.CENTER, 0, 0)
          makeText.show()
        }
        return true
      }
      return super.shouldOverrideUrlLoading(view, url)
    }
  }

來看一下效果


富江原創(chuàng)4.gif

3.使用WebChromeClient的onJsAlert()饥追、onJsConfirm()图仓、onJsPrompt()攔截JS中的對(duì)話框alert() / confirm() / prompt()

<script type="text/javascript">
        function clickAndroid(){
            // 定義一個(gè)帶輸入框的彈窗
            var x = prompt("我又調(diào)用了Android的方法");
            alert("我是JS"+x)
        }
</script>

Android代碼

android_web.webViewClient = MyWebViewClient()

inner class MyWebChromeClient : WebChromeClient(){
    override fun onJsPrompt(view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?): Boolean {
      val makeText = Toast.makeText(this@MainActivity, message, Toast.LENGTH_LONG)
      makeText.setGravity(Gravity.CENTER,0,0)
      makeText.show()
      return super.onJsPrompt(view, url, message, defaultValue, result)
    }
  }

效果圖


富江原創(chuàng)5.gif

三種區(qū)別

1)addJavascriptInterface ()使用起來方便簡(jiǎn)潔,但是再Android低版本下有問題但绕,用于Android4.4以上

2)shouldOverrideUrlLoading ()使用起來沒有漏洞救崔,但是使用起來比較負(fù)責(zé)惶看,主要用于不需要返回值的情況

3)onJsAlert()、onJsConfirm()六孵、onJsPrompt()攔截JS中的對(duì)話框alert() / confirm() / prompt()
和第二種方式一樣纬黎,沒有漏洞,而且也復(fù)雜劫窒,并且需要協(xié)議來規(guī)定他本今。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市主巍,隨后出現(xiàn)的幾起案子冠息,更是在濱河造成了極大的恐慌,老刑警劉巖孕索,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逛艰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡搞旭,警方通過查閱死者的電腦和手機(jī)散怖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來选脊,“玉大人杭抠,你說我怎么就攤上這事】疑叮” “怎么了偏灿?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)钝的。 經(jīng)常有香客問我翁垂,道長(zhǎng),這世上最難降的妖魔是什么硝桩? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任沿猜,我火速辦了婚禮,結(jié)果婚禮上碗脊,老公的妹妹穿的比我還像新娘啼肩。我一直安慰自己,他們只是感情好衙伶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布祈坠。 她就那樣靜靜地躺著,像睡著了一般矢劲。 火紅的嫁衣襯著肌膚如雪赦拘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天芬沉,我揣著相機(jī)與錄音躺同,去河邊找鬼阁猜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蹋艺,可吹牛的內(nèi)容都是我干的剃袍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捎谨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼笛园!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侍芝,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埋同,沒想到半個(gè)月后州叠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凶赁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年咧栗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虱肄。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡致板,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咏窿,到底是詐尸還是另有隱情斟或,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布集嵌,位于F島的核電站萝挤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏根欧。R本人自食惡果不足惜怜珍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凤粗。 院中可真熱鬧酥泛,春花似錦、人聲如沸嫌拣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)亭罪。三九已至瘦馍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間应役,已是汗流浹背情组。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工燥筷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院崇。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓肆氓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親底瓣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谢揪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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