Android混合开发之WebViewJavascriptBridge实现JS与java安全交互
前言:
为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与java互相调用的需求。它就是WebViewJavascriptBridge。
学习动机:
先看下之前的解决办法:Android混合开发之WebView与Javascript交互
最近棒棒安全的一个市场推广来我们公司推广他们的产品,当时也没太引起我的注意,后来这个市场推广人员把我们的app的进行了他们的安全验证,然后发给我一份检测报告,关于WebView的检测内容大致如下:

其实目前公司采用H5的业务都是相对不是很重要的一些业务,而且安全性要求相对比较低,不过作为技术负责人的我,觉得现在很有必要尽快寻找一个相对安全的方式来解决这个问题,算是未雨绸缪吧。经过搜过资料寻找的解决办法就是使用WebViewJavascriptBridge来实现Js与Java的互相调用。
WebViewJavascriptBridge介绍:
WebViewJavascriptBridge是WebView和Js交互通信的桥梁,用作者的话来说就是实现java和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得开发者更方便的让js和native灵活交互,使我们的开发更加灵活和安全。
目前实现JSBridge的开源框架很多,这里采用的hi大头鬼hi写的开源框架:https://github.com/lzyzsd/JsBridge
WebViewJavascriptBridge使用方式:
1.)添加配置信息
project的build.gradle中添加如下配置
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
在module的build.pradle中添加如下配置
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
2.)用BridgeWebView替换WebView
<com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/test_bridge_webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
3.)Js调用Java方法并传递数据
可以通过registerHandler()用来注册一个java函数,来实现js回调的handler
//必须和js同名函数,注册具体执行函数,类似java实现类。
//第一参数是订阅的java本地函数名字 第二个参数是回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)
mBridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() { @Override
public void handler(String data, CallBackFunction function) {
Log.e(TAG, "指定Handler接收来自web的数据:" + data);
function.onCallBack("指定Handler收到Web发来的数据,回传数据给你");
}
});
Js调用指定函数并传递参数
function testClick1() {
//调用本地java方法
//第一个参数是 调用java的函数名字 第二个参数是要传递的数据 第三个参数js在被回调后具体执行方法,responseData为java层回传数据
var data='发送消息给java代码指定接收';
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
,data
, function(responseData) {
bridgeLog('来自Java的回传数据: ' + responseData);
}
);
}
也可以mBridgeWebView.setDefaultHandler()设置DefaultHandler,这样可以接收Js通过window.WebViewJavascriptBridge通过send的所有数据
mBridgeWebView.setDefaultHandler(new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Log.e(TAG, "DefaultHandler接收全部来自web的数据:"+data);
function.onCallBack("DefaultHandler收到Web发来的数据,回传数据给你");
}
});
js实现向java发送数据
function testClick() {
//发送消息给java代码
var data = '发送消息给java代码全局接收';
window.WebViewJavascriptBridge.send(
data
, function(responseData) {
bridgeLog('来自Java的回传数据: ' +responseData);
}
);
}
4.)Java调用Js方法并传递参数
//注册事件监听
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
callback(WebViewJavascriptBridge)
},
false
);
}
}
在使用WebViewJavaScriptBridge的时候需要首先判断一下WebViewJavaScriptBridge是否存在,如果不存在需要通过添加监听'WebViewJavascriptBridgeReady'来监听
//注册回调函数,第一次连接时调用 初始化函数
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
bridgeLog('默认接收收到来自Java数据: ' + message);
var responseData = '默认接收收到来自Java的数据,回传数据给你';
responseCallback(responseData);
}); bridge.registerHandler("functionInJs", function(data, responseCallback) {
bridgeLog('指定接收收到来自Java数据: ' + data);
var responseData = '指定接收收到来自Java的数据,回传数据给你';
responseCallback(responseData);
});
})
通过上面的链接WebViewJavascriptBridge可以得到一个可用WebViewJavascriptBridge,可以通过init方法来设置一个默认接收所以java发来的数据的回调,也可以通过registerHandler设置指定接收方法。
java发送数据给Js默认接收
mBridgeWebView.send("发送数据给web默认接收",new CallBackFunction(){
@Override
public void onCallBack(String data) {
Log.e(TAG, "来自web的回传数据:" + data);
}
});
java发送数据给Js指定方法接收
mBridgeWebView.callHandler("functionInJs","发送数据给web指定接收",new CallBackFunction(){
@Override
public void onCallBack(String data) {
Log.e(TAG, "来自web的回传数据:" + data);
}
});
5.)整个示例
为了方便学习,贴出整个示例
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG=MainActivity.class.getSimpleName();
private BridgeWebView mBridgeWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
mBridgeWebView= (BridgeWebView) findViewById( R.id.test_bridge_webView);
mBridgeWebView.loadUrl("file:///android_asset/wx.html");
mBridgeWebView.setDefaultHandler(new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Log.e(TAG, "DefaultHandler接收全部来自web的数据:"+data);
function.onCallBack("DefaultHandler收到Web发来的数据,回传数据给你");
}
});
//必须和js同名函数,注册具体执行函数,类似java实现类。
//第一参数是订阅的java本地函数名字 第二个参数是回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)
mBridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Log.e(TAG, "指定Handler接收来自web的数据:" + data);
function.onCallBack("指定Handler收到Web发来的数据,回传数据给你");
}
});
findViewById(R.id.to_web_default).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mBridgeWebView.send("发送数据给web默认接收",new CallBackFunction(){
@Override
public void onCallBack(String data) {
Log.e(TAG, "来自web的回传数据:" + data);
}
});
}
});
findViewById(R.id.to_web).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mBridgeWebView.callHandler("functionInJs","发送数据给web指定接收",new CallBackFunction(){
@Override
public void onCallBack(String data) {
Log.e(TAG, "来自web的回传数据:" + data);
}
});
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.whoislcj.jsbridge.MainActivity"> <com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/test_bridge_webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/to_web_default"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:text="默认传递数据给Web"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/to_web"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:text="指定传递数据给Web"
android:layout_height="wrap_content"/>
</LinearLayout>
wx.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<script > function testClick() {
//发送消息给java代码
var data = '发送消息给java代码全局接收';
//第一个参数要发送的数据 第二个参数js在被回调后具体执行方法,responseData为java层回传数据
window.WebViewJavascriptBridge.send(
data
, function(responseData) {
bridgeLog('来自Java的回传数据: ' +responseData);
}
);
} function testClick1() {
//调用本地java方法
//第一个参数是 调用java的函数名字 第二个参数是要传递的数据 第三个参数js在被回调后具体执行方法,responseData为java层回传数据
var data='发送消息给java代码指定接收';
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
,data
, function(responseData) {
bridgeLog('来自Java的回传数据: ' + responseData);
}
);
} function bridgeLog(logContent) {
document.getElementById("log_msg").innerHTML = logContent;
} //注册事件监听
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
callback(WebViewJavascriptBridge)
},
false
);
}
}
//注册回调函数,第一次连接时调用 初始化函数
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
bridgeLog('默认接收收到来自Java数据: ' + message);
var responseData = '默认接收收到来自Java的数据,回传数据给你';
responseCallback(responseData);
}); bridge.registerHandler("functionInJs", function(data, responseCallback) {
bridgeLog('指定接收收到来自Java数据: ' + data);
var responseData = '指定接收收到来自Java的数据,回传数据给你';
responseCallback(responseData);
});
})
</script> </head>
<body>
<p>WebViewJsBridge</p>
<div>
<button onClick="testClick()">发送数据给默认Handler接收</button>
</div>
<br/>
<div>
<button onClick="testClick1()">发送数据给指定Handler接收</button>
</div>
<br/>
<div id="log_msg">调用打印信息</div>
</body>
</html>
总结:
这里仅仅是先找到了一种安全的调用方式,并没有进行真正的商用验证,接下来会对这个框架进一步了解,然后推广使用。
Android混合开发之WebViewJavascriptBridge实现JS与java安全交互的更多相关文章
- Android混合开发之WebView与Javascript交互
前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...
- Android混合开发之WebView使用总结
前言: 今天修改项目中一个有关WebView使用的bug,激起了我总结WebView的动机,今天抽空做个总结. 混合开发相关博客: Android混合开发之WebView使用总结 Android混合开 ...
- Android 利用WebViewJavascriptBridge 实现js和java的交互(一)
此文出自:http://blog.csdn.net/sk719887916/article/details/47189607,skay 按安卓开发目前现状来说,开发者大部分时间还是花在UI的屏幕适配上 ...
- Android JNI开发之C/C++层调用JAVA
一.从C/C++层调用JAVA层代码(无参数调用) //在c代码里面调用java代码里面的方法 // java 反射 // 1 . 找到java代码的 class文件 // jclass (*Find ...
- Android安全开发之WebView中的地雷
Android安全开发之WebView中的地雷 0X01 About WebView 在Android开发中,经常会使用WebView来实现WEB页面的展示,在Activiry中启动自己的浏览器,或者 ...
- Android安全开发之ZIP文件目录遍历
1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在“../”的字符串,攻击者可以利用多个“../”在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接s ...
- Android驱动开发之Hello实例
Android驱动开发之Hello实例: 驱动部分 modified: kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_defconf ...
- android软件开发之webView.addJavascriptInterface循环渐进【二】
本篇文章由:http://www.sollyu.com/android-software-development-webview-addjavascriptinterface-cycle-of-gra ...
- android软件开发之webView.addJavascriptInterface循环渐进【一】
本篇文章由:http://www.sollyu.com/android-software-development-webview-addjavascriptinterface-cycle-of-gra ...
随机推荐
- SQL Server中的高可用性(2)----文件与文件组
在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...
- 闲来无聊,研究一下Web服务器 的源程序
web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...
- [Spring]IoC容器之进击的注解
先啰嗦两句: 第一次在博客园使用markdown编辑,感觉渲染样式差强人意,还是github的样式比较顺眼. 概述 Spring2.5 引入了注解. 于是,一个问题产生了:使用注解方式注入 JavaB ...
- ABP文档 - SignalR 集成
文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用 ...
- kafka学习笔记:知识点整理
一.为什么需要消息系统 1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险. ...
- javascript中的继承与深度拷贝
前言 本篇适合前端新人,下面开始...... 对于前端新手来说(比如博主),每当对js的对象做操作时,都是一种痛苦,原因就是在于对象的赋值是引用的传递,并非值的传递,虽然看上去后者赋值给了前者,他们就 ...
- Coroutine in Java - Quasar Fiber实现--转载
转自 https://segmentfault.com/a/1190000006079389?from=groupmessage&isappinstalled=0 简介 说到协程(Corout ...
- windows环境redis主从安装部署
准备工作 下载windows环境redis,我下载的是2.4.5,解压,拷贝一主(master)两从(slaveof).主机端口使用6379,两从的端口分别为6380和6381, 我本地索性用6379 ...
- [干货来袭]MSSQL Server on Linux预览版安装教程(先帮大家踩坑)
前言 昨天晚上微软爸爸开了全国开发者大会,会上的内容,我就不多说了,园子里面很多.. 我们唐总裁在今年曾今透漏过SQL Server love Linux,果不其然,这次开发者大会上就推出了MSSQL ...
- linux服务器开发一 基础
注:本文仅限交流使用,请务用于商业用途,否则后果自负! Linux 1.Linux介绍 Linux是类Unix计算机操作系统的统称. Linux操作系统的内核的名字也是“Linux”. Linux这个 ...