android js 获取源码,Android Webview与JS交互之DSbridge源码分析

本文介绍了如何使用DSbridge库封装Webview与JS的交互,通过一个示例展示了如何在Android端获取用户登录信息并传递给H5页面。DSbridge通过反射机制调用指定的方法,并通过注解确保安全,简化了原本繁琐的交互过程。
摘要由CSDN通过智能技术生成

自从有了Webview与JS交互,而我又使用过并且有了一定的理解,真心的体会到让开发者能在web页相关开发为所欲为。demo地址

f898c80ef761?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image.png

比如,在一个活动页面,需要用户登陆后的userId,才能领取活动页面的奖品,怎么获取呢?这个时候,你可以通过js跳转到登录页,登陆成功带着userId回到活动页,就可以进行下一步动作了,美滋滋~

上面只是个简单的例子,本章的主角是DSbridge,不过,在这之前,我们先回顾下,在没封装的时候,Webview与JS交互的实现。(我之前一直在用的方式)

/**js调用android端的方法:**/

//主要看showLog这个方法

public void initView() {

webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new TestEntity(),"test");

}

public classTestEntity {

@JavascriptInterface

public void showLog(String data) {

Log.i("android",data);

}

}

js调用showLog()方法:

function handleAndroidMethod() {

test.showLog('hhh');

}

android 调用js 的方法:

//js里面方法

function jsMethod(data) {

....方法实现

}

android这边这样调用:

webview.loadUrl('jsMethod('测试')')

很好,传统的是如上这样实现,我们回到DSbridge,DSbridge其实就是在这样的交互中封装了一下。那么在分析封装实现之前,我们来看看,DSbridge完成交互中的流程。(还是以分享的例子)

android需要处理的:

public void initView() {

webView= (DWebView) findViewById(R.id.webView);

webView.getSettings().setJavaScriptEnabled(true);

webView.setJavascriptInterface(newJsApiEntity(this));

}

public class JsApiEntity {

private Activity mActivity;

public JsApiEntity(Activity mActivity) {

this.mActivity= mActivity;

}

//for synchronous invocation 同步

@JavascriptInterface

String testSyn(JSONObject jsonObject)throwsJSONException {

return jsonObject.getString("msg") +"[syn call]";

}

//for asynchronous invocation 异步

//分享相关

@JavascriptInterface

void share(JSONObject jsonObject,CompletionHandler handler)throwsJSONException {

EventBus.getDefault().post(jsonObject,"SHOW_SHARE_DIALOG");

handler.complete("对应后台里面的flag");//回调数据给H5

}

}

js那边调用:

var title = "我是标题";

var content = "我是内容";

var url = "落地页的链接";

function share() {

dsBridge.call("share", {title: title,content:content,

imageUrl: "图片链接哟",url:url}, function(flag){alert(flag);})

}

很对,上面就是使用DSbridge之后的使用详情了。其实还是挺有意思的,只要调用dsBridge.call()就可以了,参数是之前定义的方法名称(比如 share)。

DSbridge做的事情,就是在js调用的原生代码时候做了封装,每次调用都是用dsBridge.call()来处理,然后具体的就根据参数来区分了。

我们来看看他的主要源码部分 DWebView.java:

void init() {

......

super.addJavascriptInterface(new Object() {

int i = 0;

@JavascriptInterface

@Keep

public String call(String methodName, String args) {

String error = "Js bridge method called, but there is not a JavascriptInterface object, please set JavascriptInterface object first!";

if(DWebView.this.jsb == null) {

Log.e("SynWebView", error);

return "";

} else {

Class cls = DWebView.this.jsb.getClass();

try {

boolean asyn = false;

JSONObject arg = new JSONObject(args);

final String callback = "";

Method e;

try {

callback = arg.getString("_dscbstub");

arg.remove("_dscbstub");

e = cls.getDeclaredMethod(methodName, new Class[]{JSONObject.class, CompletionHandler.class});

asyn = true;

} catch (Exception var12) {

e = cls.getDeclaredMethod(methodName, new Class[]{JSONObject.class});

}

if(e == null) {

error = "ERROR! \n Not find method \"" + methodName + "\" implementation! ";

Log.e("SynWebView", error);

DWebView.this.evaluateJavascript(String.format("alert(decodeURIComponent(\"%s\"})", new Object[]{error}));

return "";

}

JavascriptInterface annotation = (JavascriptInterface)e.getAnnotation(JavascriptInterface.class);

if(annotation != null) {

e.setAccessible(true);

Object ret;

if(asyn) {

ret = e.invoke(DWebView.this.jsb, new Object[]{arg, new CompletionHandler() {

public void complete(String retValue) {

this.complete(retValue, true);

}

public void complete() {

this.complete("", true);

}

public void setProgressData(String value) {

this.complete(value, false);

}

private void complete(String retValue, boolean complete) {

try {

if(retValue == null) {

retValue = "";

}

retValue = URLEncoder.encode(retValue, "UTF-8").replaceAll("\\+", "%20");

String e = String.format("%s(decodeURIComponent(\"%s\"));", new Object[]{callback, retValue});

if(complete) {

e = e + "delete window." + callback;

}

DWebView.this.evaluateJavascript(e);

} catch (UnsupportedEncodingException var4) {

var4.printStackTrace();

}

}

}});

} else {

ret = e.invoke(DWebView.this.jsb, new Object[]{arg});

}

if(ret == null) {

ret = "";

}

return ret.toString();

}

error = "Method " + methodName + " is not invoked, since it is not declared with JavascriptInterface annotation! ";

DWebView.this.evaluateJavascript(String.format("alert(\'ERROR \\n%s\')", new Object[]{error}));

Log.e("SynWebView", error);

} catch (Exception var13) {

DWebView.this.evaluateJavascript(String.format("alert(\'ERROR! \\n调用失败:函数名或参数错误 [%s]\')", new Object[]{var13.getMessage()}));

var13.printStackTrace();

}

return "";

}

}

@JavascriptInterface

@Keep

public void returnValue(int id, String value) {

OnReturnValue handler = (OnReturnValue)DWebView.this.handlerMap.get(Integer.valueOf(id));

if(handler != null) {

handler.onValue(value);

DWebView.this.handlerMap.remove(Integer.valueOf(id));

}

}

@JavascriptInterface

@Keep

public void init() {

DWebView.this.injectJs();

}

}, "_dsbridge");

......

public void setJavascriptInterface(Object object) {

this.jsb = object;

}

}

很好,我们先看init方法(@Keep,其实就是为了不被混淆,不用在意),从

Class cls = DWebView.this.jsb.getClass()里面一开始就很明显的说出了意图,使用反射来处理,通过e = cls.getDeclaredMethod获取到this.jsb里面的方法,方法区分同步和异步,还有这个call方法是不是很眼熟?public String call(String methodName, String args) 就是js调用原生代码里面用到的,methodName就是需要调用的方法。

我们回到这个jsb ,其实就是通过setJavascriptInterface方法设置进来的,在上面例子里面其实就是我们定义的JsApiEntity对象,现在,通过反射,把需要调用的Method (e)获取到了。接下来肯定是通过注解来调用方法了,我们接着看:

JavascriptInterface annotation = (JavascriptInterface)e.getAnnotation(JavascriptInterface.class);

if(annotation != null) {'....''}

使用了@JavascriptInterface注解的,才会进入里面,里面其实就是通过e.invoke来执行js调用的方法了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值