非常需要注意的是關於安卓端 在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);
})