WebViewJavascriptBridge.js
7.17 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//notation: js file can only use this kind of comments
//since comments will cause error when use in webview.loadurl,
//comments will be remove by java use regexp
(function() {
if (window.WebViewJavascriptBridge && window.WebViewJavascriptBridge.inited) {
return;
}
var receiveMessageQueue = [];
var messageHandlers = {};
var sendMessageQueue = [];
var responseCallbacks = {};
var uniqueId = 1;
var lastCallTime = 0;
var stoId = null;
var FETCH_QUEUE_INTERVAL = 20;
var messagingIframe;
var CUSTOM_PROTOCOL_SCHEME = "yy";
var QUEUE_HAS_MESSAGE = "__QUEUE_MESSAGE__";
// 创建消息index队列iframe
function _createQueueReadyIframe() {
messagingIframe = document.createElement('iframe');
messagingIframe.style.display = 'none';
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
document.documentElement.appendChild(messagingIframe);
}
//创建消息体队列iframe
function _createQueueReadyIframe4biz() {
bizMessagingIframe = document.createElement('iframe');
bizMessagingIframe.style.display = 'none';
document.documentElement.appendChild(bizMessagingIframe);
}
//set default messageHandler 初始化默认的消息线程
function init(messageHandler) {
if (WebViewJavascriptBridge._messageHandler) {
throw new Error('WebViewJavascriptBridge.init called twice');
}
_createQueueReadyIframe();
_createQueueReadyIframe4biz();
WebViewJavascriptBridge._messageHandler = messageHandler;
var receivedMessages = receiveMessageQueue;
receiveMessageQueue = null;
for (var i = 0; i < receivedMessages.length; i++) {
_dispatchMessageFromNative(receivedMessages[i]);
}
WebViewJavascriptBridge.inited = true;
}
// 发送
function send(data, responseCallback) {
_doSend('send', data, responseCallback);
}
// 注册线程 往数组里面添加值
function registerHandler(handlerName, handler) {
messageHandlers[handlerName] = handler;
}
function removeHandler(handlerName, handler) {
delete messageHandlers[handlerName];
}
// 调用线程
function callHandler(handlerName, data, responseCallback) {
// 如果方法不需要参数,只有回调函数,简化JS中的调用
if (arguments.length == 2 && typeof data == 'function') {
responseCallback = data;
data = null;
}
_doSend(handlerName, data, responseCallback);
}
//sendMessage add message, 触发native处理 sendMessage
function _doSend(handlerName, message, responseCallback) {
var callbackId;
if(typeof responseCallback === 'string'){
callbackId = responseCallback;
} else if (responseCallback) {
callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
responseCallbacks[callbackId] = responseCallback;
message.callbackId = callbackId;
}else{
callbackId = '';
}
try {
var fn = eval('WebViewJavascriptBridge.' + handlerName);
} catch(e) {
console.log(e);
}
if (typeof fn === 'function'){
var responseData = fn.call(WebViewJavascriptBridge, JSON.stringify(message), callbackId);
if(responseData){
responseCallback = responseCallbacks[callbackId];
if (!responseCallback) {
return;
}
responseCallback(responseData);
delete responseCallbacks[callbackId];
}
}
sendMessageQueue.push(message);
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}
// 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue() {
// 空数组直接返回
if (sendMessageQueue.length === 0) {
return;
}
// _fetchQueue 的调用间隔过短,延迟调用
if (new Date().getTime() - lastCallTime < FETCH_QUEUE_INTERVAL) {
if (!stoId) {
stoId = setTimeout(_fetchQueue, FETCH_QUEUE_INTERVAL);
}
return;
}
lastCallTime = new Date().getTime();
stoId = null;
var messageQueueString = JSON.stringify(sendMessageQueue);
sendMessageQueue = [];
//android can't read directly the return data, so we can reload iframe src to communicate with java
bizMessagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
}
//提供给native使用,
function _dispatchMessageFromNative(messageJSON) {
setTimeout(function() {
var message = JSON.parse(messageJSON);
var responseCallback;
//java call finished, now need to call js callback function
if (message.responseId) {
responseCallback = responseCallbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
delete responseCallbacks[message.responseId];
} else {
//直接发送
if (message.callbackId) {
var callbackResponseId = message.callbackId;
responseCallback = function(responseData) {
_doSend('response', responseData, callbackResponseId);
};
}
var handler = WebViewJavascriptBridge._messageHandler;
if (message.handlerName) {
handler = messageHandlers[message.handlerName];
}
//查找指定handler
try {
handler(message.data, responseCallback);
} catch (exception) {
if (typeof console != 'undefined') {
console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception);
}
}
}
});
}
//提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以
function _handleMessageFromNative(messageJSON) {
if (receiveMessageQueue) {
receiveMessageQueue.push(messageJSON);
}
_dispatchMessageFromNative(messageJSON);
}
WebViewJavascriptBridge.init = init;
WebViewJavascriptBridge.doSend = send;
WebViewJavascriptBridge.registerHandler = registerHandler;
WebViewJavascriptBridge.callHandler = callHandler;
WebViewJavascriptBridge._handleMessageFromNative = _handleMessageFromNative;
var readyEvent = document.createEvent('Events');
var jobs = window.WVJBCallbacks || [];
readyEvent.initEvent('WebViewJavascriptBridgeReady');
readyEvent.bridge = WebViewJavascriptBridge;
window.WVJBCallbacks = [];
jobs.forEach(function (job) {
job(WebViewJavascriptBridge)
});
document.dispatchEvent(readyEvent);
})();