Android WebView实现js与java交互

刚学Android用WebView来做应用

Android Studio下载: http://www.android-studio.org/

写此文时最新稳定版是2.3.3,预览版3.0.0,3.0.0支持使用Kotlin进行开发,有点坑,毕竟还不够成熟

安卓开发文档:https://developer.android.google.cn/develop/index.html

网上比较流行的js与java交互解决方案:https://github.com/lzyzsd/JsBridge

百度、Google过好多文章,都是对addJavascriptInterfaceevaluateJavascript很粗暴的解释,很少具体实例代码,所以自己整理了一下,以下方案仅对android4.4以上可用

照着安卓官方开发文档新建一个安卓工程出来不难,就不详说了,直接上代码,看注释

MainActivity.java

1package com.example.demo.mydemo; 2 3import android.os.Build; 4import android.support.v7.app.AppCompatActivity; 5import android.os.Bundle; 6import android.util.Log; 7import android.view.KeyEvent; 8import android.webkit.JavascriptInterface; 9import android.webkit.ValueCallback; 10import android.webkit.WebResourceRequest; 11import android.webkit.WebView; 12import android.webkit.WebViewClient; 13 14public class MainActivity extends AppCompatActivity { 15 WebView view; 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 view = new WebView(this); 19 super.onCreate(savedInstanceState); 20 // 注释默认视图,稍候将我们创建的WebView渲染出来 21 // setContentView(R.layout.activity_main); 22 // 开启对javascript支持,WebView默认是不支持javascript的 23 view.getSettings().setJavaScriptEnabled(true); 24 // 允许chrome浏览器进行远程调试 25 view.setWebContentsDebuggingEnabled(true); 26 // 如果不重写shouldOverrideUrlLoading这个方法,默认使用外部浏览器打开网页 27 view.setWebViewClient(new WebViewClient() { 28 @Override 29 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 30 if (Build.VERSION.SDK_INT >= 21) { 31 view.loadUrl(request.getUrl().toString()); 32 } else { 33 view.loadUrl(request.toString()); 34 } 35 return false; 36 } 37 }); 38 // 注入可在webview用js调用java方法的对象和变量Android 39 view.addJavascriptInterface(new MyJs(), "Android"); 40 // 加载首页 41 view.loadUrl("file:///android_asset/index.html"); 42 43 // 使activity显示webview的内容 44 setContentView(view); 45 } 46 47 public class MyJs { 48 // 注册给js用的方法 49 @JavascriptInterface 50 public void showToast (final String id, final String context) { 51 // 在Android Monitor的logcat可以查看这句java的输出 52 Log.i("toast", context); 53 54 // 调用js的全局方法将数据返回给js(必须用UI线程,否则app会崩溃) 55 runOnUiThread(new Runnable() { 56 @Override 57 public void run() { 58 // 返回给js的回调数据, 59 // id 用于给js找到对应的局部回调函数, 60 // context 应该是java获取到的数据,这里为了方便,直接将js传过来的数据返回 61 String data = "{id:" + id + ", result: '" + context + "'}"; 62 63 //执行js的方法(只能执行windows域下的全局方法) 64 view.evaluateJavascript("exec(" + data + ")", new ValueCallback<String>() { 65 @Override 66 public void onReceiveValue(String s) { 67 // 当exec方法执行完成,会回调这个java方法 68 // s 是exec的return值(一般很少用到) 69 Log.i("callback", s); 70 } 71 }); 72 } 73 }); 74 } 75 } 76 77 // 处理返回键 78 @Override 79 public boolean onKeyDown(int keyCode, KeyEvent event) { 80 if(keyCode==KeyEvent.KEYCODE_BACK) 81 { 82 if(view.canGoBack()) 83 { 84 view.goBack();//返回上一页面 85 return true; 86 } 87 else 88 { 89 System.exit(0);//退出程序 90 } 91 } 92 return super.onKeyDown(keyCode, event); 93 } 94} 95

在WebView里必须使用UI线程的官方原文:https://developer.android.google.cn/guide/webapps/migrating.html#Threads

If you call methods on WebView from any thread other than your app's UI thread, it can cause unexpected results.

我自己翻译:如果你使用了非UI线程的其它线程去调用WebView里的方法,将会产生不被期待的结果。

上文我说APP会崩溃是实践所得。

创建index.htmlindex.js文件,放到assets文件夹里,如果项目里没assets文件夹,可以这样创建:File > New > Folder > Assets Folder

index.html

1<html> 2 <head> 3 <meta charset="utf-8" /> 4 <title>Hello Demo</title> 5 </head> 6 <body> 7 <button id="a">A</button> 8 <script src="index.js"></script> 9 </body> 10</html>

index.js

1// 用于区别回调 2var id = 0 3// 回调池,存放局部回调 4window.pool = [] 5// 给java调用的全局方法 6window.exec = function (data) { 7 for (var i = 0; i < pool.length; i++) { 8 if (pool[i][0] == data.id) { 9 pool[i][1](data.result) 10 pool.splice(i, 1) 11 return true 12 } 13 } 14} 15// 封闭java方法的全局空间,方便给js调用 16window.orz = { 17 showToast: function (msg, callback) { 18 Android.showToast(++id, msg) 19 pool.push([id, callback]) 20 } 21} 22document.getElementById('a').onclick = function () { 23 // 经过上面的一层封装,调用原生并执行回调就很方便了 24 orz.showToast('Call', function (txt) { 25 // 这里用了console输出,需要在谷歌浏览器Remote devices对应的Inspect的Console查看,不能用alert,alert方法还没实现 26 console.log(txt) 27 }) 28 orz.showToast('Me', function (txt) { 29 console.log(txt) 30 }) 31 orz.showToast('Superman', function (txt) { 32 console.log(txt) 33 }) 34}

总结:js和java交互的原理主要是用addJavascriptInterface给WebView注入java方法,让js可以调用,然后用evaluateJavascript执行js方法将数据传回js,也可以用view.loadUrl("javascript:...")来代替evaluateJavascript

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

swap空间的增减方法

(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap

Java获得今日零时零分零秒的时间(Date型)

publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS