Android 利用WebViewJavascriptBridge 实现js和java的交互(一)
此文出自:http://blog.csdn.net/sk719887916/article/details/47189607,skay
按安卓开发目前现状来说,开发者大部分时间还是花在UI的屏幕适配上,使用原生控件开发成本已不是那么理想,鉴于很多项目和ios基于一致的ui界面,至使安卓UI开发成本花费更大的代价,因此目前结合Html5和原生控件是解决UI适配的一种很好的选择,处于APP性能也会用java和native层进行结合。不管是哪种结合,其实原理都差不多,只要按照它的协议来,是很容易的,今天我们仅对于Html和Java层结合,学习下WebViewJavascriptBridge。
已经熟悉了jsbridge的朋友直接移步:
《Android基于JsBridge封装的高效带加载进度的WebView》:http://blog.csdn.net/sk719887916/article/details/52402470
一 什么是webViewjavascripBridge?
WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,用作者的话来说就是实现java(ios为oc)和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得我们的开发更加灵活和安全。
二 为什么要用webViewjavascripBridge?
mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction");
4.4之后调用需要在调用方法加入加入@JavascriptInterface注解,如果代码无此申明,那么也就无法使得js生效,也就是说这样就可以避免恶意网页利用js对安卓客户端的窃取和攻击。
但是即使这样,我们很多时候需要在js记载本地代码的时候,要做一些判断和限制,或者有可能也会做些过滤和对用户友好提示,因此JavascriptInterface也就无法满足我们的需求了,特此有大神就写出了WebViewJavascriptBridge框架。
三 怎么使用webViewjavascripBridge
1 将jsBridge.jar引入到我们的工程
repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
2 WebView包需使用以上包的webView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- button 演示Java调用web -->
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:text="@string/button_name"
android:layout_height="48dp"
/>
<!-- webview 演示web调用Java -->
<com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.github.lzyzsd.jsbridge.BridgeWebView>
</LinearLayout>
3 Java代码
public class MainActivity extends Activity implements OnClickListener {
private final String TAG = "MainActivity";
BridgeWebView webView;
Button button;
int RESULT_CODE = 0;
ValueCallback<Uri> mUploadMessage;
static class Location {
String address;
}
static class User {
String name;
Location location;
String testStr;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (BridgeWebView) findViewById(R.id.webView);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
webView.setDefaultHandler(new DefaultHandler());
webView.setWebChromeClient(new WebChromeClient() {
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {
this.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {
this.openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
pickFile();
}
});
//加载本地网页
//webView.loadUrl("file:///android_asset/demo.html");
//加载服务器网页
webView.loadUrl("https://www.baidu.com");
//必须和js同名函数,注册具体执行函数,类似java实现类。
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str ="这是html返回给java的数据:" + data;
// 例如你可以对原始数据进行处理
makeText(MainActivity.this, str, LENGTH_SHORT).show();
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
}
});
//模拟用户获取本地位置
User user = new User();
Location location = new Location();
location.address = "上海";
user.location = location;
user.name = "Bruce";
webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show();
}
});
webView.send("hello");
}
public void pickFile() {
Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooserIntent.setType("image/*");
startActivityForResult(chooserIntent, RESULT_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == RESULT_CODE) {
if (null == mUploadMessage){
return;
}
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
@Override
public void onClick(View v) {
if (button.equals(v)) {
webView.callHandler("functionInJs", "data from Java", new CallBackFunction() {
@Override
public void onCallBack(String data) {
// TODO Auto-generated method stub
Log.i(TAG, "reponse data from js " + data);
}
});
}
}
}
2 自定webVIewClient
class MyWebViewClient extends BridgeWebViewClient{
public MyWebViewClient(BridgeWebView webView) {
super(webView);
}
}
将自定义webViewClient设置到webview上
mWebView.setWebViewClient(new MyWebViewClient(mWebView));
上面句话很关键:
通过实例化webView,用法和安卓原生的view没多大区别,设置WebChromClient, 设置加载的html(同样支持网络和本地文件),接着我们需要给web注册和html端约定好的js方法名。代码列举的submitFromweb和js的执行的方法名一致,玩过NDK的JNI调用的朋友也知道必须和c代码之间有个约定,其实js桥和jni有点类似,
//必须和js函数同名,注册具体执行回调函数,类似java实现类。
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str ="这是html返回给java的数据:" + data;
// 例如你可以对原始数据进行处理
makeText(MainActivity.this, str, LENGTH_SHORT).show();
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
}
});
如果是webview刚开始就执行一段Java代码 ,可以通过webView.CallHandler()来实现 。当然我们注册的方法也要和js里面的方法名一致。
webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show();
}
});
3 Html和js实现
html代码如下,效果图
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<title>
js调用java
</title>
</head>
<body>
<p>
<xmp id="show">
</xmp>
</p>
<p>
<xmp id="init">
</xmp>
</p>
<p>
<input type="text" id="text1" value="用户名(username)" />
</p>
<p>
<input type="text" id="text2" value="password" />
</p>
<p>
<input type="button" id="enter" value="发消息给Native" onclick="testClick();"
/>
</p>
<p>
<input type="button" id="enter1" value="调用Native方法" onclick="testClick1();"
/>
</p>
<p>
<input type="button" id="enter2" value="显示html" onclick="testDiv();" />
</p>
<p>
<input type="file" value="打开文件" />
</p>
</body>
</html>
js代码
<script>
function testDiv() {
document.getElementById("show").innerHTML = document.getElementsByTagName("html")[0].innerHTML;
}
function testClick() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
//发送消息给java代码
var data = "name=" + str1 + ",pass=" + str2;
window.WebViewJavascriptBridge.send(
data
, function(responseData) {
document.getElementById("show").innerHTML = "repsonseData from java, data = " +responseData
}
);
}
function testClick1() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
//调用本地java方法
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': str1}
, function(responseData) {
document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
}
);
}
function bridgeLog(logContent) {
document.getElementById("show").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) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': 'Wee!'
};
console.log('JS responding with', data);
responseCallback(data);
});
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
});
})
</script>
这段代码不难理解,我们对上面的id为enter的Button注册了一个点击事件,点击后执行以下testClick()方法,依次类推,其他Button注册事件相同,
当点击“发消息给Native”的按钮时,Js通过webWiew的jsBridage.send()发送一条数据给java层(密码和用户名),同时在此用function()来执行应java层回调函数的。此demo中是把java返回的数据插入到"show"的div里面去。
testClick1():此方法中调用callHandler来调用Java代码的submitFromweb同名函数,可以结合上面的Activty的代码理解下,此函数调用我们已在java注册实现好的
//必须和js同名函数,注册具体执行函数,类似java实现类。
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str ="这是html返回给java的数据:" + data;
// 例如你可以对原始数据进行处理
makeText(MainActivity.this, str, LENGTH_SHORT).show();
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
}
});
java注册Js函数如上面列子 ,那么在js中注册方法来注册呢,
在js中我们同样可以直接注册一个回调函数,通过 bridge.registerHandler()来注册,接着调用 responseCallback(responseData)来返回数据给java代码的同名函数。f
也可以直接调用init()来指定网页首次加载上面注册java代码。
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': 'Wee!'
};
console.log('JS responding with', data);
responseCallback(data);
});
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
});
})
四 总结
通过以上的API介绍,代码示例,不难发现此框架的优雅和简便,对js和java双方来说,如果Html中的js需要调用java代码,而java代码没做任何实现,那么js中方法也是无效的,反之java代码注册的函数,没在js里去回调实现,那么Java层也是无法获取js中数据的,由此可见,此通信是双方支持的,必须由双方来约定,这样就避免了Android之前存在的js注入漏洞,也很大的提高了安全性,也可以保证我们的网页数据不被第三方的APP获取,具体来讲,列如我们的项目某一个web的h5界面,被系统浏览器或者其他第三方App的恶意加载,那么它的java代码想调用你的js函数,实现需要你的H5的Js先注册,不然跟本无法调用你的h5信息。这样保证了这个html数据的安全性,,第三方的浏览器可以加载预览你的网页,但是第三方java无法和你的的h5中的js交互通信的。同样加载我们自己的APP加载第三方的网页时候,我们可以对第三方网页进行一些行为的过滤,方便保护我们手机的安全,列如第三方可以获取本机地址时我们可以提示用户授权。虽然H5并不属于插件的一种,但是借助h5我可以方便的去更新一些运营活动,和某些需要经常需要更换UI的业务功能的地方,以上只JSBridge的使用姿势,,以后再给大家解剖下JsBridge的内部实现。
Android 利用WebViewJavascriptBridge 实现js和java的交互(一)的更多相关文章
- Android混合开发之WebViewJavascriptBridge实现JS与java安全交互
前言: 为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与j ...
- android webView开发之js调用java代码示例
1.webView设置 webView.getSettings().setJavaScriptEnabled(true);//设置支持js webView.addJavascriptInterface ...
- Android的WebView通过JS调用java代码
做项目时候会遇到我们用WebView 打开一个web,希望这个web可以调用自己的一些方法,比如我们在进一个web页面,然后当我们点击web上的某个按钮时,希望能判断当前手机端是否已经登录,如果未登录 ...
- android 与html交互java调js与js调java操作
1.首先在项目下建一个assets目录(右击app->New->Folder->Assets Flolder),直接放在项目根目录下和res目录同级别(把所html,js,图片,cs ...
- Android 使用js调用Java
效果如: 主要用到一个接口类:MyObject package com.example.jsdemo; import android.content.Context; import android.s ...
- android混合开发,webview的java与js互操作
android原生应用,用webview加载应用中的网页,并且java代码与js代码可以互相操作. 这是混合开发的基石,最基本也最重要的东西,实验代码在这里. 概括说说—— java调js:调用web ...
- Android webview js 调用java方法报错"Uncaught TypeError: Object [object Object] has no method xx
webview开发,在Android4.4下js调用java方法报错"Uncaught TypeError: Object [object Object] has no method,同样的 ...
- html和java的交互,利用jsBridge开源框架
html中,js注册监听和回调 function connectWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBrid ...
- Java和Android Http连接程序:使用java.net.URL 下载服务器图片到客户端
Java和Android Http连接程序:使用java.net.URL 下载服务器图片到客户端 本博客前面博文中利用org.apache.http包中API进行Android客户端HTTP连接的例子 ...
随机推荐
- ACM 畅通工程2
Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到 ...
- Bootstrap3 表格-状态类
通过这些状态类可以为行或单元格设置颜色. .active---鼠标悬停在行或单元格上时所设置的颜色 .success--–标识成功或积极的动作 .info----标识普通的提示信息或动作 .warni ...
- Android源码解析——Toast
简介 Toast是一种向用户快速展示少量信息的视图.当它显示时,它会浮在整个应用层的上面,并且不会获取到焦点.它的设计思想是能够向用户展示些信息,但又能尽量不显得唐突.本篇我们来研读一下Toast的源 ...
- ViewPager滑动后,可移动的Imageview会回到初始化的位置
知乎看到的原文http://www.zhihu.com/question/37398770?sort=created ViewPager滑动后,可移动的Imageview会回到初始化的位置? < ...
- Spark编译及spark开发环境搭建
最近需要将生产环境的spark1.3版本升级到spark1.6(尽管spark2.0已经发布一段时间了,稳定可靠起见,还是选择了spark1.6),同时需要基于spark开发一些中间件,因此需要搭建一 ...
- Android Studio精彩案例(一)《ActionBar和 ViewPager版仿网易新闻客户端》
转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 为了能更好的分享高质量的文章,所以开设了此专栏.文章代码都以Android Studio亲测运行,读者朋友可在后面直接下载源码.该专栏 ...
- Web自动化框架LazyUI使用手册(3)--单个xpath抓取插件详解(selenium元素抓取,有此插件,便再无所求!)
概述 前面的一篇博文粗略介绍了基于lazyUI的第一个demo,本文将详细描述此工具的设计和使用. 元素获取插件:LazyUI Elements Extractor,作为Chrome插件,用于抓取页面 ...
- 关于ROS学习的一些反思
距离发布上一篇ROS的博客已经过去两年了,才发现原来自己已经这么久可没有写过关于ROS的文章,想来很是惭愧.这两年时间,自己怀着程序员的梦想,研究过RTOS,探索过Linux,编写过Android应用 ...
- XMPP(一)-openfire服务端的安装和搭建
XMPP全称:可扩展通讯和表示协议 简介:可扩展通讯和表示协议 (XMPP) 可用于服务类实时通讯.表示和需求响应服务中的XML数据元流式传输.XMPP以Jabber协议为基础,而Jabber是即时通 ...
- 剑指Offer——分治算法
剑指Offer--分治算法 基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更 ...