使用Kotlin:让Android与JS交互的详解

先来说说什么是JS交互:
说的俗一点就是通过我们项目中的控件来调用HTML里的JS代码,也可以通过JS来调用项目中的代码。
Android与JS之间的桥梁就是WebView了,我们是通过WebView来实现他们的相互调用。
Android调用Js代码:
Android调用Js代码有两种方式
1)通过WebView的loadUrl ()调用
2)通过WebView的evaluateJavascript ()调用
Js调用Android代码:
Js调用Android代码有三种方式
1)通过WebView的addJavascriptInterface ()进行对象映射
2)通过WebViewClient的shouldOverrideUrlLoading()来拦截Url调用代

3)通过WebChromeClient 的onJsAlert()、onJsConfirm()、
onJsPrompt()拦截JS中的对话框alert() / confirm() / prompt()


用Kotlin实现Android与JS交互


一、Android通过 loadUrl ()调用JS代码

1.把需要调用的JS代码以.Html的格式放到src/main/assets文件夹中,没有的新建一个

    <html>
      <head>
        <meta charset="utf-8" />
        <title>Android与Js交互</title>
      </head>
    <body>
               //JS的代码
        <script type="text/javascript">
              //无参方法
            function clickJS(){
                document.getElementById("zi").innerHTML = "Android调用了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()">我是一个按钮</button>

        <p id="zi">在这里改变代码</p>

         </body>
    </html>

2.在Android中用WebView调用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="调用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
    //        设置WebView可以与JS交互 这里必须设置
    settings.javaScriptEnabled = true
//        设置允许JS中的弹窗
    settings.javaScriptCanOpenWindowsAutomatically = true

//        然后加载JS代码
    android_web.loadUrl("file:///android_asset/index.html")
//        调用JS无参方法
    android_btn.setOnClickListener {
      android_web.post {
        run {
          //第一种方法 通过loadUrl调用JS代码
          //调用无参JS方法
          android_web.loadUrl("javascript:clickJS()")
          //调用有参JS方法
          // androidWeb.loadUrl("javascript:clickJS('我调用了JS的方法')")
        }
      }
    }
  }
}
富江原创.gif

Android通过evaluateJavascript ()调用JS代码

先来说说使用这个方法的优点

 使用这个方法不会刷新页面,如果使用第一种方法则会刷新页面
 *注意 这个方法只能在Android4.4之后使用

使用方式
1.将minSdkVersion最低版本改为19
build.gradle----minSdkVersion
2.直接替换第一种方式

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

两种方式的区别

1.loadUrl() 
 使用起来方便简洁。
 但是他是在没有返回的情况下使用。
 效率比较低,获取返回值的时候很麻烦。
 并且调用的时候会刷新WebView
2.evaluateJavascript ()
 效率比loadUrl ()高很多
 虽然效率高但是只支持Android4.4以上
 在获取返回值时候很方便
 调用时候不刷新WebView

根据情况使用两种方式
我们可以根据当前项目开发的需求选择相应的使用方式
我们可以直接判断版本号来区分使用方式

if (Build.VERSION.SDK_INT< 18) {
  android_web.loadUrl("javascript:clickJS()")
} else {
  android_web.evaluateJavascript("javascript:clickJS()") {
    //返回JS方法中的返回值,我们没有写返回值所以为null
  }
}

二、JS调用Android代码


1.使用WebView的addJavascriptInterface()进行对象映射

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

inner class JsObject {
    @JavascriptInterface
    fun jsAndroid(msg : String){
      //点击html的Button调用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.调用映射的对象    这里的androids是addJavascriptInterface()的第二个参数
        androids.jsAndroid("我是JS,我调用了Android的方法")
    }
</script>

来看看效果图


富江原创3.gif

2.使用WebViewClient ()的shouldOverrideUrlLoading ()方法拦截Url调用Android代码

使用这个方式需要定义一个协议进行拦截

<script type="text/javascript">
    function clickAndroid(){
        //定义url协议
        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是我们在JS方法中写的URL协议"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)
    }
  }

来看一下效果


富江原创4.gif

3.使用WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()拦截JS中的对话框alert() / confirm() / prompt()

<script type="text/javascript">
        function clickAndroid(){
            // 定义一个带输入框的弹窗
            var x = prompt("我又调用了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)
    }
  }

效果图


富江原创5.gif

三种区别

1)addJavascriptInterface ()使用起来方便简洁,但是再Android低版本下有问题,用于Android4.4以上

2)shouldOverrideUrlLoading ()使用起来没有漏洞,但是使用起来比较负责,主要用于不需要返回值的情况

3)onJsAlert()、onJsConfirm()、onJsPrompt()拦截JS中的对话框alert() / confirm() / prompt()
和第二种方式一样,没有漏洞,而且也复杂,并且需要协议来规定他。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容