android调⽤js⽅法多参数,这也许是功能最强⼤的Android与
Javascript。。。
项⽬中为了减少端上开发量,通常会使⽤⼀些跨平台的解决⽅案,⽽ web 就是最简单、兼容性最强的⽅案,但 web ⼜受制于浏览器,不能直接访问系统的⼀些属性,⽽且我们也需要 web 调⽤ native 的⼀些⽅法,所以我们需要⼀套 web 和 native 双向交互的⽅案。
⽬前,Android 要实现与 web 交互有以下⼏种常⽤⽅案:
WebView addJavascriptInterface⽅法
拦截⾃定义协议链接实现数据交换
实现 prompt,console等原⽣⽅法来数据交互
⽅案⼀是官⽅推荐实现⽅案,但是在 android 4.2以下存在严重安全漏洞,⽽且和 JS 交换的数据仅仅局限于基本类型
(int,float,double,String 等),不⽀持直接 JS 函数调⽤和回调(需要通过注⼊ JS ⽀持), 案例:wendux/DSBridge-Android
⽅案⼆是兼容 iOS 的⽅案, ⼀般情况下前端需要依赖 JS ⽂件 或者 端上注⼊ JS, 调⽤⽅法固定,⽅法参数⼀般为: 函数名, 传递参数和回调函数, 传输数据长度就是 url 长度限制, 不⽀持同步回调,案例:lzyzsd / JsBridge 和
marcuswestin / WebViewJavascriptBridge
⽅案三是通过实现 Android WebView 原⽣⽅法来交互数据, 执⾏效率⾼,不限传输数据, ⽀持同步和异步传输,但也有弊端, 占据了系统函数,意味着前端使⽤这个函数就没效果了。
我们今天要介绍的库就是基于第三种⽅案的改进,基于 prompt ⽅法来实现 Android 与 Javascript 双向交互。
为什么说它功能强⼤呢?它可以实现你要想的任意 JS ⽅法,⽀持 JS 函数,对象,数组等所有基础类型的解析和回调。我们先来看个⽰例吧。如何启用javascript功能
如果要实现⼀个分享功能要怎么做呢?
public class ServiceModule extends JsModule {
@Override
public String getModuleName() {
return "service";
}
@JSBridgeMethod
public void share(String msg, final JBCallback success, final JBCallback failure) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, msg);
if (solveActivity(getContext().getPackageManager()) != null) {
getContext().ateChooser(intent, "share"));
success.apply("success");
} else {
failure.apply("failure");
}
}
JS 怎么调⽤呢?
JsBridge.service.share('分享内容',
function(){
console.log('分享成功')
},
function(){
console.log('分享失败')
}
)
不⽤传递函数名, 调⽤的⽅法名和原⽣定义的⽅法名⼀致,参数⽀持所有 JS 类型(对象,数组等), ⽀持多个回调函数,回调函数参数也可以⽀持 JS 的所有类型,⼀看就和其他妖艳xx 不⼀样
你说 JS 可能没有成功失败的回调?没关系,我们⽀持缺省参数,下⾯这样也可以哟,不过原⽣⽅法 share 收到的 JBCallback 参数就为空咯
JsBridge.service.share('分享内容');
数据还不够复杂?实际开发情况数据复杂多了。
那你看下⾯这样还⾏吗?JS 数组⾥基本包含了所有的类型
st(
[ - 1111111111111111111, 1.235, 'hello world', true,
function(args) {
alert(args)
},
{
a: 100101,
b: function() {
alert('执⾏复杂回调函数')
}
},
[1, 2, 3, 4]]);
原⽣怎么解析这种情况呢?so easy, 不就⼀个 JBArray嘛
@JSBridgeMethod
public void test(JBArray array) {
for (int i = 0; i < array.size(); i++) {
String output = "" + (i);
if ((i) != null) {
output += "##" + (i).getClass();
}
Log.d(JsBridge.TAG, output);
}
}
轻松回调 JS 数组⾥⾯的 function。JS 对象也不怕,JBMap全部搞定。
调⽤⽅法只能三个层级?我们项⽬不需要 module!!就想 st 直接调⽤。⽼铁当然没问题啦,只要继承JsStaticModule, ⾥⾯的⽅法分分钟变成静态,对象名直接调⽤。
public class ServiceModule extends JsStaticModule {
...
}
我们项⽬要求多个层级呢?
需求还真多,多个层级是需要多少层级呢?4级够了吗?不⾏再多点?那你⾃⼰按需求定制吧!!
public class ServiceModule extends JsModule {
@Override
public String getModuleName() {
return "d.e.f.g";
}
}
现在调⽤路径如下,
我不敢保证 FE 看到这个⽅法会不会拿⼑去你
JsBridge.d.(...);
iOS 要实现类似功能怎么办?
我们推荐使⽤ marcuswestin / WebViewJavascriptBridge,JsBridge 是可以兼容这个库的。怎么兼容呢?iOS 的WebViewJavascriptBridge不主要就是⼀个⽅法嘛?
responseCallback(String())
})
⼀个静态⽅法实现⾜以
怎么都觉得配合 iOS 这么强⼤的库就算杀鸡⽤⽜⼑了!
介绍完功能,接下来我们从源码层⾯来介绍下JsBridge实现原理!
在分析之前,我们先来了解⼏个相关知识点
关键⼀: WebView 怎么执⾏ JS
在 API 19+, 可以⽤系统⽅法
WebView.evaluateJavascript("alert(1)", null)
兼容所有版本的⽅案:
WebView.loadUrl("javascript:alert(1)")
有⼀点需要明确,JS的执⾏是异步进⾏的
怎么利⽤执⾏ JS 注⼊⼀个对象呢?⽐如我需要⼀个对象JsBridge, 它包含⼀个 print()⽅法, JS 的语法是这样:
var JsBridge = {
print:function(msg){
console.log(msg);
}
}
WebView 只需要执⾏这段 JS 就好了
WebView.loadUrl("javascript:var JsBridge = {print:function(msg){console.log(msg);}")
在 JS 中就可以直接⽤JsBridge.print(1)来调⽤这个⽅法了
关键⼆: onJsPrompt的参数了解
onJsPrompt 是 WebChromeClient 接⼝的⼀个回调⽅法,⽤来处理prompt⽅法的回调。
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { return true;
}
我们再看下 prompt的使⽤, 下⾯的代码⽹页中是什么效果呢?
prompt("输⼊你的名字", "张三");
prompt 第⼀个参数是标题,对应onJsPrompt⽅法的 message, 第⼆个参数是需要输⼊的内容的默认值, 对应`onJsPrompt的defaultValue, 那JsPromptResult是⽤来⼲啥的呢?我们实现同步回调就完全靠它了,⽤来设置 prompt ⽅法的返回值,假如我们端上执⾏firm("12"), 那么 prompt(xx) 的返回值就是12
基本的知识点我们都了解了,怎么串联起来上⾯的两条来实现WebView 和 JS 的双向交互呢?⾸先我们需要给 JS 提供调⽤⽅法, 如最早的JsBridge.service.share(...), ⼤概你已经知道了要⽤注⼊ JS 的⽅式。
WebView.loadUrl("javascript:alert(1)")
这样,在 JS 就可以执⾏上⾯的⽅法,接下来的问题就是我们怎么把 JS 的数据传递给 Android 呢?prompt 要上场了!
JsBridge
这样的话,在onJsPrompt的回调⾥message 就取到了 title。你就要问了,success 和 error 怎么传递给 Android 呢?这两个类型是function, Android 和 JS 的 变量并不能共享或者相互转换,所以是做不到把 JS 的变量传递到 Android 的!那怎么去解决这个问题呢?
既然不能转换,我们能不能换种思路,在分享执⾏完成的时候,我们需要执⾏ success 或者 error 来告诉 JS 分享结果,我们可以执⾏这个⽅法来实现呀,和 注⼊ JS 是⼀个套路,但是问题是对我们来说 success 和 error 是⼀个匿名⽅法(和 Java 的匿名内部类对象相似),我们并不知道怎么去调⽤它,这个容易解决呀,把这个函数赋值给⼀个已知名称的函数,然后我们在 Android 端调⽤已知名称的函数不就都解决了?我们来看下实现⽅式!
print()
Android 端实现
var JsBridge = {
print:function(msg){
console.log(msg);
}
}
这样 JS 就可以收到 success 回调了。
以上 Android 和 JS 的双向交互原理都讲明⽩了,我们来看下JsBridge这个库是怎么实现的!就是两步⾛,注⼊ JS 和 接受和处理 JS 参数并回调。
先看怎么注⼊的呢?
JsBridge 需要继承JsModule来创建模块,然后模块⾥对⽅法添加JSBridgeMethod 注解的就是需要注⼊的⽅法。Java ⽅法的参数有⼀点的要求,和 JS 的参数有⼀个映射表
Java 类型 | 映射的 JS 类型
----|------
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论