Что нужно знать фронтенд-инженерам о WebView

Webkit
Что нужно знать фронтенд-инженерам о WebView

| 导语В настоящее время при разработке мобильных приложений H5 взаимодействие с Native незаменимо. В Native контейнером размещения H5 является WebView, и его ядром является использование элемента управления WebView для реализации URL-адреса загрузки.

Концепция WebView

WebViewиспользуется для отображения веб-страницviewКомпонент, который является основой для запуска вашего собственного браузера или отображения онлайн-контента в вашей теме. использоватьWebkitМеханизм рендеринга для отображения и поддерживает перемотку вперед и назад на основе истории просмотров, увеличение и уменьшение масштаба и многое другое.

Проще говоряWebViewЭто высокопроизводительный встроенный мобильный телефон.WebkitБраузер ядра, компонент, упакованный в SDK. Однако здесь нет адресной строки и панели навигации, только простое отображение веб-интерфейса.

Выше описан разработчиком клиента, а с точки зрения фронтенд разработчика ощущения после использования такие:

WebViewЭто может быть просто понято как страница вiframe. Роднойappа такжеWebViewВзаимодействие можно просто рассматривать как страницу и страницу.iframeвзаимодействие со страницей. как страницы и внутри страницiframeподелиться однимWindowтакой же, родной иWebViewТакже поделился набором нативных методов.

Поскольку мы использовалиWebViewнестиH5, то необходимоNativeвзаимодействие междуWebViewСтраницы размещеныJSа такжеNativeЧтобы общаться, мы делаем «мост» этого общения какJSBridge. Если вы участвовали во встроенном браузере WeChatH5развития, вы найдете частое явление, называемоеWeixinJSBridge.

JSBridge

JSBridgeПроще говоря, основнойJavaScript 提供调用 Native 功能的接口, чтобы "внешняя часть" в гибридной разработке могла легко использовать адресное расположение, камеру и даже оплату и т.д.NativeФункция.

Поскольку это «просто», цель JSBridge определенно не только в том, чтобы «вызвать нативную функцию» как простую и широкую. На самом деле, JSBridge, как и значение слова «мост» в его названии, является мостом между нативным и не-нативным.构建 Native 和非 Native 间消息通信的通道,И является双向通信的通道.так называемый双向通信的通道:

  • JS отправляет сообщения в Native: вызывает связанные функции, уведомляет Native о текущем состоянии JS и т. д.

  • Native отправляет сообщения в JS: отслеживание результатов вызова, push-сообщения, уведомление JS о текущем статусе Native и т. д.

JavaScript работает в отдельном JS-контексте (например, движке WebView Webkit, JCore). Из-за естественной изоляции этих контекстов от собственной операционной среды мы можем сравнить эту ситуацию с обменом данными RPC (удаленный вызов процедур, удаленный вызов процедур) и рассматривать каждый взаимный вызов между Native и JavaScript как вызов RPC. Таким образом, мы можем проектировать и реализовывать обычным способом RPC.

