您的位置:首页 > 移动开发 > Android开发

Android JavascriptBridge 详解(二)

2017-11-14 09:52 211 查看
repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
1
2
3
4
5
6
7
8

2 WebView需使用jsBridge的webView
<com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
1
2
3
4
5


JS和Native交互

JS是基于订阅和回调来实现Js和native交互的,我们需要在java中订阅,然后Js中回调,反之也可以。

3.1 Java

registerHandler()用来注册一个java函数,来实现js回调的handler,
第一个:订阅的方法名

第二个: 回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)
//必须和js同名函数,注册具体执行函数,类似java实现类
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
function.onCallBack( data + “java”);
}
});
1
2
3
4
5
6
7
8

3.2 JS

Js代码需要用window.WebViewJavascriptBridge.callHandler同步回调java层注册的同名函数,这和java和c库的jni调用如出一辙,方法名必须和Java层保持一致
第一参数:方法名
第二个:js调用native的请求参数

第三个:js在被回调后具体执行方法,responseData为java层回传jsonStr.
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': requsetData }
, function(responseData) {
// do somrthing
}
);
1
2
3
4
5
6
7
8


案列实践

* Activity*

初始化WebView,设置必要的参数。
mWebView = (BridgeWebView) findViewById(R.id.webView);
// 设置具体WebViewClient
mWebView.setWebViewClient(new MyWebViewClient(mWebView));
// set HadlerCallBack
mWebView.setDefaultHandler(new myHadlerCallBack());
// setWebChromeClient
mWebView.setWebChromeClient(new WebChromeClient());
1
2
3
4
5
6
7
8

