Android 去调用JS 的代码
通过WebView的loadUrl()
先写一个html,很简单的一个代码,alert显示。
android_load_js.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Android调用 JS 代码demo</title> // JS代码 <script> // Android需要调用的方法 function callJS(){ alert("Android调用了JS的callJS方法"); } </script> </head> </html>
在Activity中
mWebSettings = mWebview.getSettings(); //与JS交互开关 mWebSettings.setJavaScriptEnabled(true); //设置允许JS弹窗 mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true); mWebview.loadUrl("file:///android_asset/android_load_js.html"); //在这我用了一个TextView 点击事件中去调用JS中的方法 beginLoading.setOnClickListener(new View.OnClickListener() { [@Override](https://my.oschina.net/u/1162528) public void onClick(View view) { //执行JS方法 mWebview.loadUrl("javascript:callJS()"); } }); mWebview.setWebChromeClient(new WebChromeClient() { //获取网站标题 [@Override](https://my.oschina.net/u/1162528) public void onReceivedTitle(WebView view, String title) { System.out.println("标题在这里"); mtitle.setText(title); } //获取加载进度 [@Override](https://my.oschina.net/u/1162528) public void onProgressChanged(WebView view, int newProgress) { if (newProgress < 100) { String progress = newProgress + "%"; loading.setText(progress); } else if (newProgress == 100) { String progress = newProgress + "%"; loading.setText(progress); } } //由于设置了弹窗检验调用结果,所以需要支持js对话框 //webview只是载体,内容的渲染需要使用webviewChromClient类去实现 //通过设置WebChromeClient对象处理JavaScript的对话框 //设置响应js 的Alert()函数 [@Override](https://my.oschina.net/u/1162528) public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { AlertDialog.Builder b = new AlertDialog.Builder(TestActivity.this); b.setTitle("Alert"); b.setMessage(message); b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { [@Override](https://my.oschina.net/u/1162528) public void onClick(DialogInterface dialog, int which) { result.confirm(); } }); b.setCancelable(false); b.create().show(); return true; } });
通过WebView的evaluateJavascript()
该方法比第一种方法效率更高,因为该方法的执行不会使页面刷新,而第一种方法(loadUrl)的执行则会。该方法在Android 4.4 后才可使用,该方法在主线程执行
//将上面webView.loadUrl("javascript:callJS()")替换为 mWebview.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此处为 js 返回的结果 } });
可以做一下兼容:
if (Build.VERSION.SDK_INT > 18) { mWebview.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此处为 js 返回的结果 } }); } else { mWebview.loadUrl("javascript:callJS()"); }
JS 去调用 Android的代码
通过WebView的addJavaScriptInterface()进行对象映射
html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>DEMO</title> <script> function callAndroid(){ // 由于对象映射,所以调用test对象等于调用Android映射的对象 test.showLog("js调用了android中的hello方法"); } </script> </head> <body> //点击按钮则调用callAndroid函数 <button type="button" id="button1" onclick="callAndroid()" text="Android"></button> </body> </html>
映射的代码
package org.professor.procartoon.temp; import android.webkit.JavascriptInterface; import org.professor.procartoon.utils.LogUtils; /** * Created by Caipeng on 2018.02.06. */ public class JSObject { /** * 定义JS需要调用的方法被JS调用的方法必须加入@JavascriptInterface注解 */ @JavascriptInterface public void showLog(String text) { LogUtils.i(text); } }
在Activity中的测试代码
mWebSettings.setJavaScriptEnabled(true); mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true); //通过addJavascriptInterface()将Java对象映射到JS对象 //参数1:Javascript对象名 //参数2:Java对象名 mWebview.addJavascriptInterface(new JSObject(),"test"); mWebview.loadUrl("file:///android_asset/android_load_js.html");
通过WebViewClient的ShouldOverrideUrlLoading() 方法进行回调拦截
Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url,解析该 url 的协议,如果检测到是预先约定好的协议,就调用Android相应的方法。
html Document
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>DEMO</title> <script> function callAndroid(){ //协议org://professor?arg1=com&arg2=test document.location = "org://professor?arg1=111&arg2=222"; } </script> </head> <body> //点击按钮则调用callAndroid函数 <button type="button" id="button1" onclick="callAndroid()">CallAndroid</button> </body> </html>
JAVA代码
@Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { //一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) Uri uri = Uri.parse(request.getUrl().toString()); if (uri.getScheme().equals("org")) { if (uri.getAuthority().equals("professor")) { LogUtils.i(uri.getQueryParameter("arg1")); } return true; } return super.shouldOverrideUrlLoading(view, request); }
备注
JS获取Android方法的返回值复杂。 如果JS想要得到Android方法的返回值,只能通过 WebView 的loadUrl ()去执行 JS 方法把返回值传递回去,相关的代码如下:
//Android原生调用js mWebView.loadUrl("javascript:returnResult(" + result + ")"); //需要在html中接收 function returnResult(result){ alert("result is" + result); }
通过WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
首先介绍下JS中的alert()、confirm()、prompt()三个方法
- alert(),弹出警告窗,没有返回值,在文本加入\n可换行
- confirm(),弹出确认框,两个返回值,返回布尔值,通过该值可以判断点击是确认还是取消(true表示点击了确认,false表示点击了取消)
- prompt(),弹出输入框,任意设置返回值,点击确认返回输入框中的值,点击取消返回null
原理:Android通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调分别拦截JS对话框 (即上面的三个方法),得到他们的消息内容,然后解析即可。
常用的拦截是:拦截 JS的输入框(即prompt()方法)。因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值。
html代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>DEMO</title> <script> function callAndroid(){ //document.location = "org://professor?arg1=111&arg2=222"; var result=prompt("org://professor?arg1=111&arg2=222"); alert("demo " + result); } </script> </head> <body> //点击按钮则调用callAndroid函数 <button type="button" id="button1" onclick="callAndroid()">CallAndroid</button> </body> </html>
JAVA代码
@Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { //一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) Uri uri = Uri.parse(url); if (uri.getScheme().equals("org")) { if (uri.getAuthority().equals("professor")) { LogUtils.i(uri.getQueryParameter("arg1")); //参数result:代表消息框的返回值(输入值) result.confirm("js调用了Android的方法成功啦"); } return true; } return super.onJsPrompt(view, url, message, defaultValue, result); }
结语
由上可以比较,根据第三种方式,即:通过WebChromeClient的方法拦截比较灵活一些