В дизайне JSBridge внешний интерфейс можно рассматривать как клиент RPC, а собственный конец можно рассматривать как серверный конец RPC, поэтому основная логика, которую должен реализовать JSBridge, выглядит следующим образом:通信调用(Native 与 JS 通信а также句柄解析调用. (Если вы работаете с интерфейсом и не знакомы с RPC, вы также можете сравнить этот процесс с процессом JSONP.)

Из вышеприведенного анализа видно, чтоJSBridgeОсновные функции и обязанности, затем анализAndroid WebViewа такжеiOS WebViewПринцип реализации связи между Native и JS в .

Android WebView

До Android 4.4:Android WebViewВ низкой версии и старшей версии ядро ​​​​различных версий webkit (поскольку многие новые функции H5 не поддерживаются на машинах Android с версией Android ниже 4.4) Android 4.4 после: Первоначально основан наWebkitизWebViewначать на основеChromiumядро, это изменение значительно улучшаетWebViewпроизводительность компонентов иHTML5, CSS3, JavaScriptслужба поддержки. Тем не менее, его API не сильно изменился: в нем представлено лишь небольшое количество новых API, но он совместим с более ранними версиями и не требует внесения серьезных изменений.

В Android WebView для реализации JS, вызывающего Java, есть 3 метода:

  • JavascriptInterface
  • WebViewClient.shouldOverrideUrlLoading()
  • WebChromeClient.onXXX()

1. JavascriptИнтерфейс

Это официальное решение для JS и Native-коммуникаций, предоставляемое Android.

Во-первых, нативная сторона должна реализовать такой класс и вызвать его для JavaScript.

public class WebAppInterface {
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

тогда поставь этоWebAppInterfaceКласс со следующим кодом добавляется в JavaScriptInterface WebView.

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android"); 
// 这里的Android会被当做一个变量,注入到页面的window中。

Затем вы можете вызвать Native в JS.

function showAndroidToast(toast) {
    Android.showToast(toast);
}

2. WebViewClient.shouldOverrideUrlLoading()

Цель этого метода — перехватить все URL-схемы WebView.

URL SchemeаналогичныйURLСсылка для удобстваappНапрямую называть друг друга разработанными, формальными и обычнымиURLприблизительно, главное отличиеprotocolа такжеhostОбычно на заказ.

перехватыватьURL SchemeОсновной процесс:Webкаким-либо образом заканчиваться (например,iframe.src/location.href)ОтправитьURL Schemeпросьба, послеNativeперехватил запрос иURL Scheme(включая параметры, которые он принимает) для выполнения связанных операций.

Страница может создать специальную схему URL-адреса для запуска,shouldOverrideUrlLoadingперехватыватьURLПосле оценки его формата, затемNativeОн может выполнять свою собственную логику.

public class CustomWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(
      WebView view,
      String url
     ) {
      if (isJsBridgeUrl(url)) {
        // JSbridge的处理逻辑
        return true;
      }
      return super.shouldOverrideUrlLoading(view, url);
    }
}

3. WebChromeClient.onXXX()

Модифицируя некоторые методы исходного окна браузера, затем перехватывая параметры фиксированных правил, а затем раздавая их соответствующим методам в Java для обработки

  • оповещение, может быть WebViewWebChromeClient.onJsAlert()монитор
  • подтвердить, который может использоваться WebViewWebChromeClient.onJsConfirm()монитор
  • console.log, к которому можно получить доступ с помощью WebViewWebChromeClient.onConsoleMessage()монитор
  • подсказка, к которой может получить доступ WebViewWebChromeClient.onJsPrompt()монитор

prompt — это простой пример, веб-страница вызываетprompt()метод, клиент Android прослушиваетWebChromeClient.onJsPrompt()События, перехватывать входящие параметры, если параметры соответствуют определенной спецификации протокола, то парсить параметры и кидать их на последующую Яву для обработки.

window.prompt(message, value);

WebChromeClient.onJsPrompt() будет вызван обратно. Значение параметра сообщения метода onJsPrompt() точно соответствует значению сообщения метода JS window.prompt().

public class CustomWebChromeClient extends WebChromeClient {
  @Override
  public boolean onJsPrompt(
    WebView view,
    String url,
    String message,
    String defaultValue,
    JsPromptResult result
    ) {
        // 处理JS 的调用逻辑
        result.confirm();
        return true;
  }
}

Java вызывает JavaScript

Android в Kitkat (4.4) может использовать loadUrl только как фрагмент кода JavaScript.

webView.loadUrl("javascript:" + javaScriptString);

Версия после Kitkat также может быть реализована с помощью метода AssessmentJavascript:

webView.evaluateJavascript(javaScriptString, new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
      // native代码
    }
});

IOS WebView

In apps that run in iOS 8 and later, use the WKWebView class instead of using UIWebView. Additionally, consider setting the WKPreferences property javaScriptEnabled to NO if you render files that are not supposed to run JavaScript.