需要自定义HandlerCallBack和WebViewClent;
/**
* 自定义的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();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

加载网页 支持本地和远程
mWebView.loadUrl("file:///android_asset/demo.html");
1
2


1 java调用js函数

订阅一个叫submitFromWeb 的方法名 并会写回调函数
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);
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

js同样需要java注册订阅的同名函数
//call native method
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': data }
, function(responseData) {
document.getElementById("show").innerHTML = "send get responseData from java,       data = " + responseData
}
);
1
2
3
4
5
6
7
8
9


2 JS调用Java代码

反之js调用java代码

Js 订阅一个叫functionInJs的方法
// 注册一个"functionInJs",
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says  我要你的地址!";
// response java层
responseCallback(responseData);
});
1
2
3
4
5
6
7
8

Java代码响应functionInJs 函数
// 回调 "functionInJs"
mWebView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {

// to do somthing

}
});
1
2
3
4
5
6
7
8
9
10


3 注意事项

无论怎样形式的交互,Js 必须要初始化jsBridge
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': '测试中文!'
};
console.log('JS responding with', data);
responseCallback(data);
});
1
2
3
4
5
6
7
8
9
效果图:




代码展示

1. Activty

public class MainActivity extends AppCompatActivity {
private BridgeWebView mWebView;

ValueCallback<Uri> 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<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();
}
});

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();

}
});
}

/**
* 自定义的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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139



通过实例化webView,用法和安卓原生的view没多大区别,设置WebChromClient, 设置加载的html(同样支持网络和本地文件),接着我们需要给web注册和html端约定好的js方法名。代码列举的submitFromweb和js的执行的方法名一致,玩过NDK的JNI调用的朋友也知道必须和c代码之间有个约定,其实js桥和jni有点类似

2 js代码
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: "这是一个图片 <img src=\"a.png\"/> 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);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

这段代码不难理解,我们对上面的id为enter的Button注册了一个点击事件,点击后执行以下testClick()方法,依次类推,其他Button注册事件相同,当点击“发消息给Native”的按钮时,Js通过webWiew的jsBridage.send()发送一条数据给java层(密码和用户名),同时执行function()来执行应java层回调函数的。此demo中是把java返回的数据插入到ID为”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));
}

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

3. H5



这里so ez ! 你不必care

h5实现文件上传




四 总结

通过以上的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的业务功能的地方,由于本文是从CSDN迁移过来的,原文实在一年前写的,所以带来的坟贴感觉请见谅。 

原文csdn请戳:这里

以上只JSBridge的使用姿势,,以后再给大家解剖下JsBridge的内部实现。

项目地址

项目实例:https://github.com/NeglectedByBoss/JsBridge_Android 

英文介绍:https://github.com/lzyzsd/JsBridge

repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
1
2
3
4
5
6
7
8

2 WebView需使用jsBridge的webView
<com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
1
2
3
4
5


JS和Native交互

JS是基于订阅和回调来实现Js和native交互的,我们需要在java中订阅,然后Js中回调,反之也可以。

3.1 Java

registerHandler()用来注册一个java函数,来实现js回调的handler,
第一个:订阅的方法名

第二个: 回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)
//必须和js同名函数,注册具体执行函数,类似java实现类
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
function.onCallBack( data + “java”);
}
});
1
2
3
4
5
6
7
8

3.2 JS

Js代码需要用window.WebViewJavascriptBridge.callHandler同步回调java层注册的同名函数,这和java和c库的jni调用如出一辙,方法名必须和Java层保持一致
第一参数:方法名
第二个:js调用native的请求参数

第三个:js在被回调后具体执行方法,responseData为java层回传jsonStr.
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': requsetData }
, function(responseData) {
// do somrthing
}
);
1
2
3
4
5
6
7
8


案列实践

* Activity*

初始化WebView,设置必要的参数。
mWebView = (BridgeWebView) findViewById(R.id.webView);
// 设置具体WebViewClient
mWebView.setWebViewClient(new MyWebViewClient(mWebView));
// set HadlerCallBack
mWebView.setDefaultHandler(new myHadlerCallBack());
// setWebChromeClient
mWebView.setWebChromeClient(new WebChromeClient());
1
2
3
4
5
6
7
8

需要自定义HandlerCallBack和WebViewClent;
/**
* 自定义的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();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

加载网页 支持本地和远程
mWebView.loadUrl("file:///android_asset/demo.html");
1
2


1 java调用js函数

订阅一个叫submitFromWeb 的方法名 并会写回调函数
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);
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

js同样需要java注册订阅的同名函数
//call native method
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': data }
, function(responseData) {
document.getElementById("show").innerHTML = "send get responseData from java,       data = " + responseData
}
);
1
2
3
4
5
6
7
8
9


2 JS调用Java代码

反之js调用java代码

Js 订阅一个叫functionInJs的方法
// 注册一个"functionInJs",
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says  我要你的地址!";
// response java层
responseCallback(responseData);
});
1
2
3
4
5
6
7
8

Java代码响应functionInJs 函数
// 回调 "functionInJs"
mWebView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {

// to do somthing

}
});
1
2
3
4
5
6
7
8
9
10


3 注意事项

无论怎样形式的交互,Js 必须要初始化jsBridge
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': '测试中文!'
};
console.log('JS responding with', data);
responseCallback(data);
});
1
2
3
4
5
6
7
8
9
效果图:




代码展示

1. Activty

public class MainActivity extends AppCompatActivity {
private BridgeWebView mWebView;

ValueCallback<Uri> 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<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();
}
});

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();

}
});
}

/**
* 自定义的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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139



通过实例化webView,用法和安卓原生的view没多大区别,设置WebChromClient, 设置加载的html(同样支持网络和本地文件),接着我们需要给web注册和html端约定好的js方法名。代码列举的submitFromweb和js的执行的方法名一致,玩过NDK的JNI调用的朋友也知道必须和c代码之间有个约定,其实js桥和jni有点类似

2 js代码
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: "这是一个图片 <img src=\"a.png\"/> 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);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

这段代码不难理解,我们对上面的id为enter的Button注册了一个点击事件,点击后执行以下testClick()方法,依次类推,其他Button注册事件相同,当点击“发消息给Native”的按钮时,Js通过webWiew的jsBridage.send()发送一条数据给java层(密码和用户名),同时执行function()来执行应java层回调函数的。此demo中是把java返回的数据插入到ID为”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));
}

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

3. H5



这里so ez ! 你不必care

h5实现文件上传




四 总结

通过以上的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的业务功能的地方,由于本文是从CSDN迁移过来的,原文实在一年前写的,所以带来的坟贴感觉请见谅。 

原文csdn请戳:这里

以上只JSBridge的使用姿势,,以后再给大家解剖下JsBridge的内部实现。

项目地址

项目实例:https://github.com/NeglectedByBoss/JsBridge_Android 

英文介绍:https://github.com/lzyzsd/JsBridge
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: