предисловие
В предыдущей статье были представлены соответствующие технологии разработки мобильных терминалов.Эта статья в основном начинается с связи JS Bridge, разработанной Hybrid.
Как следует из названия, JS Bridge означает мост, который является мостом, соединяющим JS и Native, а также ядром гибридного приложения. Обычно он делится на две формы: JS, вызывающий Native, и Native, активно вызывающий JS.
URL Scheme
Схема URL – это специальный URL-адрес, который обычно используется для пробуждения приложения в веб-интерфейсе или даже для перехода на определенную страницу приложения. Например, при оплате на мобильном веб-сайте вы можете напрямую вызвать платеж Alipay. страница.
Вот небольшой пример, вы можете ввести прямо в браузереweixin://, система предложит вам открыть WeChat. войтиmqq://Это поможет вам разбудить мобильный QQ.
Вот краткий обзор часто используемых схем URL-адресов приложений:Коллекция URL-схем
Открыв эту страницу на своем мобильном телефоне, нажмите здесь, и вам будет предложено открыть WeChat.
Мы часто говорим, что Deeplink обычно реализуется на основе схемы URL. Структура URI выглядит следующим образом:
URI = scheme:[//authority]path[?query][#fragment]
// scheme = http
// authority = www.baidu.com
// path = /link
// query = url=xxxxx
authority = [userinfo@]host[:port]
Помимо двух распространенных протоколов http/https, вы также можете настроить протокол. Чтобы позаимствовать картинку из Википедии:
Обычно после установки приложения в системе мобильного телефона регистрируется схема, напримерweixin://Таким образом, когда мы получаем доступ к этому адресу схемы в мобильном браузере, система вызывает наше приложение.
Как правило, в Android вам необходимо зарегистрировать Scheme в файле AndroidManifest.xml:
<activity
android:name=".login.dispatch.DispatchActivity"
android:launchMode="singleTask"
android:theme="@style/AppDispatchTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="taobao" />
<data android:host="xxx" />
<data android:path="/goods" />
</intent-filter>
</activity>
В iOS его нужно прописать в Xcode.Некоторые уже используются системой и не должны использоваться, например Карты, YouTube, Музыка. Для получения дополнительной информации см. документацию на официальном веб-сайте Apple:Defining a Custom URL Scheme for Your App
JS вызывает натив
В iOS необходимо различать UIWebView и WKWebView два WebView:
WKWebView появился после iOS8, цель — заменить громоздкий UIWebView, он занимает меньше памяти, около 1/3 от UIWebView, поддерживает лучшие возможности HTML5 и имеет более мощную производительность. Но есть и некоторые минусы, такие как отсутствие поддержки кеширования, нужно вставлять куки самому, нельзя отправлять POST-запросы с параметрами, нельзя парсить параметры при перехвате POST-запросов и так далее.
Есть примерно три способа, которыми JS может вызвать нативную коммуникацию:
- Схема перехвата
- Блокировка всплывающих окон
- Внедрить контекст JS
Эти три метода, как правило, имеют свои преимущества и недостатки, которые будут представлены один за другим ниже.
Схема перехвата
Подумайте хорошенько, если мы передаем данные между JS и Java, что нам делать? Для фронтенд-разработки наиболее частым требованием является настройка интерфейса запросов Ajax. Независимо от того, является ли другая сторона Java или Python, мы можем получать данные через интерфейс http/https. На самом деле этот процесс больше похож на JSONP.
Известно, что клиент может перехватывать запросы, так можно ли поднимать шумиху по этому поводу?
Что, если мы запросим несуществующий адрес с некоторыми параметрами на нем и укажем клиенту функцию, которую нам нужно вызвать через параметры?
Например, я хочу вызвать функцию сканирования кода:
axios.get('http://xxxx?func=scan&callback_id=yyyy')
Клиент может перехватить этот запрос и проанализировать указанные выше параметры.funcчтобы определить, какая функция должна быть вызвана в данный момент. После того, как клиент активирует функцию сканирования кода, он получит объект обратных вызовов в WebView и вызовет его обратно в соответствии с callback_id.
Итак, основываясь на приведенном выше примере, мы можем использовать доменное имя и путь в качестве идентификатора связи, func в параметре в качестве инструкции, callback_id в качестве функции обратного вызова и другие параметры в качестве передачи данных. HTTP-запросы, не соответствующие условиям, не должны перехватываться.
Конечно, текущий основной метод — это пользовательский протокол Scheme, который мы видели ранее, который используется в качестве идентификатора связи, а имя домена и путь используются в качестве инструкций.
Преимущество этого метода в том, что iOS6 раньше поддерживала только этот метод, и совместимость лучше.
JS-сторона
У нас есть много способов инициировать запрос, наиболее широко используемым в настоящее время является переход через iframe:
- Прыгать по тегу a
<a href="taobao://">点击我打开淘宝</a>
- перенаправить
location.href = "taobao://"
- iframe прыжок
const iframe = document.createElement("iframe");
iframe.src = "taobao://"
iframe.style.display = "none"
document.body.appendChild(iframe)
Сторона Android
Доступно на стороне AndroidshouldOverrideUrlLoadingдля перехвата URL-запросов.
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("taobao")) {
// 拿到调用路径后解析调用的指令和参数,根据这些去调用 Native 方法
return true;
}
}
Сторона iOS
На стороне iOS необходимо различать UIWebView и WKWebView. В UIWebView:
- (BOOL)shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(BPWebViewNavigationType)navigationType
{
if (xxx) {
// 拿到调用路径后解析调用的指令和参数,根据这些去调用 Native 方法
return NO;
}
return [super shouldStartLoadWithRequest:request navigationType:navigationType];
}
В WKWebView:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler
{
if(xxx) {
// 拿到调用路径后解析调用的指令和参数,根据这些去调用 Native 方法
BLOCK_EXEC(decisionHandler, WKNavigationActionPolicyCancel);
} else {
BLOCK_EXEC(decisionHandler, WKNavigationActionPolicyAllow);
}
[self.webView.URLLoader webView:webView decidedPolicy:policy forNavigationAction:navigationAction];
}
В настоящее время не рекомендуется использовать только форму перехвата параметров парсинга URL Scheme, есть несколько проблем.
- непрерывный вызов
location.hrefБудет потеря сообщений, потому что WebView ограничивает непрерывные переходы и отфильтровывает последующие запросы. - URL-адрес будет иметь ограничение по длине, если он станет слишком длинным, информация будет потеряна.
Поэтому такие библиотеки, как WebViewJavaScriptBridge, используются в сочетании с API-интерфейсом для внедрения, который мы также используем в настоящее время и который будет представлен позже.
Блокировка всплывающих окон
Реализация Android
Этот метод перехватывается с помощью всплывающего окна для запуска соответствующего события WebView. обычно вsetWebChromeClientвнутриonJsAlert,onJsConfirm,onJsPromptМетоды перехватывают и анализируют поступающие сообщения.
// 拦截 Prompt
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
if (xxx) {
// 解析 message 的值,调用对应方法
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
// 拦截 Confirm
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
// 拦截 Alert
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
iOS-реализация
Возьмем в качестве примера WKWebView:
+ (void)webViewRunJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
defaultText:(NSString *)defaultText
completionHandler:(void (^)(NSString * _Nullable))completionHandler
{
/** Triggered by JS:
var person = prompt("Please enter your name", "Harry Potter");
if (person == null || person == "") {
txt = "User cancelled the prompt.";
} else {
txt = "Hello " + person + "! How are you today?";
}
*/
if (xxx) {
BLOCK_EXEC(completionHandler, text);
} else {
BLOCK_EXEC(completionHandler, nil);
}
}
Недостатком этого метода является то, что UIWebView не поддерживается на iOS, а WKWebView лучшеscriptMessageHandler, скорее обидно.
внедрить контекст
Ранее мы говорили о встроенном в iOS фреймворке JavaScriptCore, который может реализовывать такие функции, как выполнение JS и внедрение Native-объектов.
Этот метод не полагается на перехват, он в основном внедряет объекты и методы в контекст JS через WebView, позволяя JS напрямую вызывать натив.
PS: Block в iOS — это реализация OC для замыкания, которая по сути является объектом, определяющим функции в JS.
iOS UIWebView
Боковой код iOS:
// 获取 JS 上下文
JSContext *context = [webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 注入 Block
context[@"callHandler"] = ^(JSValue * data) {
// 处理调用方法和参数
// 调用 Native 功能
// 回调 JS Callback
}
JS-код:
window.callHandler({
type: "scan",
data: "",
callback: function(data) {
}
});
Самое классное в этом методе то, что вызов JS является синхронным и возвращаемое значение может быть получено немедленно.
Нам больше не нужно делать то же самое с методом перехвата, каждый раз при передаче значения объект должен бытьJSON.stringify, вы можете напрямую передавать JSON в прошлом, а также поддерживать прямую передачу функции в прошлом.
iOS WKWebView
В WKWebView черезaddScriptMessageHandlerдля внедрения объектов в контекст JS, который можно вызывать при уничтожении WebViewremoveScriptMessageHandlerуничтожить этот объект.
После того, как внешний интерфейс вызовет введенный собственный метод, вы можете передатьdidReceiveScriptMessageдля получения параметров, переданных из внешнего интерфейса.
WKWebView *wkWebView = [[WKWebView alloc] init];
WKWebViewConfiguration *configuration = wkWebView.configuration;
WKUserContentController *userCC = configuration.userContentController;
// 注入对象
[userCC addScriptMessageHandler:self name:@"nativeObj"];
// 清除对象
[userCC removeScriptMessageHandler:self name:@"nativeObj"];
// 客户端处理前端调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// 获取前端传来的参数
NSDictionary *msgBody = message.body;
// 如果是 nativeObj 就进行相应处理
if (![message.name isEqualToString:@"nativeObj"]) {
//
return;
}
}
использоватьaddScriptMessageHandlerВнедренный объект на самом деле только одинpostMessageметод, пользовательские методы больше не могут быть вызваны. Передняя часть называется следующим образом:
window.webkit.messageHandlers.nativeObj.postMessage(data);
Следует отметить, что для этого подхода требуется iOS8 и выше, а возврат не синхронизирован. UIWebView и то же самое, также поддерживает объект JSON с прямой передачей, без строки.
Android addJavascriptInterface
Внедрение JS до Android 4.2 обычно выполняется с использованиемaddJavascriptInterface, и предыдущийaddScriptMessageHandlerЕсть несколько похожих, но без своих ограничений.
public void addJavascriptInterface() {
mWebView.addJavascriptInterface(new DatePickerJSBridge(), "DatePickerBridge");
}
private class PickerJSBridge {
public void _pick(...) {
}
}
Вызовите это в JS:
window.DatePickerBridge._pick(...)
Но эта схема имеет определенные риски, вы можете обратиться к этой статье:Скрытые опасности интерфейса в WebView и использование висячих лошадей мобильного телефонаПредоставляется после Android 4.2@JavascriptInterfaceАннотация, методы, открытые для JS, должны нести это.
Итак, предыдущий_pickМетод должен содержать эту аннотацию.
private class PickerJSBridge {
@JavascriptInterface
public void _pick(...) {
}
}
Нативные вызовы JS
Собственные вызовы JS обычно являются прямыми строками кода JS, которые чем-то похожи на вызовы JS.evalдля выполнения строки кода. обычно имеютloadUrl,evaluateJavascriptНесколько других методов представлены здесь один за другим.
Но в любом случае, клиент может получить монтирование только дляwindowСвойства и методы объектов.
Android
В Android необходимо различать версию, версия до Android 4.4 поддерживает loadUrl, и метод использования аналогичен тому, что в теге a.hrefЭто то же самое, что писать в нем JS-скрипты.javascript:xxxформа. Таким образом, возвращаемое значение не может быть получено напрямую.
webView.loadUrl("javascript:foo()")
Обычно используется в версиях выше Android 4.4.evaluateJavascriptвызвать этот API. Тут надо судить о версии.
if (Build.VERSION.SDK_INT > 19) //see what wrapper we have
{
webView.evaluateJavascript("javascript:foo()", null);
} else {
webView.loadUrl("javascript:foo()");
}
UIWebView
Используется в UIWebView на iOSstringByEvaluatingJavaScriptFromStringдля вызова JS-кода. Этот метод является синхронным и блокирует поток.
results = [self.webView stringByEvaluatingJavaScriptFromString:"foo()"];
WKWebView
WKWebView может использоватьevaluateJavaScriptспособ вызова JS-кода.
[self.webView evaluateJavaScript:@"document.body.offsetHeight;" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
// 获取返回值 response
}];
JS-дизайн моста
Я закончил все методы интермодуляции между JS и Native. Давайте представим дизайн JS Bridge на нашей стороне. Связь JS Bridge на нашей стороне реализована на основе библиотеки WebViewJavascriptBridge. В основном это делается в сочетании с протоколом Scheme + внедрением контекста. Учитывая различные методы связи между Android и iOS, он инкапсулирован здесь, чтобы обеспечить согласованность API, предоставляемого извне. Мы инкапсулируем определенные вызовы функций в пакеты npm Ниже приведены несколько основных API:
- callHandler(name, params, callback): это метод для вызова функции Native, передачи имени модуля, параметров и функции обратного вызова в Native.
- hasHandler(name): это вызов для проверки того, поддерживает ли клиент определенную функцию.
- registerHandler(name): это для предварительной регистрации функции и ожидания обратного вызова Native, например
pageDidBackэта сцена.
Так как же реализованы эти API? Здесь пакеты Android и iOS несовместимы и должны обсуждаться отдельно.
Android Bridge
Ранее мы говорили, что Android может пройти@JavascriptInterfaceАннотации для предоставления объектов и методов JS. Поэтому несколько методов здесь представлены JS через аннотации, а некоторая обработка совместимости выполняется на уровне JS.
hasHandler
Первый и самый простой этоhasHandler, заключается в том, чтобы поддерживать в клиенте таблицу (на самом деле, мы жестко закодированы), в которой есть информация о поддерживаемых модулях Bridge, просто используйтеswitch...caseПросто судить.
@JavascriptInterface
public boolean hasHandler(String cmd) {
switch (cmd) {
case xxx:
case yyy:
case zzz:
return true;
}
return false;
}
callHandler
Тогда давайте посмотримcallHandlerЭтот метод, который предоставляет JS для вызова собственных функций. Прежде чем вызывать этот метод, нам обычно нужно решить, поддерживает ли Native эту функцию.
function callHandler(name, params, callback) {
if (!window.WebViewJavascriptBridge.hasHandler(name)) {
}
}
Если Native не поддерживает этот мост, нам нужно выполнить обработку совместимости при обратном вызове. Эта обработка совместимости включает два аспекта: один аспект функции, а другой — возвращаемый параметр обратного вызова по умолчанию.
Например, если мы вызываем всплывающую функцию Native, если клиент не поддерживает этот мост или если мы открываем страницу в браузере, мы должны в это время выйти в использование Интернета.alertВсплывающие окна. Для обратного вызова мы можем передать 0 по умолчанию, указывая, что эта функция в настоящее время не поддерживается.
Предположим, этоalertМост получает два параметра, которыеtitleа такжеcontent, то вы должны использовать собственный браузерalertпокажи это.
function fallback(params, callback) {
let content = `${params.title}\n{params.content}`
window.alert(content);
callback && callback(0)
}
этоfallbackМы надеемся, что сможете функционировать более общие, каждый вызов метода должен иметь свой собственныйfallbackфункция, так что предыдущаяcallHandlerДолжно быть спроектировано так:
function callHandler(name, params, fallback) {
return function(...rest, callback) {
const paramsList = {};
for (let i = 0; i < params.length; i++) {
paramsList[params] = rest[i];
}
if (!callback) {
callback = function(result) {};
}
if (fallback && !window.WebViewJavascriptBridge.hasHandler(name))) {
fallback(paramsList, callback);
} else {
window.WebViewJavascriptBridge.callHandler(name, params, callback);
}
}
}
Мы можем инкапсулировать некоторые функциональные методы на основе этой функции, такие как предыдущее предупреждение:
function fallback(params, callback) {
let content = `${params.title}\n{params.content}`
window.alert(content);
callback && callback(0)
}
function alert(
title,
content,
cb: any
) {
return callHandler(
'alert',
['title', 'content'],
fallback
)(title, content, cb);
}
alert(`this is title`, `hahaha`, function() {
console.log('success')
})
Конкретный эффект подобен следующему, это изображение, которое я случайно нашел в Google (вторжение и удаление):
Так как же клиент реализует функцию обратного вызова? Как упоминалось ранее, если клиент хочет вызвать метод JS, он может вызвать и подключиться только кwindowнад объектом.
Следовательно, вот очень умный метод, на самом деле, функция обратного вызова все еще JS выполнение. Перед вызовом уроженца мы можем сопоставить функцию обратного вызова и UniqueId, а затем есть локальные JS. Нам нужно только передать Callbackid для родных.
function callHandler(name, data, callback) {
const id = `cb_${uniqueId++}_${new Date().getTime()}`;
callbacks[id] = callback;
window.bridge.send(name, JSON.stringify(data), id)
}
На стороне клиента, когда метод отправки получит параметры, он выполнит соответствующую функцию, а затем используетwebView.loadUrlАктивно вызывать принимающую функцию внешнего интерфейса.
@JavascriptInterface
public void send(final String cmd, String data, final String callbackId) {
// 获取数据,根据 cmd 来调用对应功能
// 调用结束后,回调前端 callback
String js = String.format("javascript: window.bridge.onReceive(\'%1$s\', \'%2$s\');", callbackId, result.toDataString());
webView.loadUrl(js);
}
Поэтому JS должен определить это заранее.onReceiveметод, который получает callbackId и результат.
window.bridge.onReceive = function(callbackId, result) {
let params = {};
try {
params = JSON.parse(result)
} catch (err) {
//
}
if (callbackId) {
const callback = callbacks[callbackId];
callback(params)
delete callbacks[callbackId];
}
}
Общий процесс выглядит следующим образом:
registerHandler
Процесс регистрации относительно прост, и мы также сохраняем функцию обратного вызова вmessageHandlerобъект, но на этот раз ключ уже не случайный id, аname.
function registerHandler(handlerName, callback) {
if (!messageHandlers[handlerName]) {
messageHandlers[handlerName] = [handler];
} else {
// 支持注册多个 handler
messageHandlers[handlerName].push(handler);
}
}
// 检查是否有这个注册可以直接检查 messageHandlers 里面是否有
function hasRegisteredHandler(handlerName) {
let has = false;
try {
has = !!messageHandlers[handlerName];
} catch (exception) {}
return has;
}
это не похожеcallHandlerнужно активно звонитьwindow.bridge.sendЧтобы уведомить клиента, просто подождите, пока клиент позвонит в нужное время.window.bridge.onReceiveВот и все.
Так что здесь нужно переделыватьonReceiveметод. Поскольку callbackId больше не будет, клиент может передать нулевое значение, а затемhandlerNameПоместите это в результат.
window.bridge.onReceive = function(callbackId, result) {
let params = {};
try {
params = JSON.parse(result)
} catch (err) {
//
}
if (callbackId) {
const callback = callbacks[callbackId];
callback(params)
delete callbacks[callbackId];
} else if (params.handlerName)(
// 可能注册了多个
const handlers = messageHandlers[params.handlerName];
for (let i = 0; i < handlers.length; i++) {
try {
delete params.handlerName;
handlers[i](params);
} catch (exception) {
}
}
)
}
Процесс в этом случае выглядит следующим образом, и можно обнаружить, что JS вообще не нужно вызывать Native:
iOS Bridge
После разговора об Android, давайте поговорим об iOS.Изначально iOS и Android могут быть спроектированы одинаково, но есть много различий по разным причинам.
Наиболее заметное различие между iOS и Android заключается в следующем.window.bridge.sendДля реализации метода в Android напрямую вызывается метод Native, а в iOS — в виде схемы URL.
Протокол по-прежнему остается протоколом в WebViewJavaScriptBridge.Сама схема URL-адресов не будет передавать данные, а просто сообщит Native, что есть новый вызов.
Затем Native вызовет метод JS, чтобы получить все методы, которые необходимо выполнить в очереди.
Поэтому нам нужно заранее создать iframe и вставить его в DOM для последующего использования.
const CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme';
const QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__';
function _createQueueReadyIframe(doc) {
messagingIframe = doc.createElement('iframe');
messagingIframe.style.display = 'none';
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
doc.documentElement.appendChild(messagingIframe);
}
callHandler
Вам нужно только повторно использовать этот iframe каждый раз, когда вы его вызываете. Вот код, который обрабатывает обратный вызов и уведомляет Native:
function callHandler(handlerName, data, responseCallback) {
_doSend({ handlerName: handlerName, data: data }, responseCallback);
}
function _doSend(
message,
callback
) {
if (responseCallback) {
const callbackId = `cb_${uniqueId++}_${new Date().getTime()}`;
callbacks[callbackId] = callback;
message['callbackId'] = callbackId;
}
sendMessageQueue.push(message);
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}
После уведомления Native, как он получает нашиhandlerNameа такжеdataШерстяная ткань? мы можем достичьfetchQueueМетоды.
function _fetchQueue() {
const messageQueueString = JSON.stringify(sendMessageQueue);
sendMessageQueue = [];
return messageQueueString;
}
а затем смонтировать его наwindow.WebViewJavascriptBridgeнад объектом.
window.WebViewJavascriptBridge = {
_fetchQueue: _fetchQueue
};
Таким образом, iOS может использоватьevaluateJavaScriptЛегко получить этоmessageQueue.
- (void)flushMessageQueue
{
[_webView evaluateJavaScript:@"WebViewJavascriptBridge._fetchQueue();" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
[self _flushMessageQueue:result];
}];
}
- (void)_flushMessageQueue:(id)messageQueueObj
{
// 解析 messageQueueString
// 根据传入的 handlerName 执行对应操作
}
Так как же iOS вызывает функцию обратного вызова JS? Это на самом деле то же самое, что и AndroidonReceiveтот же принцип. Здесь можно добиться_handleMessageFromObjCметод, также смонтированный наwindow.WebViewJavascriptBridgeПоверх объекта, ожидая обратного вызова iOS.
function _dispatchMessageFromObjC(messageJSON) {
const message = JSON.parse(messageJSON);
if (message.responseId) {
var responseCallback = callbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
delete callbacks[message.responseId];
}
}
Процесс выглядит следующим образом:
registerHandler
Принцип registerHandler точно такой же, как и в Android, они и регистрируют событие заранее, и ждут вызова iOS, не буду вдаваться в подробности, вот код:
// 注册
function registerHandler(handlerName, handler) {
if (typeof messageHandlers[handlerName] === 'undefined') {
messageHandlers[handlerName] = [handler];
} else {
messageHandlers[handlerName].push(handler);
}
}
// 回调
function _dispatchMessageFromObjC(messageJSON) {
const message = JSON.parse(messageJSON);
if (message.responseId) {
var responseCallback = callbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
delete callbacks[message.responseId];
} else if (message.handlerName){
handlers = messageHandlers[message.handlerName];
for (let i = 0; i < handlers.length; i++) {
try {
handlers[i](message.data, responseCallback);
} catch (exception) {
}
}
}
}
Суммировать
Это общие принципы взаимодействия JS и Native в Hybrid, игнорируя многие детали, такие как инициализацияWebViewJavascriptBridgeОбъекты и т. д. Если вам интересно, вы также можете обратиться к этой библиотеке:JsBridge