Сегодня коротко поговоримJSBridge
Зачем говорить о jsbridge?
Нет причин
Отлично,JSBridge
Несмотря на то, что он относительно старый,JSBridge
Принцип также является знанием, которое в настоящее время необходимо понимать фронтенд-разработчику.
В настоящее время при разработке мобильных приложений для H5 взаимодействие с Native является обязательным.Native здесь включает в себя приложения в традиционном понимании и всевозможные сегодняшние апплеты Pit King.
Обычно крупные компании инкапсулируют свой собственный набор js sdk для предоставления веб-разработчикам возможности взаимодействия с Native.Они могут иметь свои собственные имена, но все вместе они называютсяJSBridge
.
JSBridge
JSBridge
ПринциптыJSBridge
Взаимодействие с родным. В то же время, чтобы не видеть ненужного нативного кода, здесь, но более введеноJavaScriptCore API
Для реализации интерактивного способа вводится только оригинальная классическая схема.
Что такое JSBridge?
Проще говоря,JSBridge
Это что-то среднее между страницей H5 и Native.Асинхронный двунаправленныйПо сути, ничем не отличается от наиболее распространенного метода связи HTTP, который мы вступаем в контакт с каждым днем.
Для лучшего опыта
Чтобы пользователь не знал, использует ли он веб-приложение или собственное приложение
для эффективности
搞开发的嘛,肯定都是为了提高工作效率,同时不降低太多用户体验的情况下,复用,复用这个复用那个,统一这个统一那个的。一款App产品要做好几个端,重复的页面扔给H5算了! Какой!需要一些奇特的功能?做个bridge接口吧!
Как проходит процесс коммуникации в JSBridge?
Проще говоря, этот процесс общения похож на процесс подачи поваром еды во время еды в ресторане.Шеф, как правило, не обслуживает вас лично (пожалуйста, не обращайте внимания на местных тиранов и частных поваров), а повара будут щелкать, чтобы выбрать после того, как каждое блюдо будет приготовлено, приготовьте еду.Когда прозвенит звонок, официант подойдет, чтобы забрать еду и обслуживать гостей.
В нормальных условиях после нажатия звонка подойдет официант и заберет блюда.Иногда повара могут готовить N блюд одновременно и звонить в звонок N раз.В это время официанты будут очень преданы всем этим посуду, упакуйте и выбросьте.
Так как же это достигается?
Теперь пришло время перейти к сути, давайте рассмотрим основные принципы JSBridge.
-
Давайте начнем с общения из Интернета на родной:
Ранее мы узналиJSBridge
Суть H5 — это способ связи, поэтому здесь проще понять Суть вызова H5 Native — перехват запроса.
Когда мир H5 хочет общаться с внешним миром, ему нужно (и может только) отправить запрос, например, отправить простой запрос GET.
Мы можем придумать три способа отправить запрос:
- Запрос отправляется с помощью ярлыков атрибутов SRC, например
iframe
...
const iframe = document.createElement('iframe')
iframe.src = "xxx"
Этот метод также обычно используется крупными гибридными каркасами. Неоднократно отправляя большое количество сообщений не нужно беспокоиться о потере сообщений.
- Отправить запрос с Location.href
location.href = "xxx"
Этот метод больше подходит для некоторых сценариев одноразового вызова, например, операция в H5 должна перейти на определенную страницу приложения, повторная отправка большого количества запросов таким образом приведет к потере сообщения запроса, и принимается только последний.
- Отправляйте запросы с помощью Ajax
const url = 'xxx'
fetch(url, { ... })
.then()
.catch()
Этот метод более хлопотный в написании, но производительность немного выше, чем у первых двух.
Знаменитый Cordova.js использует:
execIframe = document.createElement('iframe')
execIframe.style.display = 'none'
execIframe.src = 'gap://ready'
document.body.appendChild(execIframe)
iOS называетсяWebViewJavascriptBridge
const messagingIframe = document.createElement('iframe')
messagingIframe.src = 'https://__wvjb_queue_message__'
body.appendChild(messagingIframe)
уведомлениеCordova
WebViewJavascriptBridge
Cordova
-
Требуется точечный параметр
В большинстве случаев мы предпочитаем выносить некоторые параметры в Native, поэтому далее рассмотрим проблему передачи параметров
Вы можете подумать, в то время запрос отправляется непосредственно к параметру адреса по запросу позже, в виде швасящего запроса на него, как это:
execIframe.src = 'gap://ready?p1=v1&p2=v2&p3=v3…'
Но есть некоторые проблемы с этим подходом
-
Во-первых, его длина ограничена, хотя лимит очень большой, все-таки это будет скрытая опасность.
-
Во-вторых, если это временный интерфейс jsbridge для приложения вашей компании, вы действительно можете написать его так, но если он инкапсулирован как общий инструмент, он будет слишком тесно связан с бизнесом, если он будет реализован таким образом.
в типичномJSBridge
В схеме реализации обработка параметров реализована следующим образом:
-
Прежде всего, всякий раз, когда JS в H5 должен вызывать Native, URL-адрес для отправки запроса является фиксированным, например, gap://ready
-
Во-вторых, определите глобальную переменную массива в окне с именем messageQueue, которое пусто при инициализации.Когда H5 нужно отправить сообщение в Native, он сначала создает объект и помещает все соответствующие параметры в этот объект, а затем помещает этот объект. вставляется в конец массива messageQueue, что объясняется в следующем коде:
const messageQueue = []
window.messageQueue = messageQueue
messageQueue.push(JSON.stringify({
message: 'xxx',
params: 'xxx'
}))
// 发一个请求,按一下铃,戳一下Native~~
execIframe.src = 'gap://ready'
- Когда родной получает
gap://ready
После запроса он знает, что в H5 есть новое сообщение, он выполнит магический код, войдет в WebView и упакует все данные в глобальную переменную массива messageQueue, определенного в окне, и очистит messageQueue. по одному. мы используемeval
функция действует как этот магический код, чтобы объяснить логику здесь:
// 当Native拦截到'gap://ready'请求后执行的magic code
const messageQueue = eval('window.messageQueue')
const messages = JSON.parse(messageQueue)
for (const message in messages) {
doSomeThingWithMessage(message)
…
}
eval('window.messageQueue = []')
так,Еду уносил официант.Сообщение было удалено Native
messageQueue.push(JSON.stringify({
message: 'xxx',
params: 'xxx',
callBackName: 'xxx',
}))
这样,在Native执行完你需要的指令后会再次执行那段神奇的代码进入WebView的世界,执行定义在window上名为callbackName的方法,并把native执行的结果传给这个方法。 так:
const messageQueue = eval('window.messageQueue')
const messages = JSON.parse(messageQueue)
for (const message in messages) {
const result = doSomeThingWithMessage(message)
eval(`window[${message.callbackName}](${result})`)
…
}
eval('window.messageQueue = []')
В то же время это также показывает, как Native отправляет сообщения в H5, просто выполните метод, определенный в окне, напрямую.
Конечно, чтобы стандартизировать код и гарантировать, что H5 не создаст callbackName случайным образом, Native не выполняет метод callbackName напрямую в окне, а будет вызывать метод callbackName, вызываемый грубо.handleMessageFromNative
Этот метод представляет собой метод, заранее подготовленный H5 и определенный на окне.В этом методе обработка сообщения закрывается, и в нем вызывается метод callbackName на окне.После завершения выполнения вызывается метод callbackName. удалено из окна удалено, код всего процесса наверное такой:
// H5
function handleMessageFromNative (message) {
if (typeof message.callbackName === 'function') {
window[callbackName](message.result)
delete window[callbackName]
}
}
window.handleMessageFromNative = handleMessageFromNative
// Native
const messageQueue = eval('window.messageQueue')
const messages = JSON.parse(messageQueue)
for (const message in messages) {
const result = doSomeThingWithMessage(message)
const messageFromNative = JSON.stringify({
result,
callbackName: message.callbackName
})
eval(`window.handleMessageFromNative(${messageFromNative})`)
…
}
eval('window.messageQueue = []')
Здесь также есть некоторые правила генерации callbackName, если вам интересно, вы можете перейти к соответствующемуисходный код.大概和jsonp的规则类似。
Затем, чтобы облегчить другим использование, организацию и упаковку описанного выше процесса, H5 и Native одновременно предоставляют два интерфейса, что выглядит следующим образом:
// H5与Native同时增加如下两个接口供对方使用:
// ≈ function addEventListener(eventName, callback)
function registerHandler (handlerName, block) {
window.handlers[handlerName] = block
…
}
// Web或Native调用对方接口的方式
// ≈ dispatchEvent(eventName, data, callback)
function callHandler (handlerName, message, callback) {
window.handlers[handlerName](message)
…
}
Это делает очень удобным использование, например, для реализации функции сканирования QR-кода:
// Native
// 注册了一个扫描二维码的方法
registerHanlder('scanQRCode', () => {
// ...
Camera.open().scanQRCode()
// ...
})
// H5
// 调用扫描二维码的方法
callHanlder('scanQRCode', { type: 'qrcode' }, result => {
console.log('扫码结果:', result)
})
Если хотите, можете обернуть его в Promise:
// 为H5封装好的bridge-sdk.js,在H5中使用
/**
* 扫描二维码并返回结果
* ...
* @memberOf Camera
* @async
* @returns {Promise} 可以在then中接受扫码结果`result`,参数为 { code: 'xxxxxx' }
* ...
*/
export async function scanQRCode () {
return new Promise((resolve, reject) => {
callHanlder('scanQRCode', { type: 'qrcode' }, result => {
console.log('扫码结果:', result)
resolve(result)
})
})
}
Ну а выше это классикаJSBridge
Реализация, это выглядит очень просто, и нет проблем совместимости.
Поскольку у Native есть волшебный код, есть ли более тщательный способ?
имеют! ! ! В Native есть еще один волшебный API, назовем его пока функцией defineFunc, который может напрямую внедрять код Native в WebView несущей H5 и вешать его на окно WebView.
// define 翻译过来大概就是下面的这个意思
function defineFunc (funcName, func) {
const window = webView.window ... // 通过一些Native的API拿到WebView的window
window[funcName] = func // 这里的func 是Native的func,执行的是纯Native的代码
}
// Native
defineFunc('callSomeNativeFunction', () => {
// 这些是由Native的代码翻译成javascript的伪代码
const file = io.readFile('/path/to/file')
...
// 做一些H5做不到的事情
file.write('/path/to/file', 'content')
...
})
Это принцип использования API, такого как JavaScriptCore в iOS для достижения взаимодействия, Android имеет аналогичный метод, и есть некоторые требования к версии системы, которые можно игнорировать. Здесь это обсуждаться не будет.
Какой? ? Native может свободно выполнять код в WebView? Эта ошибка сделана Native? Серьезно испугался!
H5: Боже, мы жили в виртуальном мире! ! ! На самом дне цепи презрения! !
Да! Напоминает Матрицу, что? не видел? Показать свой возраст?