先来说说什么是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()
1.把需要调用的JS代码以.Html的格式放到src/main/assets文件夹中,没有的新建一个
<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的方法"+")")
}
}
})
}
}
先来说说使用这个方法的优点
使用这个方法不会刷新页面,如果使用第一种方法则会刷新页面
*注意 这个方法只能在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
}
})
}
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>
来看看效果图
使用这个方式需要定义一个协议进行拦截
<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)
}
}
来看一下效果
<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)
}
}
效果图
1)addJavascriptInterface ()使用起来方便简洁,但是再Android低版本下有问题,用于Android4.4以上
2)shouldOverrideUrlLoading ()使用起来没有漏洞,但是使用起来比较负责,主要用于不需要返回值的情况
3)onJsAlert()、onJsConfirm()、onJsPrompt()拦截JS中的对话框alert() / confirm() / prompt()
和第二种方式一样,没有漏洞,而且也复杂,并且需要协议来规定他。