Подробное объяснение JSBridge: от принципа до использования

JavaScript
Подробное объяснение JSBridge: от принципа до использования

Введение

В сегодняшнюю эпоху мобильных терминалов выбор технологий в основном представляет собой смешанное развитие (Hybrid), гибридная разработка — это режим разработки, который относится к использованию нескольких моделей разработки для разработки приложений, которые обычно включают два типа технологий: нативныеNative,Web H5

  • Нативные технологии в основном относятся к iOS (Objective C), Android (Java), эффективность нативной разработки низкая, все приложение необходимо переупаковывать после разработки, и выпускаются зависящие от пользователя обновления с более высокой производительностью и более широким функциональным охватом.
  • Web H5 в основном состоит из HTML, CSS и JavaScript, Интернет может лучше реализовать выпуск и обновление, а кроссплатформенность также лучше, но производительность низкая, а функции ограничены.

Значение гибридной разработки состоит в том, чтобы поглотить преимущества обоих, а с обновлением и повторением аппаратного обеспечения мобильного телефона и лучшей поддержкой системы (Android 5.0+, ISO 9.0+) для веб-функций недостатки H5 постепенно уменьшаются.

Гибридную разработку можно разделить на следующие категории в зависимости от рендеринга:

  • Гибридное приложение веб-рендеринга (Codova, NativeScript)
  • Нативные гибридные приложения (ReactNative, Weex)
  • Апплеты

Среди них нативное и веб-общение неотделимы друг от другаJSBridge, апплет здесь особенный, а среда рендеринга пользовательского интерфейса и среда выполнения JS изолированы, основанные на первых двух методах.

2. Что делает JSBridge?

В гибридном режиме H5 часто потребуется использовать собственные функции, такие как открытие QR-кода, вызов собственных страниц, получение информации о пользователе и т. д. В то же время Native также необходимо отправлять push-уведомления на веб-сторону, обновлять статус и т. д. ., в то время как JavaScript выполняется отдельно отJS Context(контейнер веб-просмотра, JCore и т. д.), он изолирован от собственной операционной среды, поэтому должен быть механизм для реализации нативной и веб-стороны.двусторонняя связь, это JSBridge: механизм, который использует движок JavaScript или контейнер Webview в качестве среды для связи через протокол протокола для реализации двусторонней связи между нативной стороной и веб-стороной.

Через JSBridge веб-сторона может вызывать интерфейс Java нативной стороны, а нативная сторона также может вызывать интерфейс JavaScript веб-стороны через JSBridge для осуществления двусторонних вызовов друг к другу.

3. Веб-просмотр

Прежде всего, разберитесь с webView. WebView — это среда, предоставляемая мобильным терминалом для запуска JavaScript. Это элемент управления для системы для отображения веб-страниц. Он может взаимодействовать с JavaScript страницы для реализации гибридной разработки. Android и iOS немного отличаются:

Android WebView использует разные версии младшей и старшей версий.webkitЯдро, используемое сразу после 4.4Chrome.

iOSUIWebViewОн доступен начиная с IOS2, но производительность низкая, а поддержка функций плохая.WKWebViewЭто обновленная версия после iOS8 с более высокой производительностью и улучшенной поддержкой функций.

В дополнение к загрузке указанного URL-адреса элемент управления WebView также может выполнять мощную обработку запросов URL-адресов, диалоговых окон JavaScript, хода загрузки и взаимодействия со страницей.Позже будет упомянуто, что от этого зависит перехват запросов и выполнение сценариев JS.

В-четвертых, принцип реализации JSB

Веб-сторону и нативную можно сравнить с режимом клиент/сервер.Когда веб-сторона вызывает собственный интерфейс, это похоже на то, как клиент отправляет запрос на серверную сторону.JSB играет здесь роль, аналогичную протоколу HTTP.Там два основных момента для реализации JSBridge:

  1. Инкапсулируйте нативный интерфейс на нативной стороне в интерфейс JavaScript
  2. Инкапсулируйте веб-интерфейс JavaScript в собственный интерфейс

4.1 Native->Web

Прежде всего, нативная сторона вызывает веб-сторону.Это относительно просто.Как интерпретируемый язык, самая большая особенность JavaScript заключается в том, что он может выполнять часть кода JS через интерпретатор в любое время и в любом месте, поэтому сплайсированный JavaScript строка кода может быть передана в JS для синтаксического анализа.Синтаксический анализатор JS может быть выполнен, синтаксический анализатор JS — это webView здесь.

Доступно только до Android 4.4loadUrlреализовать, и обратный вызов не может быть выполнен:

String jsCode = String.format("window.showWebDialog('%s')", text);
webView.loadUrl("javascript: " + jsCode);

