先来说说什么是 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() {
- 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)
- // 初始化控件
- 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 的方法"+")")
- }
- }
- })
- }
- }
富江原创. 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) {
- androidWeb!!.loadUrl("javascript:clickJS()")
- } else {
- androidWeb!!.evaluateJavascript("javascript:clickJS()", object : ValueCallback<String> {
- override fun onReceiveValue(value: String?) {
- // 返回 JS 方法中的返回值, 我们没有写返回值所以为 null
- }
- })
- }
二, JS 调用 Android 代码
1. 使用 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")
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>
代码中这样写
- 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)
- }
- }
来看一下效果
富江原创 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 代码
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)
- }
- }
效果图
富江原创 5.gif
三种区别
1)addJavascriptInterface () 使用起来方便简洁, 但是再 Android 低版本下有问题, 用于 Android4.4 以上
2)shouldOverrideUrlLoading () 使用起来没有漏洞, 但是使用起来比较负责, 主要用于不需要返回值的情况
3)onJsAlert(),onJsConfirm(),onJsPrompt() 拦截 JS 中的对话框 alert() / confirm() / prompt()
和第二种方式一样, 没有漏洞, 而且也复杂, 并且需要协议来规定他.
来源: http://www.jianshu.com/p/826a39ed81e6