-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWebViewJavascriptBridge.js
More file actions
323 lines (307 loc) · 9.59 KB
/
Copy pathWebViewJavascriptBridge.js
File metadata and controls
323 lines (307 loc) · 9.59 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// h5 调用 native 的方法,统一调用方法为 window.JSBridge.xxx(param,callback,ishold)
var events = [
'titleBar',
'titleButton',
'open',
'close',
'resume',
'pause',
'pulltorefresh',
'call',
'share',
'login',
'pay',
'position',
'camera',
'upload',
'logout',
'scan',
]
// native 调用 h5 的方法
var receive = {
functionInJs: function (data, responseCallback) {
// 这里是android native 调用 H5 的
console.log('registerHandler 1接收的数据', data)
if (responseCallback) {
// 这里是往 native 回传的
responseCallback({ call: '这是由 native 调用 js 事件,js 给的回调 1' })
}
},
functionJs: function (data, responseCallback) {
// 这里是android native 调用 H5 的
console.log('registerHandler 2接收的数据', data)
if (responseCallback) {
// 这里是往 native 回传的
responseCallback({ call: '这是由 native 调用 js 事件,js 给的回调 2' })
}
},
}
// 根据 ua 标识判断设备类型
var ua = navigator.userAgent
var IOS = 'ios'
var ANDROID = 'android'
function getDeviceInfo() {
//获取设备信息
var device = {
type: null,
version: null,
}
//设备类型
if (/\(i[^;]+;( U;)? CPU.+Mac OS X/.test(ua)) {
device.type = IOS
// iOS 版本号提取
var iosVersion = /\b[0-9]+_[0-9]+(?:_[0-9]+)?\b/.exec(ua)
if (iosVersion && iosVersion[0]) {
device.version = iosVersion[0].replace(/_/g, '.')
}
} else if (/Android/i.test(ua)) {
device.type = ANDROID
var match = ua.match(/Android\s+([\d\.]+)/i)
device.version = match && match[1]
} else {
device.type = undefined
}
return device
}
var info = getDeviceInfo()
// 根据不同的类型注入不同的 js
if (info.type == IOS) {
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady',
function () {
callback(WebViewJavascriptBridge)
},
false
)
}
// iOS的特殊处理
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback)
}
window.WVJBCallbacks = [callback]
var WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(function () {
document.documentElement.removeChild(WVJBIframe)
}, 0)
}
setupWebViewJavascriptBridge(function (bridge) {
// 这个是 os 调用 js 的地方,因为Bridge是由 java 注入的,所以判断一下异常
if (bridge.registerHandler) {
try {
for (key in receive) {
bridge.registerHandler(key, receive[key])
}
} catch (error) {
console.log('ios 调用失败', error)
}
}
})
} else if (info.type == ANDROID) {
// 注入 android 的 Bridge
;(function () {
if (window.WebViewJavascriptBridge) {
return
}
var messagingIframe
var bizMessagingIframe
var sendMessageQueue = []
var receiveMessageQueue = []
var messageHandlers = {}
var CUSTOM_PROTOCOL_SCHEME = 'yy'
var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/'
var responseCallbacks = {}
var uniqueId = 1
// 创建消息index队列iframe
function _createQueueReadyIframe(doc) {
messagingIframe = doc.createElement('iframe')
messagingIframe.style.display = 'none'
doc.documentElement.appendChild(messagingIframe)
}
//创建消息体队列iframe
function _createQueueReadyIframe4biz(doc) {
bizMessagingIframe = doc.createElement('iframe')
bizMessagingIframe.style.display = 'none'
doc.documentElement.appendChild(bizMessagingIframe)
}
//set default messageHandler 初始化默认的消息线程
function init(messageHandler) {
if (WebViewJavascriptBridge._messageHandler) {
throw new Error('WebViewJavascriptBridge.init called twice')
}
WebViewJavascriptBridge._messageHandler = messageHandler
var receivedMessages = receiveMessageQueue
receiveMessageQueue = null
for (var i = 0; i < receivedMessages.length; i++) {
_dispatchMessageFromNative(receivedMessages[i])
}
}
// 发送
function send(data, responseCallback) {
_doSend(
{
data: data,
},
responseCallback
)
}
// 注册线程 往数组里面添加值
function registerHandler(handlerName, handler) {
messageHandlers[handlerName] = handler
}
// 调用线程
function callHandler(handlerName, data, responseCallback) {
_doSend(
{
handlerName: handlerName,
data: data,
},
responseCallback
)
}
//sendMessage add message, 触发native处理 sendMessage
function _doSend(message, responseCallback) {
if (responseCallback) {
var callbackId = 'cb_' + uniqueId++ + '_' + new Date().getTime()
responseCallbacks[callbackId] = responseCallback
message.callbackId = callbackId
}
sendMessageQueue.push(message)
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE
}
// 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue() {
var messageQueueString = JSON.stringify(sendMessageQueue)
sendMessageQueue = []
//android can't read directly the return data, so we can reload iframe src to communicate with java
if (messageQueueString !== '[]') {
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({
responseId: callbackResponseId,
responseData: responseData,
})
}
}
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) {
console.log(messageJSON)
if (receiveMessageQueue) {
receiveMessageQueue.push(messageJSON)
}
_dispatchMessageFromNative(messageJSON)
}
var WebViewJavascriptBridge = (window.WebViewJavascriptBridge = {
init: init,
send: send,
registerHandler: registerHandler,
callHandler: callHandler,
_fetchQueue: _fetchQueue,
_handleMessageFromNative: _handleMessageFromNative,
})
var doc = document
_createQueueReadyIframe(doc)
_createQueueReadyIframe4biz(doc)
var readyEvent = doc.createEvent('Events')
readyEvent.initEvent('WebViewJavascriptBridgeReady')
readyEvent.bridge = WebViewJavascriptBridge
doc.dispatchEvent(readyEvent)
})()
if (
window.WebViewJavascriptBridge &&
window.WebViewJavascriptBridge.registerHandler
) {
// 这个是 android 调用 js 的地方
for (key in receive) {
window.WebViewJavascriptBridge.registerHandler(key, receive[key])
}
}
}
var JSBridge = {
device: info,
eventMap: {
//事件队列
},
uid: 0,
// 根据不同的端调用不同的方法,目前是一样的,为了防止两边变化注入的值,所以还是分开调用
deviceRouter: function (method, params, callback, isHold) {
if (this.device.type == IOS) {
this.iosMethod(method, params, callback, isHold)
} else if (this.device.type == ANDROID) {
this.androidMethod(method, params, callback, isHold)
} else {
console.error(
'请在native端使用此方法:' + method,
params,
callback,
isHold
)
}
},
// ios 方法
iosMethod: function (method, params, callback, isHold) {
window.WebViewJavascriptBridge.callHandler(method, params, callback)
},
// 安卓方法
androidMethod: function (method, params, callback, isHold) {
window.WebViewJavascriptBridge.callHandler(method, params, callback)
},
}
// 向 Bridge 中添加 H5 调用的事件
for (var i = 0; i < events.length; i++) {
var event = events[i]
JSBridge[event] = (function (event) {
return function (params, callback, isHold) {
this.deviceRouter(event, params, callback, isHold)
}
})(event)
}
// 挂载到 window
window.JSBridge = JSBridge