Доступно после Android 4.4evaluateJavascriptЧтобы выполнить код JS, и вы можете получить возвращаемое значение для выполнения обратного вызова:

String jsCode = String.format("window.showWebDialog('%s')", text);
webView.evaluateJavascript(jsCode, new ValueCallback<String>() {
  @Override
  public void onReceiveValue(String value) {

  }
});

Использование iOS UIWebViewstringByEvaluatingJavaScriptFromString:

NSString *jsStr = @"执行的JS代码";
[webView stringByEvaluatingJavaScriptFromString:jsStr];

WKWebView для iOS используетevaluateJavaScript:

[webView evaluateJavaScript:@"执行的JS代码" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
  
}];

4.2 Web->Native

В Интернете есть два основных способа вызова нативной стороны.

4.2.1 Схема URL для перехвата запросов Webview

Схема URL-адреса — это формат запроса, подобный URL-адресу, формат выглядит следующим образом:

<protocol>://<host>/<path>?<qeury>#fragment

Мы можем настроить URL-схему связи JSBridge, например:jsbridge://showToast?text=hello

После того, как Native загрузит WebView, все запросы, отправленные из Интернета, будут проходить через компонент WebView, поэтому Native может переписать методы в WebView и никогда не перехватывать запросы, инициированные Интернетом.Мы оцениваем формат запроса:

  • Если он соответствует нашей пользовательской схеме URL-адресов, проанализируйте URL-адрес, получите соответствующие операции и операции, а затем вызовите собственный метод.
  • Если он не соответствует нашей пользовательской схеме URL-адресов, мы перенаправляем его напрямую и запрашиваем реальную услугу.

В Интернете существует несколько способов отправки запросов URL:

  1. aЭтикетка
  2. location.href
  3. использоватьiframe.src
  4. Отправитьajaxпросить

эти методы,aЯрлыки требуют действий пользователя,location.hrefМожет привести к потере звонка при переходе на страницу, отправитьajaxСоответствующего метода перехвата запроса Android нет, поэтому используйтеiframe.srcэто схема, которая часто используется:

  • Android обеспечивает перехват метода shouldOverrideUrlLoading
  • UIWebView использует shouldStartLoadWithRequest, а WKWebView используетsolvePolicyForNavigationAction.

Этот метод существует с первых дней, и совместимость очень хорошая, но из-за метода на основе URL длина ограничена и не интуитивно понятна, формат данных ограничен, а создание запроса занимает много времени.

4.2.2 Внедрение JS API в Webview

Этот метод будет передавать интерфейс, предоставленный webView, и приложение внедрит интерфейс, связанный с Native, в объект JS Context (окно).Вообще говоря, имя метода в этом объекте такое же, как имя метода, связанного с Native, и Веб-сторона может напрямую глобальноwindowЗатем используйте этот открытый глобальный объект JS для вызова собственных методов.

Этот процесс будет более простым и интуитивно понятным, но есть проблемы с совместимостью, и этот метод будет использоваться в большинстве случаев.

Android (4.2+) обеспечиваетaddJavascriptInterfaceвпрыск:

// 注入全局JS对象
webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge");

class NativeBridge {
  private Context ctx;
  NativeBridge(Context ctx) {
    this.ctx = ctx;
  }

  // 增加JS调用接口
  @JavascriptInterface
  public void showNativeDialog(String text) {
    new AlertDialog.Builder(ctx).setMessage(text).create().show();
  }
}

Вы можете напрямую вызвать этот метод на веб-стороне:

window.NativeBridge.showNativeDialog('hello');

UIWebView в iOS предоставляетJavaSciptCore

WKWebView для iOS предоставляетWKScriptMessageHandler

4.3 Звонки с обратными вызовами

Два метода двусторонней связи между Native и Интернетом были упомянуты выше, но это по-прежнему односторонний процесс связи с одного конца.Например, с точки зрения Интернета: Интернет вызывает метод Native, а Native работает напрямую, но не может преобразовать результат. Возврат в сеть, но при реальном использовании часто необходимо вернуть результат операции, то есть обратный вызов JS.

Итак, работайте на противоположном конце и возвращайте результат, есть ввод и вывод для полного вызова, так как же этого добиться?

На самом деле это можно реализовать на базе предыдущей односторонней связи.Добавляем параметр к параметру при звонке на одном конце.callbackIdОтметьте соответствующий обратный вызов. После того, как одноранговый узел получит запрос на вызов, он выполнит фактическую операцию. Если имеется callbackId, одноранговый узел выполнит еще один вызов и вернет результат и callbackId. Одноранговый узел сопоставляет соответствующий обратный вызов в соответствии с callbackId и передает результат. Просто выполните его.

Видно, что это реально достигается за счет двух одноэлементных коммуникаций.

Возьмите Android в качестве примера для реализации вызовов JSB с обратными вызовами на веб-стороне:

