[toc]

先来说说什么是JS交互:

说的俗一点就是通过我们项目中的控件来调用HTML里的JS代码,也可以通过JS来调用项目中的代码。
Android与JS之间的桥梁就是WebView了,我们是通过WebView来实现他们的相互调用。

Android调用Js代码:

Android调用Js代码有两种方式

1.通过WebView的loadUrl ()调用

把需要调用的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>

在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() {
  private var androidText : TextView? = null
  private var androidBtn : Button? = null
  private var androidWeb : WebView? = null
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
  //        初始化控件
 //       kotlin不需要findViewById,直接使用控件id调用即可,这里是为了刚入门kotlin的人可以看的更直白
      androidText = findViewById(R.id.android_text)
      androidBtn = findViewById(R.id.android_btn)
      androidWeb = findViewById(R.id.android_web)

      val settings = androidWeb.settings
  //        设置WebView可以与JS交互 这里必须设置
      settings.javaScriptEnabled = true
  //        设置允许JS中的弹窗
      settings.javaScriptCanOpenWindowsAutomatically = true
  //        然后加载JS代码
      androidWeb.loadUrl(file:///android_asset/index.html)
  //        调用JS无参方法
      androidBtn.setOnClickListener({
          androidWeb.post {
              run {
                  //第一种方法 通过loadUrl调用JS代码
                  //调用无参JS方法
                  androidWeb.loadUrl(javascript:clickJS())
                  //调用有参JS方法
                 // androidWeb!!.loadUrl(javascript:clickJS(+我调用了JS的方法+))
              }
          }
      })
  }
}

loadUrl()交互

2.通过WebView的evaluateJavascript ()调用

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

使用方式

  1. 将minSdkVersion最低版本改为19build.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

Js调用Android代码有三种方式

通过WebView的addJavascriptInterface ()进行对象映射

androidWeb.addJavascriptInterface(object : Object(){
        @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()
        }
      //第二个参数可以自己随便设置,在html里会用到
    },"androids")

js的方法

<script type="text/javascript">
    function clickAndroid(){
        //用androids.调用映射的对象    这里的androids是addJavascriptInterface()的第二个参数
        androids.jsAndroid("我是JS,我调用了Android的方法")
    }
</script>

addJavascriptInterface()

通过WebViewClient的shouldOverrideUrlLoading()来拦截Url调用代码

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

<script type="text/javascript">
    function clickAndroid(){
        //定义url协议
        document.location = "js://webview?name=zhangsan&age=20&sex=0"
    }   
</script>

Android 代码中这样写

androidWeb.webViewClient = object : WebViewClient(){
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
//      获取Uri  这里的URL是我们在JS方法中写的URL协议"js://webview?name=zhangsan&age=20&sex=0"
       var 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)
        }
    }

shouldOverrideUrlLoading()

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

<script type="text/javascript">
        function clickAndroid(){
            // 定义一个带输入框的弹窗
            var x = prompt("我又调用了Android的方法");
            alert("我是JS"+x)
        }
</script>
androidWeb.webChromeClient = object : 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)
    }
}

拦截对话框

三种区别

  1. addJavascriptInterface ()使用起来方便简洁,但是再Android低版本下有问题,用于Android4.4以上
  2. shouldOverrideUrlLoading ()使用起来没有漏洞,但是使用起来比较负责,主要用于不需要返回值的情况
  3. onJsAlert()、onJsConfirm()、onJsPrompt()拦截JS中的对话框alert() / confirm() / prompt()和第二种方式一样,没有漏洞,而且也复杂,并且需要协议来规定他。
说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...