刚学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过好多文章,都是对addJavascriptInterface和evaluateJavascript很粗暴的解释,很少具体实例代码,所以自己整理了一下,以下方案仅对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.html和index.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。