[关闭]
@Tyhj 2019-03-12T03:54:15.000000Z 字数 8455 阅读 1185

Android WebView与JavaScript的交互

Android


之前有写过WebView的小demo,之后一直没有在项目中使用过网页开发,最近准备重新再看一下,记录一些基本的使用方法

相关链接:Android使用JsBridge与JavaScript交互

JavaScript调用Android方法

  • 第一种是用webView的JavascriptInterface注解进行对象映射
  • 第二种是通过webViewClient的shouldOverrideUrlLoading()方法拦截URL
  • 第三种是通过WebChromeClient的onJsAlert()onJsConfirm()onJsPrompt()来拦截JS对话框alert()confirm();

对象映射

比较简单,在Android的对象里面申明一些方法,暴露给JavaScript,传递这个对象给JavaScript,JavaScript就可以调用这些方法

  1. webView = findViewById(R.id.wbView);
  2. //支持JavaScript
  3. webView.getSettings().setJavaScriptEnabled(true);
  4. //加载本地HTML文件
  5. webView.loadUrl("file:///android_asset/test.html");
  6. //传递对象给JavaScript
  7. webView.addJavascriptInterface(MainActivity.this, "activity");
  8. /**
  9. * 暴露给JavaScript的方法
  10. *
  11. * @param msg
  12. */
  13. @JavascriptInterface
  14. public void showToast(String msg) {
  15. Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
  16. }

HTML代码,放在assets文件下的HTML

  1. <html>
  2. <head>
  3. <title>js调用android原生代码</title>
  4. <meta http-equiv="Content-Type" content="text/html;charset=gb2312">
  5. <meta id="viewport" name="viewport"
  6. content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui">
  7. </head>
  8. <body>
  9. <br/>
  10. <li><a onclick="activity.showToast('你好呀');">点击调用Toast</a></li>
  11. <br/>
  12. </body>
  13. </html>
调用方法返回数据

返回数据肯定和刚才那个是一样的,只是方法有返回值而已,只是测试的时候,因为我们不怎么会JavaScript呀,不知道HTML怎么使用这个JavaScript返回来的值,所以有些难搞;我试了两种方法证明的确拿到这个值了,其实怎么用我感觉也不用我们关心,我是找到一个类似Toast的JavaScript方法,用它展示获取到的返回值;

  1. /**
  2. * 返回信息给JavaScript
  3. *
  4. * @return
  5. */
  6. @JavascriptInterface
  7. public String getMsg() {
  8. return "Hello from Android";
  9. }

同样还是暴露一个方法给JavaScript,然后第一种方法是在HTML中获取到数据,然后调用HTML中的JavaScript显示

  1. <!--一个类似Toast的JavaScript方法,不用管怎么搞的-->
  2. <script>
  3. function toast(msg,duration){
  4. duration=isNaN(duration)?3000:duration;
  5. var m = document.createElement('div');
  6. m.innerHTML = msg;
  7. m.style.cssText="width: 60%;min-width: 150px;opacity: 0.7;height: 30px;color: rgb(255, 255, 255);line-height: 30px;text-align: center;border-radius: 5px;position: fixed;top: 40%;left: 20%;z-index: 999999;background: rgb(0, 0, 0);font-size: 12px;";
  8. document.body.appendChild(m);
  9. setTimeout(function() {
  10. var d = 0.5;
  11. m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
  12. m.style.opacity = '0';
  13. setTimeout(function() { document.body.removeChild(m) }, d * 1000);
  14. }, duration);
  15. }
  16. </script>
  17. <!--调用Android的getMsg()方法获取返回值,方法前面这个window好像可以加可以不加-->
  18. <li><a onclick="toast(window.activity.getMsg(),100)">点击获取MSG</a></li>

第二种就是直接在JavaScript中获取

  1. <!--一个类似Toast的JavaScript方法,我小改了一下,调用了Android的getMsg()方法-->
  2. <script>
  3. function toast(duration){
  4. <!--在这里获取返回值-->
  5. var msg=window.activity.getMsg();
  6. duration=isNaN(duration)?3000:duration;
  7. var m = document.createElement('div');
  8. m.innerHTML = msg;
  9. m.style.cssText="width: 60%;min-width: 150px;opacity: 0.7;height: 30px;color: rgb(255, 255, 255);line-height: 30px;text-align: center;border-radius: 5px;position: fixed;top: 40%;left: 20%;z-index: 999999;background: rgb(0, 0, 0);font-size: 12px;";
  10. document.body.appendChild(m);
  11. setTimeout(function() {
  12. var d = 0.5;
  13. m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
  14. m.style.opacity = '0';
  15. setTimeout(function() { document.body.removeChild(m) }, d * 1000);
  16. }, duration);
  17. }
  18. </script>
  19. <!--直接调用JavaScript方法就完事儿了-->
  20. <li><a onclick="toast(100)">点击获取MSG</a></li>

拦截URL

JavaScript简单的发送一些消息

  1. <script>
  2. function callAndroid(){
  3. <!--约定的url协议为:js://webview?name=Tyhj-->
  4. document.location = "js://webview?name=Tyhj";
  5. }
  6. </script>
  7. <li><a onclick="callAndroid()">点击测试拦截URL</a></li>

Android通过webView.setWebViewClient()重写shouldOverrideUrlLoading方法,拦截到URL,对协议进行解析,获取信息,从而响应JavaScript发送的数据

  1. public static final String URL_SCHEME = "js";
  2. public static final String URL_AUTHORITY = "webview";
  3. webView.setWebViewClient(new WebViewClient() {
  4. @Override
  5. public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
  6. Uri uri = request.getUrl();
  7. //判断协议,约定的url协议为:js://webview?name=Tyhj
  8. if (URL_SCHEME.equals(uri.getScheme()) && URL_AUTHORITY.equals(uri.getAuthority())) {
  9. String name = uri.getQueryParameter("name");
  10. Toast.makeText(MainActivity.this, "JavaScript通过拦截调用Android代码" + name, Toast.LENGTH_SHORT).show();
  11. return true;
  12. }
  13. return super.shouldOverrideUrlLoading(view, request);
  14. }
  15. });

拦截JS对话框

正常网页是会弹出弹窗让我们点击操作或者输入操作返回一些值;现在我们监听到之后返回true而不是默认的方法,这时候就是拦截了这些对话框,网页就不会弹出来,但是也需要我们做响应的处理,并且返回值给JavaScript;

JavaScript简单的弹出对话窗

  1. <li><a onclick="alert('alert测试')">点击测alert</a></li>
  2. <li><a onclick="showPrompt()">点击测prompt</a></li>
  3. <li><a onclick="showConfirm()">点击测confirm</a></li>
  4. <script>
  5. function showPrompt() {
  6. var person = prompt("Please enter your name", "Harry Potter");
  7. if (person != null) {
  8. document.getElementById("demo").innerHTML =
  9. "Hello " + person + "! How are you today?";
  10. }
  11. }
  12. </script>
  13. <script>
  14. function showConfirm(){
  15. var r=confirm("Press a button!");
  16. if(r==true){
  17. document.getElementById("demo").innerHTML ="you choose yes";
  18. }else{
  19. document.getElementById("demo").innerHTML ="you choose no";
  20. }
  21. }
  22. </script>

Android对这些方法进行拦截,并做出数据的展示,返回响应的值

  1. webView.setWebChromeClient(new WebChromeClient() {
  2. @Override
  3. public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
  4. Toast.makeText(MainActivity.this, "onJsAlert:" + message, Toast.LENGTH_SHORT).show();
  5. result.confirm();
  6. return true;
  7. }
  8. @Override
  9. public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
  10. Toast.makeText(MainActivity.this, "onJsConfirm:" + message, Toast.LENGTH_SHORT).show();
  11. result.cancel();
  12. return true;
  13. }
  14. @Override
  15. public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
  16. Toast.makeText(MainActivity.this, "onJsPrompt:" + message, Toast.LENGTH_SHORT).show();
  17. result.confirm("Tyhj");
  18. return true;
  19. }
  20. });

Android调用JavaScript方法

  • webView的loadUrl()方法,无法获取返回值
  • webView的evaluateJavascript()方法,可以获取返回值

调用loadUrl方法

调用JavaScript的方法比较简单,直接调用就可以了,遇到一个问题是我在加载网页后直接调用JavaScript的方法发现一直不行,是网页还没有加载完成所以没法调用,监听一下网页加载完成再调用就好了

  1. webView.loadUrl("file:///android_asset/test.html");
  2. webView.setWebViewClient(new WebViewClient() {
  3. @Override
  4. public void onPageFinished(WebView view, String url) {
  5. String msg = "呵呵呵";
  6. int duration = 1000;
  7. //调用JavaScript的toast()方法
  8. webView.loadUrl("javascript:toast('" + msg + "','" + duration + "')");
  9. }
  10. });

