JS - нативный коммуникационный мост во флаттере

В продолжение моей статьи, объясняющей, как создавать коммуникационные мосты в Android и iOS, я подумал, что было бы неплохо сделать то же самое для Flutter. Хотя может показаться, что это несложное дело, вы скоро поймете, что для того, чтобы эта функция заработала, потребуется немного поработать.

Прежде всего, важно понимать, что (на момент написания этой статьи) Flutter НЕ встроен в поддержку встроенных WebView. Это означает, что в отличие от собственного приложения в Kotlin или Swift, где вы можете просто создать экземпляр компонента WebView, вы не можете просто добавить компонент WebView в свое приложение из коробки.

После создания нового проекта Flutter нам нужно использовать пакет webview_flutter, чтобы иметь возможность использовать WebView. Мы добавим зависимость в наш файл pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^1.0.7

Затем нам нужно запустить Pub get или в терминале:

flutter pub get

Далее нам нужно импортировать пакет в наш файл main.dart:

import 'package:webview_flutter/webview_flutter.dart';

Если вы еще не очистили код начального проекта, сейчас самое подходящее время для этого. После того, как вы удалите все комментарии, плавающую кнопку действия и все, что с ней связано, у вас останется это (я добавил текстовый виджет только для показа):

Что даст вам такой результат:

Добавление нашего локального файла

Поскольку мы будем использовать локальный html-файл со встроенным в него кодом JavaScript, нам необходимо создать его в нашем проекте. Все локальные ресурсы в приложении Flutter должны находиться в каталоге assets. Создайте каталог ресурсов в основной иерархии проекта, щелкнув правой кнопкой мыши на левой боковой панели и выбрав «Создать» → «Каталог». Этот каталог должен быть дочерним по отношению к каталогу android.

Затем продолжайте и создайте index.html внутри каталога ресурсов.

Вы заметите, что мы написали два метода в разделе JavaScript нашего html:

  1. fromFlutter - это метод, который мы будем вызывать из Flutter со строкой, представляющей новый заголовок страницы.
  2. sendBack - это метод, который мы будем вызывать для обратной связи с Flutter. В нем мы отправляем строковое сообщение.

Мы перейдем к содержимому sendBack через минуту, но перед этим мы должны настроить наш WebView в нашем приложении.

✋ Не забудьте добавить index.html в свой pubspec.yaml в разделе ресурсов (используйте правильный отступ).

Настройка WebView

Поскольку мы уже импортировали пакет в наш файл main.dart, нам нужно заменить виджет Text на виджет WebView.

Мы обернули наш WebView виджетом Scaffold (его назначение будет раскрыто позже в статье), но давайте сосредоточимся на различных полях виджета WebView, показанного выше:

  • initialUrl - здесь мы можем определить, на какой URL-адрес указывает WebView. Здесь мы решили ни на что не указывать, так как мы собираемся загрузить наш локальный html файл.
  • onWebViewCreated - это обратный вызов, который мы получаем от пакета после создания WebView. Поскольку мы хотим сохранить экземпляр контроллера, полученный в результате этого обратного вызова, мы создали закрытый член для его сохранения (_controller)

Вы также заметите, что мы создали метод под названием _loadHtmlFromAssets, который, как следует из его имени, загрузит наш локальный файл HTML в WebView.

Внутри этого метода мы используем наш частный экземпляр WebViewController, _controller, и его открытый метод loadUrl для загрузки нашего локального файла HTML. Из-за логики этого метода он выполняется асинхронно.

Если мы запустим наше приложение, мы получим следующее:

Давайте общаться (Flutter - ›WebView)

Теперь давайте добавим некоторые функции для вызова метода fromFlutter, который мы определили в нашем локальном html-файле. Для этого мы добавим плавающую кнопку действия (или FAB) в наш макет и подключим ее метод onPressed для вызова метода fromFlutter. Это также причина использования виджета Scaffold, поэтому мы можем легко добавить FAB.

Чтобы выполнять вызовы из Flutter в загруженный HTML-код, мы используем метод AssessmentJavascript. Чтобы использовать его, мы должны добавить в наш WebView еще одно свойство, называемое javascriptMode. Выше мы установили неограниченный доступ. Если мы не установим его, мы не сможем взаимодействовать между Flutter и WebView.

Обратное общение (WebView - ›Flutter)

Помните, как я сказал, что мы поговорим о содержимом нашего метода sendBack? Что ж, сейчас самое время сделать это.

В методе sendBack мы используем объект под названием messageHandler и прикрепленный к нему метод под названием postMessage. Если вы когда-либо создавали коммуникационный мост в собственном приложении, то вы знаете, что после его настройки вы добавляете объект к глобальному объекту окна на уровне Javascript, который будет использоваться для связи. Вы можете назвать этот объект как угодно, если вы будете ссылаться на него, когда делаете вызовы из Javascript в свое собственное приложение.

Как этот объект добавлен в слой Javascript в нашем приложении? Добавив атрибут JavascriptChannels в наш виджет WebView:

Мы определили JavascriptChannel с именем и обработчиком onMessageReceived. Имя, которое мы дали этому каналу, messageHandler, - это имя, которое мы используем для связи из локального файла html, который мы загрузили на наш собственный уровень.

Для зорких глаз вы, вероятно, заметили, что была добавлена ​​новая частная переменная _scaffoldKey. Это потому, что нам нужно было добавить ключ к нашему виджету Scaffold, чтобы мы могли отображать Snackbar.

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



Два последних момента, о которых следует помнить:

  1. Не работает метод оповещения в пакете webview_flutter
  2. Чтобы использовать пакет в iOS, вы должны добавить следующий ключ в свой файл info.plist:
<key>io.flutter.embedded_views_preview</key><string>yes</string>

Другие источники, которые могут оказаться полезными, если вы хотите узнать больше о Flutter и WebViews:

Следите за сообществом Flutter в Twitter за всем, что происходит в 🌎 Flutter: https://www.twitter.com/FlutterComm