前言
上篇介绍了WebView
的基本使用,WebView
使用中常用的类和方法。本篇将介绍WebView
中Android
原生Javascript
之间交互。以及它们之间通信桥梁JSBridge
。
1、Android调用JS
Android
调用Javascript
有两种方法,第一种是通过loadUrl
方法,第二种是通过evaluateJavascript
。
1-1.loadUrl示例
首先新建index.html
放在android
工程的assets
目录下。
看下Html
中的Javascript
代码和Android
中调用,JS代码相对比较简单。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebView测试</title>
</head>
<script type="text/javascript">
<!--android将调用的方法-->
function androidCallJs(){
alert("android 调用了 JS了")
}
</script>
</html>
看下Android
中如何实现调用JavaScript
代码的。
布局文件:
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/callJsBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击调用 JS" />
Kotlin
代码:
//初始化webview
val webView = getView(R.id.webview)
//设置webview选项参数
val webSetting = webView!!.settings
//设置webview可以调用javascript代码
webSetting.javaScriptEnabled = true
//设置javascript可以自动弹弹窗
webSetting.javaScriptCanOpenWindowsAutomatically = true
//加载html,这里android_asset是固定写法
webView!!.loadUrl("file:///android_asset/index.html")
callJsBtn = getView(R.id.callJsBtn)
callJsBtn!!.setOnClickListener {
//点击调用Js方法
webView!!.loadUrl("javascript:androidCallJs()")
}
//webview是加载整个html作用,内容的渲染需要使用它的功能辅助类WebviewChromClient类去实现
webView!!.webChromeClient = object : WebChromeClient() {
override fun onJsAlert(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
val b = AlertDialog.Builder(this@MainActivity);
b.setTitle("Android Call Js")
b.setMessage(message)
b.setPositiveButton("确定",object :DialogInterface.OnClickListener{
override fun onClick(dialog: DialogInterface?, which: Int) {
result!!.confirm()
}
})
b.setCancelable(false)
b.create().show()
return true
}
}
1-2、evaluateJavascript示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebView测试</title>
</head>
<script type="text/javascript">
//android调用js代码第二种方法
function androidCallJs(){
alert("android evaluateJs 调用了 JS了")
return "Android你能收到消息吗?"
}
</script>
</html>
callJsBtn!!.setOnClickListener {
//第二种方法调用JS
webView!!.evaluateJavascript("javascript:androidCallJs()", object : ValueCallback<String> {
//Js返回的值
override fun onReceiveValue(value: String?) {
ToastUtils.show(value!!)
}
})
// webView!!.loadUrl("javascript:androidCallJs()")
}
只要将第一种方法loadUrl
更换为evaluateJavascript
方法即可。这种方法相比较第一种方法,能够接收到Javascript
返回值,loadUrl
只能显示。
2、JS调用Android
2-1.WebView
提供方法 addJavascriptInterface
将Javascript
和Android
建立映射关系。
2-1-1.Html
声明映射对象以及Android
被调用的方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>JS调用Android测试1</title>
</head>
<script type="text/javascript">
function JsCallAndroid(){
<!--testHello是android中注册的对象,helloJs()是android中的方法-->
testHello.helloJs("JsCallAndroid")
}
</script>
<body>
<button type="button" id="btn" onclick="JsCallAndroid()">点击调用Android代码</button>
</body>
</html>
2-1-2、定义与Javascript映射关系的Android类
class AndroidToJs : Object() {
//注解映射
@JavascriptInterface
fun helloJs(msg: String) {
ToastUtils.show("Js 调用了 Android helloJs方法了")
}
}
2-1-3、Kotlin添加Javascript和Android映射关系
//初始化webview
webView = getView(R.id.webview)
//设置webview选项参数
val webSetting = webView!!.settings
//设置webview可以调用javascript代码
webSetting.javaScriptEnabled = true
//加载html
webView!!.loadUrl("file:///android_asset/index.html")
//Webview添加Js和Android映射关系
webView!!.addJavascriptInterface(AndroidToJs(), "testHello")
AndroidToJs
是Android
的映射类。Kotiln
的写法。testHello
是映射到Javascript
的映射类的对象,名字可以随意取。
2-2、WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截消息解析。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS调用Android测试1</title>
</head>
<script>
function clickprompt(){
// 调用prompt() 定义js和android通信协议
var result=prompt("js://test?param1=hello11¶m1=hello22");
alert("test" + result);
}
</script>
<!-- 点击按钮则调用clickprompt() -->
<body>
<button type="button" id="btn" onclick="clickprompt()">点击调用Android代码</button>
</body>
</html>
webView!!.webChromeClient = object : WebChromeClient() {
override fun onJsPrompt(view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?): Boolean {
val uri = Uri.parse(message)
// 如果uri协议 = 预先约定的 js 协议,解析参数
if (uri.scheme == "js") {
// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
// 所以拦截url,下面JS开始调用Android需要的方法
if (uri.authority == "webview") {
// 执行JS所需要调用的逻辑
ToastUtils.show("Js 调用了 Android 中 helloToJS代码")
// 可以在协议上带有参数并传递到Android上
val params = HashMap<String, String>()
var collection = uri!!.queryParameterNames
//参数result:代表消息框的返回值(输入值)
result!!.confirm("js调用了Android的方法成功啦")
}
return true
}
return super.onJsPrompt(view, url, message, defaultValue, result)
}
}
WebView
在Android4.2
以下版本产生安全问题有一种情况就是通过第一种添加Javascript
和Android
映射关系的方式。第二种方式就是较为安全,不会产生安全漏洞问题。但是要Android
和js
约定一个协议通信,相对实现起来比较复杂,onJsAlert
和onJsConfirm
和上述实现方式一样。
3、BridgeWebView
BridgeWebView
,继承了WebView
类,实现了WebViewJavascriptBridge
接口,这里介绍下它的使用方式。
3-1.Gradle引入
compile 'com.github.lzyzsd:jsbridge:1.0.4'
3-2、使用方法
3-2-1、自定义JS事件回调类
private class MyHadlerCallBack extends DefaultHandler {
@Override
public void handler(String data, CallBackFunction function) {
if (function != null) {
Toast.makeText(JsBridgeVoteActivity.this, "自定义类继承DefaultHandler:" + data, Toast.LENGTH_SHORT).show();
}
}
}
3-2-2、自定义JS事件回调类
BridgeWebView webView = new BridgeWebView(this);
//设置默认回调处理类
webView.setDefaultHandler(new MyHadlerCallBack());
//注册Js和android之间通信的事件
webView.registerHandler("openLogin", (data, function) -> openLogin());
以上面的代码为例,在Android
中注册了事件openLogin
,这里也需要在Html
页面的Javascript
代码中进行注册相同的事件名称 openLogin
。意味着在Html
页面上用户(未登录情况下)触发登录操作。登录事件要在isBindPhone
代码中完成。
private void openLogin() {
new LoginDialog(this, new LoginDialog.OnLoginCallBack() {
@Override
public void login() {
HashMap<String, Object> params = new HashMap<>();
/*method是和js约定,这是调用方法,后面是登录成功操作*/
params.put("method", "loginSuccess");
/*webView通知js已经登录成功*/
webView.callHandler("call", new Gson().toJson(params), data ->{
});
}
}).show();
}
Javascript
调用Android
登录方法,Android
端登录成功后通过webView.callHandler
方法通知h5页面客户端登录成功,做相应的操作即可。BridgeWebView
的使用方法就是这么简单,内部已经将通信机制封装好。
总结
本篇介绍了WebView
上js和Android
互相调用方法。在大前端概念的趋势下,原生Android
和H5
的联系会越来越紧密。下篇将介绍在重构过程中WebView
上遇到的问题,以及WebView
最让人关系的内存泄漏问题以及解决方案。对于H5
和Java
层结合的混合开发Hybrid的研究也将在以后的WebView
系列中做介绍。