До IOS8 WebView Apple использовал UIWEBVIEW, UiWebview имеет несколько вопросов в течение длительного времени:

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

На WWDC 2014 iOS8 представила WKWebView, основную часть современного Webkit API в приложениях iOS 8 и OS X Yosemite. Он заменяет UIWebView в UIKit и WebView в AppKit, предоставляя унифицированный межплатформенный API. Имеет частоту обновления прокрутки 60 кадров в секунду, встроенные жесты, эффективные каналы обмена информацией между приложениями и веб-сайтами и тот же движок JavaScript, что и Safari.

JavaScript ↔︎ Быстрый механизм диалога

Использование пользовательских скриптов для внедрения JavaScript

WKUserScript допускает внедрение на страницу до или после загрузки тела. Эта мощная функция позволяет управлять веб-контентом безопасным и уникальным способом на странице.

Простой пример: пользовательский скрипт, в котором пользователь меняет фон, вставляется на веб-страницу:

let source = "document.body.style.background = #777";
// 注入脚本 在文档加载完成后执行
let userScript = WKUserScript()
let userScript = WKUserScript(source: source, injectionTime: .AtDocumentEnd, forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(userScript)

let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
self.webView =WKWebView(frame: self.view.bounds, configuration: configuration)

Объекты могут быть инициализированы в исходной форме JavaScript, а также могут быть инициализированы с указанием того, вводить ли их перед загрузкой или в конце, а также влияет ли сценарий на этот макет или только на основной макет. Таким образом, пользовательский скрипт добавляется вWKUserContentControllerв и сWKWebViewConfigurationатрибут переданWKWebViewво время инициализации.

Этот пример можно легко распространить на более продвинутые методы модификации страницы, такие как удаление рекламы, скрытие комментариев и т. д.

Message Handlers

Используйте следующий код для связи с Native

window.webkit.messageHandlers.{NAME}.postMessage()

HandlerИмя можно передатьWKScriptMessageHandlerв соглашенииaddScriptMessageHandler()Настройки функций интерфейса:

class NotificationScriptMessageHandler: NSObject, WKScriptMessageHandler {
  func userContentController(
    userContentController: WKUserContentController,
    didReceiveScriptMessage message: WKScriptMessage!
   ) {
     println(message.body)
  }
}
let userContentController = WKUserContentController()
let handler = NotificationScriptMessageHandler()
userContentController.addScriptMessageHandler(handler, name: "notification")

Поэтому, когда в приложение приходит уведомление, скажем, о создании нового объекта на странице, соответствующая информация может быть передана следующим образом:

window.webkit.messageHandlers.notification.postMessage({body: '发送给Native'});

Добавьте пользовательские сценарии для прослушивания веб-событий и используйте обработчики сообщений для передачи информации обратно в приложение.

Суммировать

Принцип общения такойJSBridgeСуть реализации может быть реализована по-разному, но она остается неизменной. Здесь рекомендуемая реализация выглядит следующим образом:

  • JavaScriptпередачаNativeРекомендуемое использование注入 APIПуть. (Игнорируется iOS6, используется ниже Android 4.2WebViewClientизonJsPromptСпособ. )

  • NativeпередачаJavaScriptЗатем непосредственно выполните сваркуJavaScriptкод подойдет.

Для других методов, таких как React Native, апплет WeChat, методы связи аналогичны описанным выше и оптимизированы в соответствии с реальной ситуацией.

В качестве примера возьмем сторону React Native для iOS: JavaScript работает в JCore, Фактически, так же, как и выше, JavaScript можно использовать для вызова собственных функций путем внедрения API. Однако React Native не предназначен для прямого вызова Object-C из JavaScript.为了与 Native 开发里事件响应机制一致, разработаны, чтобы需要在 Object-C 去调 JavaScript 时才通过返回值触发调用. Принцип в основном одинаково, но реализация отличается.