调用evaluateJavascript方法获取返回值

这个方法适用于Android4.4版本以上,以下版本其实也有一些应对的办法,可以自己找找

  1. webView.evaluateJavascript("javascript:getMsg()", new ValueCallback<String>() {
  2. @Override
  3. public void onReceiveValue(String value) {
  4. Toast.makeText(MainActivity.this,value,Toast.LENGTH_SHORT).show();
  5. }
  6. });

其实可以看出来,基本上只支持传递字符串而已,但是支持字符串,就意味着支持基本类型(自己强转一下)和Json数据了

Android注入js代码

有时候网页并不是我们定制的,里面没有我们需要的JavaScript代码,我们可以注入JavaScript代码进去;比如网页上的图片,我们可以提供查看和保存图片的功能,就需要注入JavaScript

  1. /**
  2. * 这段js函数的功能是,遍历所有的img节点,并添加onclick函数,
  3. * 函数的功能是在图片点击的时候调用本地java接口imageClick()并传递url过去
  4. */
  5. public static final String GET_IMAGE_URL = "javascript:(function(){" +
  6. "var objs = document.getElementsByTagName(\"img\");" +
  7. "for(var i=0;i<objs.length;i++)" +
  8. "{" +
  9. "objs[i].onclick=function(){window.activity.imageClick(this.getAttribute(\"src\"));}" +
  10. "}" +
  11. "})()";
  12. webView.loadUrl("file:///android_asset/test.html");
  13. //传递对象给JavaScript
  14. webView.addJavascriptInterface(MainActivity.this, "activity");
  15. //在这里注入JavaScript
  16. webView.loadUrl(GET_IMAGE_URL);
  17. /**
  18. * 点击图片时候调用
  19. *
  20. * @param imgUrl
  21. */
  22. @JavascriptInterface
  23. public void imageClick(String imgUrl) {
  24. //获取到图片的URL,可以在此操作图片
  25. Toast.makeText(MainActivity.this, imgUrl, Toast.LENGTH_SHORT).show();
  26. }

WebView长按事件

网页中相应Android的长按事件也是经常用到的,比如刚才的点击一般是查看图片,长按保存图片或者其他操作;其实就是设置WebView的长按事件,然后通过WebView的getHitTestResult()的函数可以获取点击页面元素的类型,然后,我们再根据类型进行相应的处理,还是以图片为例

  1. webView.setOnLongClickListener(new View.OnLongClickListener() {
  2. @Override
  3. public boolean onLongClick(View v) {
  4. final WebView.HitTestResult hitTestResult = webView.getHitTestResult();
  5. // 如果是图片类型或者是带有图片链接的类型
  6. if (hitTestResult.getType() == WebView.HitTestResult.IMAGE_TYPE ||
  7. hitTestResult.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
  8. String picUrl = hitTestResult.getExtra();
  9. Toast.makeText(MainActivity.this, "长按获取到图片地址:" + picUrl, Toast.LENGTH_SHORT).show();
  10. return true;
  11. }
  12. return false;
  13. }
  14. });

监听图片选择

这个是我随意加的,因为我们都可以互相调用了,那做什么都应该是没问题的,只是看见webView有一个setWebChromeClient方法里面可以监听到图片选择,可以响应一下;就是监听到图片选择以后,调用系统方法选择图片,返回给JavaScript,也比较简单

  1. ValueCallback<Uri[]> mUploadMessageArray;
  2. int RESULT_CODE = 0;
  3. webView.setWebChromeClient(new WebChromeClient() {
  4. @Override
  5. public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
  6. mUploadMessageArray = filePathCallback;
  7. //选择图片
  8. Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
  9. chooserIntent.setType("image/*");
  10. startActivityForResult(chooserIntent, RESULT_CODE);
  11. return true;
  12. }
  13. });
  14. @Override
  15. protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  16. if (requestCode == RESULT_CODE) {
  17. if (mUploadMessageArray != null) {
  18. Uri result = (data == null || resultCode != RESULT_OK ? null : data.getData());
  19. //这里返回给JavaScript
  20. mUploadMessageArray.onReceiveValue(new Uri[]{result});
  21. mUploadMessageArray = null;
  22. }
  23. }
  24. }

然后HTML里面就是简单的选择图片,好像都没有涉及到JavaScript

  1. <p>
  2. <input type="file" value="打开文件" />
  3. </p>

项目源码:https://github.com/tyhjh/WebViewH.git

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注