// Web端代码:
<body>
  <div>
    <button id="showBtn">获取Native输入,以Web弹窗展现</button>
  </div>
</body>
<script>
  let id = 1;
  // 根据id保存callback
  const callbackMap = {};
  // 使用JSSDK封装调用与Native通信的事件,避免过多的污染全局环境
  window.JSSDK = {
    // 获取Native端输入框value,带有回调
    getNativeEditTextValue(callback) {
      const callbackId = id++;
      callbackMap[callbackId] = callback;
      // 调用JSB方法,并将callbackId传入
      window.NativeBridge.getNativeEditTextValue(callbackId);
    },
    // 接收Native端传来的callbackId
    receiveMessage(callbackId, value) {
      if (callbackMap[callbackId]) {
        // 根据ID匹配callback,并执行
        callbackMap[callbackId](value);
      }
    }
  };

	const showBtn = document.querySelector('#showBtn');
  // 绑定按钮事件
  showBtn.addEventListener('click', e => {
    // 通过JSSDK调用,将回调函数传入
    window.JSSDK.getNativeEditTextValue(value => window.alert('Natvie输入值:' + value));
  });
</script>
// Android端代码
webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge");

class NativeBridge {
  private Context ctx;
  NativeBridge(Context ctx) {
    this.ctx = ctx;
  }

  // 获取Native端输入值
  @JavascriptInterface
  public void getNativeEditTextValue(int callbackId) {
    MainActivity mainActivity = (MainActivity)ctx;
    // 获取Native端输入框的value
    String value = mainActivity.editText.getText().toString();
    // 需要注入在Web执行的JS代码
    String jsCode = String.format("window.JSSDK.receiveMessage(%s, '%s')", callbackId, value);
    // 在UI线程中执行
    mainActivity.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        mainActivity.webView.evaluateJavascript(jsCode, null);
      }
    });
  }
}

Вышеприведенный код просто реализует демонстрацию.Нажатие кнопки на веб-стороне получит значение поля ввода на нативной стороне и отобразит значение во всплывающем окне на веб-стороне, таким образом реализуя Web->Native Вызов JSB с обратным вызовом Аналогично, Native->Web — это тоже та же логика, с той лишь разницей, что обратный вызов сохраняется на стороне Native, поэтому я не буду здесь его подробно обсуждать.

Пять, JSBridge с открытым исходным кодом

Видно, что реализовать полноценный JSBridge довольно хлопотно, а еще нужно учитывать вопросы совместимости младших моделей и вопрос синхронных и асинхронных вызовов.К счастью, для нас уже есть JSBridge с открытым исходным кодом использовать напрямую:

кDSBridge-AndroidНапример:

// Web端代码
<body>
  <div>
    <button id="showBtn">获取Native输入,以Web弹窗展现</button>
  </div>
</body>
// 引入SDK
<script src="https://unpkg.com/dsbridge@3.1.3/dist/dsbridge.js"></script>
<script>
  const showBtn = document.querySelector('#showBtn');
  showBtn.addEventListener('click', e => {
    // 注意,这里代码不同:SDK在全局注册了dsBridge,通过call调用Native方法
    dsBridge.call('getNativeEditTextValue', '', value => {
      window.alert('Native输入值' + value);
    })
  });
</script>
// Android代码
// 使用dwebView替换原生webView
dwebView.addJavascriptObject(new JsApi(), null);

class JSApi {
  private Context ctx;
  public JSApi (Context ctx) {
    this.ctx = ctx;
  }

  @JavascriptInterface
  public void getNativeEditTextValue(Object msg, CompletionHandler<String> handler) {
    String value = ((MainActivity)ctx).editText.getText().toString();
    // 通过handler将value传给Web端,实现回调的JSB调用
    handler.completed(value);
  }
}

Как видите, код был значительно упрощен, а другие варианты использования можно посмотреть непосредственно в документации.

6. Резюме

К этому моменту у вас должно быть более глубокое понимание принципа и использования JSBridge.Вот краткое изложение статьи:

Гибридная разработка в настоящее время является основным технологическим вариантом для мобильной разработки, в котором двусторонняя связь между Native и Web неотделима.JSBridge

Среди них Native вызывает веб-сторону для выполнения кода JS непосредственно в контексте JS, а веб-сторона вызывает Native двумя способами.URL SchemaДругой — внедрить Api в контекст (окно) JS, где внедрение Api — лучший выбор в настоящее время. Полный вызов представляет собой двустороннюю связь, для которой требуется функция обратного вызова.Техническая реализация заключается в использовании двух односторонних коммуникаций.

Во-вторых, по сравнению с строительными колесами, более рекомендуется использовать текущий открытый исходный код jsbridge: dsbridge, jsbridge.

Ссылка на ссылку: