非常需要注意的是关于安卓端 在assets文件夹里注入的js桥梁文件 一定不要有注释 或者是压缩成一行代码才能注入成功
// 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
// version 0.1.1
// write by shuchong
(function () {
if (window.la) {
return
}
// native和js的沟通,通过发送消息、接收队列、处理消息的逻辑来处理
// js发给native用url
// native发给js通用调用_handleMessageFromNative方法
// 发送消息请求url的iframe
var messagingIframe
// js发送消息的队列
var sendMessageQueue = []
// js接收消息的队列
var receiveMessageQueue = []
// 接收消息处理的方法集
var messageHandlers = {}
var CUSTOM_PROTOCOL_SCHEME = 'yy'
var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/'
// 发送信息给安卓后,安卓回调js的callback方法集
var responseCallbacks = {}
// 安卓回调js的callback方法集的id
var uniqueId = 1
// 创建发送消息的iframe
function _createQueueReadyIframe (doc) {
messagingIframe = doc.createElement('iframe')
messagingIframe.style.display = 'none'
doc.documentElement.appendChild(messagingIframe)
}
// set default messageHandler 初始化默认的接收消息队列
// messageHandler为默认的js端收到消息的处理函数
function init (messageHandler) {
if (la._messageHandler) {
throw new Error('WebViewJavascriptBridge.init called twice')
}
la._messageHandler = messageHandler
var receivedMessages = receiveMessageQueue
receiveMessageQueue = null
for (var i = 0; i < receivedMessages.length; i++) {
_dispatchMessageFromNative(receivedMessages[i])
}
console.log('la inited');
}
// 发送
function send (data, responseCallback) {
_doSend({
data: data
}, responseCallback)
}
// 注册线程 往数组里面添加值
function registerHandler (handlerName, handler) {
messageHandlers[handlerName] = handler
}
// JS调用Native方法时,通过该方法出发native的shouldOverrideUrlLoading方法,使Native主动向JS取数据
// 调用线程
// js调用native方法
function callHandler (handlerName, data, responseCallback) {
_doSend({
handlerName: handlerName,
data: data
}, responseCallback)
}
// 3、JS将数据发送到Native端
// sendMessage add message, 触发native的 shouldOverrideUrlLoading方法,使Native主动向JS取数据
// *******************
// 把消息队列数据放到shouldOverrideUrlLoading 的URL中不就可以了吗??
// 为什么还要Native主动取一次,然后再放到shouldOverrideUrlLoading的URL中返回??
function _doSend (message, responseCallback) {
// 发送的数据存在
if (responseCallback) {
//
var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime()
responseCallbacks[callbackId] = responseCallback
message.callbackId = callbackId
}
// 添加到消息队列中
sendMessageQueue.push(message)
// 让Native加载一个新的页面
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE
}
// 将数据返回给Native
// 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,
// 所以使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue () {
// json数据
var messageQueueString = JSON.stringify(sendMessageQueue)
// message数据清空
sendMessageQueue = []
// 数据返回到shouldOverrideUrlLoading
// android can't read directly the return data, so we can reload iframe src to communicate with java
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString)
}
// 2、分发Native的消息
function _dispatchMessageFromNative (messageJSON) {
setTimeout(function () {
// 解析消息
// todo:try catch
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 {
// 消息中有callbackId 说明需要将处理完成后,需要回调Native端
// 直接发送
if (message.callbackId) {
// 回调消息的 回调ID
var callbackResponseId = message.callbackId
//
responseCallback = function (responseData) {
// 发送JS端的responseData
_doSend({
responseId: callbackResponseId,
responseData: responseData
})
}
}
// jsBridge的js端默认回调
var handler = la._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)
}
}
}
})
}
// 1.收到Native的消息
function _handleMessageFromNative (messageJSON) {
//
console.log(messageJSON)
// 添加到接收消息队列
if (receiveMessageQueue) {
receiveMessageQueue.push(messageJSON)
}
// 分发Native消息
_dispatchMessageFromNative(messageJSON)
}
function listen (eventName, handler) {
callHandler(eventName)
messageHandlers[eventName] = handler
}
// mossSpeech
// Array.<string>
// 注册监听的语音识别文字。用户说该文字触发回调函数执行。
// mossSkillset
// Array.<string>
// 注册监听的语义skillcommand。用户语义生成skillcommand如果命中设置的内容,则触发回调。
// wx.addMossEventListener({
// mossSpeech:['刷新支付二维码'],
// mossSkillset:['Search']
// Tips: 当前后台语意注册需要两部分字段:intent/domain;
// // 为保持参数一致,故Skillset形式约定为 ‘intent[]domain’,如:
// // mossSkillset:['miniProgram[]search', 'generalControl[]nextPage']
// }, onSkillCommand)
// words 为字符串数组, 最少有一个词
function registerSpeech (words, handler) {
callHandler('_registerSpeech', words)
words.forEach(word => {
messageHandlers['_speech' + word] = handler
})
}
// init(messageHandler),初始化,设置js收到消息时的默认messageHandler,并消化所有init之前已接收的消息
// send(data, responseCallback),js端发送消息给native
// registerHandler,js端注册某native消息的处理方法,消息的handlerName,registerHandler(handlerName, handler)
// callHandler,js端调用native方法,callHandler(handlerName, data, responseCallback)
// listen, js端注册异步响应的消息处理方法listen(eventName, data, handler,isAdd=true),isAdd是否是增加的处理,false时清空之前的处理handler
// 这个功能还没想好-------unListen(eventName,data), 取消监听(安卓要做出相应处理,比如语音免唤醒词的反注册)
// _fetchQueue,native调用,获取消息data的方法
// _handleMessageFromNative,native调用,发送消息给js端
var la = window.la = {
listen: listen,
registerHandler: registerHandler,
registerSpeech: registerSpeech,
_fetchQueue: _fetchQueue,
_handleMessageFromNative: _handleMessageFromNative
};
['showTitle', 'playTTS','navigateMap'].forEach(a => {
la[a] = function (data, responseCallback) {
callHandler(a, data, responseCallback)
}
})
var doc = document
_createQueueReadyIframe(doc)
var readyEvent = doc.createEvent('Events')
readyEvent.initEvent('WebViewJavascriptBridgeReady')
readyEvent.bridge = la
doc.dispatchEvent(readyEvent)
init()
})()
压缩后的js文件
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){e.exports=t(1)},function(e,n){!function(){if(!window.la){var e,n=[],t=[],r={},o={},a=1,i=window.la={listen:function(e,n){u(e),r[e]=n},registerHandler:function(e,n){r[e]=n},registerSpeech:function(e,n){u("_registerSpeech",e),e.forEach(e=>{r["_speech"+e]=n})},_fetchQueue:function(){var t=JSON.stringify(n);n=[],e.src="yy://return/_fetchQueue/"+encodeURIComponent(t)},_handleMessageFromNative:function(e){console.log(e),t&&t.push(e),f(e)}};["showTitle","playTTS","navigateMap","login"].forEach(e=>{i[e]=function(n,t){u(e,n,t)}});var c=document;!function(n){(e=n.createElement("iframe")).style.display="none",n.documentElement.appendChild(e)}(c);var l=c.createEvent("Events");l.initEvent("WebViewJavascriptBridgeReady"),l.bridge=i,c.dispatchEvent(l),function(e){if(i._messageHandler)throw new Error("WebViewJavascriptBridge.init called twice");i._messageHandler=e;var n=t;t=null;for(var r=0;r<n.length;r++)f(n[r]);console.log("la 1.0.0 inited")}()}function u(e,n,t){s({handlerName:e,data:n},t)}function s(t,r){if(r){var i="cb_"+a+++"_"+(new Date).getTime();o[i]=r,t.callbackId=i}n.push(t),e.src="yy://__QUEUE_MESSAGE__/"}function f(e){setTimeout((function(){var n,t=JSON.parse(e);if(t.responseId){if(!(n=o[t.responseId]))return;n(t.responseData),delete o[t.responseId]}else{if(t.callbackId){var a=t.callbackId;n=function(e){s({responseId:a,responseData:e})}}var c=i._messageHandler;t.handlerName&&(c=r[t.handlerName]);try{c(t.data,n)}catch(e){"undefined"!=typeof console&&console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.",t,e)}}}))}}()}]);
然后我们进入正题来详细说明一下jsbridge的用法
首先是安卓端
JS端
首先注册安卓端注入的js文件的对象
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
console.log('la is ready')
},
false
);
然后就是约定的相关方法调用 js调用安卓本地注册的方法 传递网页的数据给到安卓端使用
下面是获取经纬度坐标来传递给安卓端 安卓端去调用导航来实现功能的js端代码
la.navigateMap({
latitude: detailData.lat +'', // gcj02坐标
longitude: detailData.lon +'', // gcj02坐标
address: detailData.address +'' // 地址 // 地址
},function (A2JData) {
console.log("form Android to JS:" + A2JData);
})
网友评论