前言:有些事,明知是错的,也要去坚持,因为不甘心;有些人,明知是爱的,也要去放弃,因为没有结局;有时候,明知没路了,却还在前进,因为习惯了。

精通android的人有,精通javascript的人亦有,但同时深入掌握两门语言的人少有!

android与js交互有两种方式,第一种是通过系统提供的@JavascriptInterface注解实现,第二种就是js注入。下面来详细讲解一下二者的使用方式,原理,区别。

一、@JavascriptInterface实现

实现步骤: a.设置WebView支持js脚本 b.为提供给js调用的方法加上@JavascriptInterface注解 c.给WebView添加js接口
webView.getSettings().setJavaScriptEnabled(true);webView.addJavascriptInterface(new JSMethod(mContext), "lh");public class JSMethod {    private Context mContext;    public JSMethod(Context mContext) {        this.mContext = mContext;    }    @JavascriptInterface    public void toast(String msg) {        Toast.makeText(mContext, msg == null ? "" : msg, Toast.LENGTH_SHORT).show();    }}
js端调用android方法:
lh.toast("Hello,China!");
android端执行js方法:
webView.loadUrl("javascript:console(" + "'Hello,China!'" + ")"");

二、js注入实现

先来说说原理吧,当js调用prompt()方法时,WebChromeClient.onJsPrompt()方法会被触发,当js触发Android提供的接口方法时,将该方法的方法名称、参数类型、参数值转成json,然后通过prompt方法传递给android端,android端解析json并通过反射执行对应的方法,同时也支持执行匿名回调。 整个流程比较复杂,看图: Android WebView、js交互方式原理总结_第1张图片

为WebView绑定WebChormeClient监听,在Html加载进度25%时进行js注入(注入的js是根据android提供给js的对象类名动态生成); 动态注入的js代码如下:
javascript: (function(b) {console.log("HostApp initialization begin");var a = {queue: [],callback: function() {var d = Array.prototype.slice.call(arguments, 0);//获取该函数参数并转换为Array数组var c = d.shift();//取得数组第一个元素var e = d.shift();this.queue[c].apply(this, d);//新建一个对象 属性名称为取得的c,并将d数组作为他的值。然后将这个对象push到queue数组if(!e) {//e为空的时候,将queue数组属性名称为c的对象删除delete this.queue[c]}}};//各种赋值,最后都等于同一个函数a.alert = a.alert = a.alert = a.delayJsCallBack = a.getIMSI = a.getOsSdk = a.goBack = a.overloadMethod = a.overloadMethod = a.passJson2Java = a.passLongType = a.retBackPassJson = a.retJavaObject = a.testLossTime = a.toast = a.toast = function() {var f = Array.prototype.slice.call(arguments, 0);if(f.length < 1) {throw "HostApp call error, message:miss method name"}var e = [];//此段判断,然后赋值for(var h = 1; h < f.length; h++) {var c = f[h];var j = typeof c;e[e.length] = j;if(j == "function") {var d = a.queue.length;a.queue[d] = c;f[h] = d}}//将匿名对象{method: f.shift(),types: e,args: f}转换成json字符串并用浏览器弹出确认可输入框,然后取得输入框的值json序列化为js对象var g = JSON.parse(prompt(JSON.stringify({method: f.shift(),types: e,args: f})));if(g.code != 200) {throw "HostApp call error, code:" + g.code + ", message:" + g.result}return g.result};//获取a的属性值,然后循环Object.getOwnPropertyNames(a).forEach(function(d) {var c = a[d];//判断赋值if(typeof c === "function" && d !== "callback") {a[d] = function() {//concat 连接两个数组return c.apply(a, [d].concat(Array.prototype.slice.call(arguments, 0)))}}});b.HostApp = a;console.log("HostApp initialization end")})(window);//闭包函数默认执行,然后赋给window。这样window.b就可以执行了 b.HostApp就是执行a的内容,但是a具体处理逻辑不对外开放,避免外部污染a内部逻辑
代码不难,可以自行理解,其中回调函数被封装在了a对象里面,确保android端可以通过webview.loadUrl()执行回调。 android端回调js代码如下:
javascript:HostApp.callback(0, 0 ,"call back haha");
android提供的每一个js方法都对应一个JsCallback对象,android就可以通过JsCallback对象来生成并执行回调js的代码。

三、优缺点

a.第一种方式不安全,不添加addJavascriptInterface,甚至默认false,在低于API17的WebView上默认添加"SearchBoxJavaBridge_"到mJavaScriptObjects中。这样就有可能通过用户信任的客户端获取SD卡的数据; b.第一种方式必须要API大于等于17才能使用 c.第一种方式当有js回调函数需要android端执行时,都需要将匿名回调函数赋值给全局函数才能供android端回调,增加了js和android端通信的封装层的低效代码量;而第二种方式则是通过动态注入js的方式则非常方便。 d.第二种方式也有一定限制,比如android提供的方法必须是static修饰的,且方法第一个参数必须为WebView,不过这不影响使用。


最后,附上代码地址:点我













更多相关文章

  1. 58同城android客户端手机号码解密方法
  2. Android探索之旅 | 面向对象和Java基础
  3. android 开发使用 kotlin 进行点击事件监听和界面跳转,直接传也方
  4. Unable to start activity ComponentInfo 解决方法
  5. Android 安装apk的方法
  6. Android SQLite数据库解析并使用两种方法实现增删改查
  7. Android 读取XML的两种方法。
  8. android okgo post传数组
  9. android window.requestWindowFeature()常用方法

随机推荐

  1. Android Zxing 转换竖屏扫描且提高识别率
  2. Context引发的内存泄漏
  3. android去掉titlebar的最优解决方案
  4. 详解Android(安卓)getWidth和getMeasured
  5. Android读取properties配置文件的实例详
  6. Android使用Bugly实现APP版本更新
  7. Android又现空指针(java.lang.NullPointer
  8. ViewPager如下效果你研究过吗
  9. 使用Source Insight查看Android Framewor
  10. RxJava 的使用入门