小白必看,js-bridge 原理
js-bridge 原理
題目
請(qǐng)描述 js-bridge 原理
微信 jssdk
微信中的 h5 通過(guò) jssdk 提供的 API 可以調(diào)用微信 app 的某些功能。
JS 無(wú)法直接調(diào)用 app 的 API ,需要通過(guò)一種方式 —— 通稱(chēng) js-bridge ,它也是一些 JS 代碼。 當(dāng)然,前提是 app 得開(kāi)發(fā)支持,控制權(quán)在 app 端。就像跨域,server 不開(kāi)放支持,客戶(hù)端再折騰也沒(méi)用。
方式1 - 注入 API
客戶(hù)端為 webview 做定制開(kāi)發(fā),在 window 增加一些 API ,共前端調(diào)用。
例如增加一個(gè) window.getVersion API ,前端 JS 即可調(diào)用它來(lái)獲取 app 版本號(hào)。
const v = window.getVersion()
但這種方式一般都是同步的。
因?yàn)槟慵幢隳銈魅肓艘粋€(gè) callback 函數(shù),app 也無(wú)法執(zhí)行。app 只能執(zhí)行一段全局的 JS 代碼(像 eval)
方式2 - 劫持 url scheme
一個(gè) iframe 請(qǐng)求 url ,返回的是一個(gè)網(wǎng)頁(yè)。天然支持異步。
const iframe1 = document.getElementById('iframe1')
iframe1.onload = () => {
console.log(iframe1.contentWindow.document.body.innerHTML)
}
iframe1.src = 'http://127.0.0.1:8881/size-unit.html'
上述 url 使用的是標(biāo)準(zhǔn)的 http 協(xié)議,如果要改成 'my-app-name://api/getVersion' 呢?—— 默認(rèn)會(huì)報(bào)錯(cuò),'my-app-name' 是一個(gè)未識(shí)別的協(xié)議名稱(chēng)。
既然未識(shí)別的協(xié)議,那就可以為我所用:app 監(jiān)聽(tīng)所有的網(wǎng)絡(luò)請(qǐng)求,遇到 my-app-name: 協(xié)議,就分析 path ,并返回響應(yīng)的內(nèi)容。
const iframe1 = document.getElementById('iframe1')
iframe1.onload = () => {
console.log(iframe1.contentWindow.document.body.innerHTML) // '{ version: '1.0.1' }'
}
iframe1.src = 'my-app-name://api/getVersion'
這種自定義協(xié)議的方式,就叫做“url scheme”。微信的 scheme 以 'weixin://' 開(kāi)頭,可搜索“微信 scheme”。chrome 也有自己的 scheme
chrome://version 查看版本信息
chrome://dino 恐龍小游戲
其他可參考 mp.weixin.qq.com/s/T1Qkt8DTZ…
封裝 sdk
scheme 的調(diào)用方式非常復(fù)雜,不能每個(gè) API 都寫(xiě)重復(fù)的代碼,所以一般要封裝 sdk ,就像微信提供的 jssdk 。
const sdk = {
invoke(url, data, success, err) {
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
document.body.appendChild(iframe)
iframe.onload = () => {
const content = iframe.contentWindow.document.body.innerHTML
success(JSON.parse(content))
iframe.remove()
}
iframe.onerror = () => {
err()
iframe.remove()
}
iframe.src = `my-app-name://${url}?data=${JSON.string(data)}`
}
fn1(data, success, err) {
invoke('api/fn1', data, success, err)
}
fn2(data, success, err) {
invoke('api/fn2', data, success, err)
}
}
// 使用
sdk.fn1(
{a: 10},
(data) => { console.log('success', data) },
() => { console.log('err') }
)
答案
常用方法:劫持 url scheme
擴(kuò)展
url 長(zhǎng)度不夠怎么辦?—— 可以擴(kuò)展 ajax post 方式。 微信網(wǎng)頁(yè)開(kāi)發(fā) /JS-SDK說(shuō)明文檔
作者:服部 鏈接:https://juejin.cn/post/7085997048793104398
作者:服部
歡迎關(guān)注微信公眾號(hào) :前端陽(yáng)光