js和本地交互
最近项目要求用js和本地交互,所以就去看了下webview的一些api,发现只能满足一些简单的需求,而项目里面的需求是比较多的而且要用的功能也算有点复杂,所以想想去githup搜索了下,有大神已经把这些东西封装好了。基本能满足大部分需求了。接下来说下他的用法,只是用他的源码需要把WebViewJavascriptBridge.js这文件拷贝到你的assets资源文件目录下,这个类里面自己封装了一些用于消息处理的方法。看下他的项目结构在model里面就是一个user实体了,后面有用到,接着看MainActivity.java
package com.lyk.jsbridge;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.widget.Toast;
import com.github.lzyzsd.jsbridge.BridgeHandler;
import com.github.lzyzsd.jsbridge.BridgeWebView;
import com.github.lzyzsd.jsbridge.BridgeWebViewClient;
import com.github.lzyzsd.jsbridge.CallBackFunction;
import com.github.lzyzsd.jsbridge.DefaultHandler;
import com.google.gson.Gson;
import com.lyk.jsbridge.modle.User;
public class MainActivity extends AppCompatActivity {
private BridgeWebView mWebView;
ValueCallback mUploadMessage;
int RESULT_CODE = 0;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
mWebView = (BridgeWebView) findViewById(R.id.webView);
initWebView();
}
private void initWebView() {
// 设置具体WebViewClient
mWebView.setWebViewClient(new MyWebViewClient(mWebView));
// set HadlerCallBack
mWebView.setDefaultHandler(new myHadlerCallBack());
// setWebChromeClient
mWebView.setWebChromeClient(new WebChromeClient() {
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback uploadMsg, String AcceptType, String capture) {
this.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback uploadMsg, String AcceptType) {
this.openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback uploadMsg) {
mUploadMessage = uploadMsg;
pickFile();
}
});
mWebView.loadUrl("file:///android_asset/demo.html");
//必须和js函数名字一致,注册好具体执行回调函数,类似java实现类。
mWebView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str = "这是html返回给java的数据:" + data;
// 例如你可以对原始数据进行处理
str = str + ",Java经过处理后截取了一部分:" + str.substring(0, 5);
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
//回调返回给Js
function.onCallBack(str + ",Java经过处理后截取了一部分:" + str.substring(0, 5));
}
});
mWebView.registerHandler("functionOpen", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Toast.makeText(MainActivity.this, "网页在打开你的下载文件预览", Toast.LENGTH_SHORT).show();
pickFile();
}
});
//模拟用户信息 获取本地位置,用户名返回给html
User user = new User();
user.setLocation("上海");
user.setName("Bruce");
// 回调 "functionInJs"
mWebView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
Toast.makeText(MainActivity.this, "网页在获取你的位置,"+ data, Toast.LENGTH_SHORT).show();
}
});
mWebView.send("hello");
}
/**
* 自定义的WebViewClient
*/
class MyWebViewClient extends BridgeWebViewClient {
public MyWebViewClient(BridgeWebView webView) {
super(webView);
}
}
/**
* 自定义回调
*/
class myHadlerCallBack extends DefaultHandler {
@Override
public void handler(String data, CallBackFunction function) {
if(function != null){
Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
}
}
}
public void pickFile() {
Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooserIntent.setType("image/*");
startActivityForResult(chooserIntent, RESULT_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == RESULT_CODE) {
if (null == mUploadMessage) {
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
}
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="显示源代码" onclick="testDiv();"/>
p>
<p>
<input type="file" id="open" value="打开文件" onclick="onOpen();"/>
p>
body>
<script>
function onOpen() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
var data = "name=" + str1 + ",pass=" + str2;
//call native method
window.WebViewJavascriptBridge.callHandler(
'functionOpen'
, {'param': data }
, function(responseData) {
//document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData;
}
);
}
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 = {id: 1, content: "这是一个图片 test\r\nhahaha"};
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;
var data = "name=" + str1 + ",pass=" + str2;
//call native method
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': data }
, 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
);
}
}
// 第一连接时初始化bridage
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': '测试中文!'
};
console.log('JS responding with', data);
responseCallback(data);
});
// 注册一个"functionInJs",
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says 我要你的地址!";
// response层
responseCallback(responseData);
});
})
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);
});
script>
html>
首先看下js里面的代码,可以看到有button,对应俩个点击事件onclick(),onclick1(); 再看下面的代码找到这个俩个方法的实现,
//第一个实现
function testClick() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
//发送消息给java本地代码
var data = {id: 1, content: "这是一个图片 test\r\nhahaha"};
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;
var data = "name=" + str1 + ",pass=" + str2;
//call native method
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': data }
, function(responseData) {
document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
}
);
}
可以看到俩个方法里面都有
//call native method
window.WebViewJavascriptBridge.callHandler(
‘submitFromWeb’之类的写法,这里就是开始调用本地的方法,注释里面写的很清楚,注意这里的单引号的字符串就是对应java中的别名,所以只要到java本地代码中去看看,找到这别名就知道他的调用了。go~go~go!
//必须和js函数名字一致,注册好具体执行回调函数,类似java实现类。
mWebView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str = "这是html返回给java的数据:" + data;
// 例如你可以对原始数据进行处理
str = str + ",Java经过处理后截取了一部分:" + str.substring(0, 5);
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
//回调返回给Js
function.onCallBack(str + ",Java经过处理后截取了一部分:" + str.substring(0, 5));
}
});
找到了,上面的代码就是到这webview 标上’submitFromWeb’别名,注册一个回调,看注释,其中data是点击js中的button给我的数据,而就是通过这个类CallBackFunction 将本地java的数据回调给js的: function.onCallBack(str + “,Java经过处理后截取了一部分:” + str.substring(0, 5)); 一定要注意这里的别名一定要写的跟js中的一致,不然找不到的,关于原理,其实是他内部用了一个结合将这个别名和接口装载,然后js获取的时候会根据这别名找到对应的接口也就是这个BrigeHandler,然后回调里面的数据,要弄清楚里面的细节可以自己看源码,这个过程就是js调用本地的一种,再看看本地调用js的。
//模拟用户信息 获取本地位置,用户名返回给html
User user = new User();
user.setLocation("上海");
user.setName("Bruce");
// 回调 "functionInJs"
mWebView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
Toast.makeText(MainActivity.this, "网页在获取你的位置,"+ data, Toast.LENGTH_SHORT).show();
}
});
mWebView.send("hello");
然后找到js中别名部分的代码:
// 注册一个"functionInJs",
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says 我要你的地址!";
// response层
responseCallback(responseData);
});
注释非常清楚,可以看的出来,本地java将一个data user数据传过去了,而js中通过responseCallback回调给本地的数据,这就是一个回调的过程,自己看注释,还是非常容易理解掌握的~!
好了,今天,就先到这里~大家有问题可以发我邮箱([email protected])或者留言。