На этой странице рассказывается о различных методах и рекомендациях по созданию встроенного моста, также известного как мост JavaScript, для обеспечения связи между веб-контентом в WebView и хост-приложением для Android.
Это позволяет веб-разработчикам использовать JavaScript для доступа к функциям платформы, например камере, файловой системе или продвинутым аппаратным датчикам, которые обычно недоступны через стандартные веб-API.
Примеры использования
Реализация моста JavaScript позволяет использовать различные сценарии интеграции, в которых веб-контенту требуется более глубокий доступ к операционной системе Android. Вот несколько примеров:
- Интеграция с платформой. Запуск нативных компонентов интерфейса Android (например, запросов на использование биометрических данных,
BottomSheetDialog) с веб-страницы. - Производительность. Перенос ресурсоемких вычислительных задач на нативный код Java или Kotlin.
- Сохранение данных. Доступ к локальным зашифрованным базам данных или общим настройкам.
- Передача больших объемов данных – передача медиафайлов или сложных структур данных между приложением и веб-рендерером.
Механизмы коммуникации
В Android есть три основных поколения API для создания нативного моста. Все они по-прежнему доступны, но значительно различаются по безопасности, удобству использования и производительности.
Использовать addWebMessageListener (рекомендуется)
addWebMessageListener – самый современный и рекомендуемый способ обмена данными между веб-контентом и кодом нативного приложения. Он сочетает удобство использования интерфейса JavaScript с безопасностью системы обмена сообщениями.
Как это работает. Приложение добавляет прослушиватель с определенным именем и набором правил для разрешенных источников. После этого WebView гарантирует, что объект JavaScript будет присутствовать в глобальной области видимости (window.objectName) с момента начала загрузки страницы.
Инициализация. Чтобы WebView внедрил объект JavaScript до запуска любого скрипта, необходимо вызвать метод addWebMessageListener до перехода на страницу (например, вызвать WebViewCompat.navigate или loadUrl).
Основные функции
Безопасность и надежность. В отличие от устаревших API, этот метод требует
Set<String>allowedOriginRulesво время инициализации. Это основной способ установить доверие.Если вы укажете доверенный источник, например
https://example.com, WebView будет предоставлять внедренные объекты JavaScript только веб-страницам, загруженным из этого источника.Функция обратного вызова для нативного прослушивателя получает параметр
sourceOriginс каждым сообщением. Если мост поддерживает несколько разрешенных источников, вы можете использовать этот заголовок, чтобы проверить точный источник отправителя.Поскольку WebView строго проверяет источник на уровне платформы, ваше приложение может полагаться на сообщения, полученные от доверенного
sourceOrigin, и не выполнять тщательную проверку полезной нагрузки в большинстве стандартных реализаций.- WebView сопоставляет правила со схемой (HTTP/HTTPS), хостом и портом.
- WebView игнорирует пути. Например,
https://example.comпозволяет использоватьhttps://example.com/loginиhttps://example.com/home. - В WebView уайлд-карты строго ограничены началом хоста для субдоменов. Например,
https://*.example.comсоответствуетhttps://foo.example.com, но неhttps://example.com. Если вам нужно сопоставитьhttps://example.comи его субдомены, добавьте в белый список каждое правило происхождения отдельно (например,"https://example.com", "https://*.example.com"). Нельзя использовать подстановочные знаки для схемы или в середине домена.
Это позволяет использовать мост только для проверенных доменов и предотвращает выполнение нативного кода несанкционированным сторонним контентом или внедренными окнами iframe.
Поддержка нескольких фреймов. Работает во всех фреймах, соответствующих правилам для источников.
Потоки. Обратный вызов прослушивателя выполняется в основном потоке приложения (UI). Если мосту необходимо выполнять сложную обработку данных, синтаксический анализ JSON или поиск в базе данных, эту работу следует перенести в фоновый поток, чтобы избежать зависания интерфейса приложения с ошибкой "Приложение не отвечает" (ANR).
Двунаправленная связь. Когда веб-страница отправляет сообщение, приложение получает
JavaScriptReplyProxy, которое можно использовать для отправки сообщений обратно в этот фрейм. Вы можете сохранить объектreplyProxyи использовать его в любое время, чтобы отправлять странице любое количество сообщений, а не только отвечать на каждое отдельное сообщение, отправленное страницей. Если исходный фрейм переходит на другую страницу или уничтожается, сообщения, отправленные с помощьюpostMessage()на прокси-сервере, игнорируются.Инициация со стороны приложения. Хотя канал связи с приложением всегда должен инициироваться веб-страницей, нативное приложение может в одностороннем порядке запросить у веб-страницы начало этого процесса. Нативное приложение может взаимодействовать с веб-страницей с помощью
addDocumentStartJavaScript()(для выполнения кода JavaScript до загрузки страницы) илиevaluateJavaScript()(для выполнения кода JavaScript после загрузки страницы).
Ограничение. Этот API отправляет данные в виде строк или массивов byte[]. Более сложные структуры данных, например объекты JSON, необходимо сериализовать в один из этих форматов, а затем десериализовать на другой стороне, чтобы восстановить структуру данных.
Пример использования
Чтобы понять последовательность обмена двусторонними сообщениями, события должны происходить в следующем порядке:
- Запуск (приложение). Нативное приложение регистрирует прослушиватель с помощью
addWebMessageListenerи запускает навигацию по страницам (например, с помощьюWebViewCompat.navigateилиloadUrl). - Отправка сообщения (сайт). Код JavaScript на странице вызывает функцию
myObject.postMessage(message), чтобы начать обмен данными. - Получение и отправка ответов на сообщения (приложение). Приложение получает сообщение в обратном вызове прослушивателя и отвечает на него, используя предоставленный
replyProxy.postMessage(). - Получение ответа (сайт). Веб-страница получает асинхронный ответ в функции обратного вызова
myObject.onmessage().
Kotlin
val myListener = WebViewCompat.WebMessageListener { _, _, _, _, replyProxy -> // Handle the message from JS replyProxy.postMessage("Acknowledged!") } // Check whether the WebView version supports the feature. if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { val allowedOrigins = setOf("https://www.example.com") WebViewCompat.addWebMessageListener(webView, "myObject", allowedOrigins, myListener) }
Java
WebMessageListener myListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
// Handle the message from JS
replyProxy.postMessage("Acknowledged!");
};
// Check whether the WebView version supports the feature.
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
Set<String> allowedOrigins = Set.of("https://www.example.com");
WebViewCompat.addWebMessageListener(webView, "myObject", allowedOrigins, myListener);
}
Ниже приведен код JavaScript, который реализует клиентскую часть addWebMessageListener и позволяет веб-контенту получать сообщения от нативного приложения и отправлять собственные сообщения через прокси-сервер myObject.
myObject.onmessage = function(event) {
console.log("App says: " + event.data);
};
myObject.postMessage("Hello world!");
Используйте postWebMessage (альтернативный вариант)
В Android это решение было добавлено в качестве асинхронной альтернативы на основе обмена сообщениями, аналогичной window.postMessage в интернете.
Как это работает. Приложение использует WebViewCompat.postWebMessage, чтобы отправить полезную нагрузку в основной фрейм веб-страницы. Чтобы установить двусторонний канал связи, можно создать WebMessageChannel и передать один из его портов вместе с сообщением веб-контенту.
Характеристики
- Асинхронный. Как и в случае с
addWebMessageListener, этот метод использует асинхронный обмен сообщениями, благодаря чему веб-страница остается отзывчивой на действия пользователя, пока приложение обрабатывает данные в фоновом режиме. - С учетом источника. Вы можете указать
targetOrigin, чтобы WebView передавал данные только на надежный сайт.
Ограничения
- Область действия. Этот API ограничивает связь основным фреймом. Он не поддерживает прямую адресацию или отправку сообщений в iframe.
- Ограничения URI. Этот метод нельзя использовать для контента, загруженного с помощью URI
data:,file:илиloadData(), если в качестве целевого источника не указан символ "*". В этом случае сообщение сможет получить любая страница. - Риск подмены личности. Веб-контент не позволяет проверить личность отправителя. Сообщение, полученное веб-страницей, может быть отправлено из вашего нативного приложения или другого фрейма iframe.
Этот метод подходит, если вам нужен простой асинхронный канал для передачи строковых данных в более ранних версиях Android, которые не поддерживают addWebMessageListener.
addJavascriptInterface (устаревшая)
Самый старый метод предполагает внедрение экземпляра встроенного объекта непосредственно в WebView.
Как это работает. Вы определяете класс Kotlin или Java, добавляете к разрешенным методам аннотацию @JavascriptInterface и добавляете экземпляр класса в WebView с помощью addJavascriptInterface(Object, String).
Характеристики
- Синхронный. Среда выполнения JavaScript блокируется, пока метод в коде Android не вернет значение.
- Безопасность потоков. Система вызывает методы в фоновом потоке, поэтому на стороне Kotlin или Java требуется тщательная синхронизация.
- Угроза безопасности. По умолчанию
addJavascriptInterfaceдоступен для каждого фрейма в WebView, в том числе для iframe. В нем отсутствует контроль доступа на основе источника. Из-за асинхронного поведения WebView невозможно безопасно определить URL фрейма, который вызывает ваш интерфейс. Не используйте для проверки безопасности такие методы, какWebView.getUrl(), поскольку они не гарантируют точность и не указывают, какой именно фрейм отправил запрос.
Преобразование типов данных
При использовании addJavascriptInterface мост Java на основе Chromium преобразует типы данных между средой выполнения JavaScript и кодом приложения Android.
К параметрам методов и возвращаемым значениям применяются следующие правила приведения типов:
Сопоставление типов параметров (JavaScript – Java)
Когда JavaScript передает аргументы в аннотированный метод Java или Kotlin, мост преобразует значения JavaScript в соответствующие типы параметров Java:
| Тип параметра Java | Значение аргумента JavaScript | Принуждение |
|---|---|---|
byte, short, int, long |
Число (целое число) | Значения преобразуются в целевой целочисленный тип. Значения, выходящие за пределы диапазона, переносятся в соответствии со стандартными правилами преобразования числовых типов. |
byte, short, int, long |
NaN |
Принудительно преобразуется в 0. |
byte, short, int, long |
Infinity |
Принудительно устанавливает значение -1 для byte и short или Integer.MAX_VALUE и Long.MAX_VALUE для int и long. |
float, double |
Число | Приводит к соответствующему значению с плавающей запятой в Java. |
float, double |
NaN/Infinity |
Принудительно преобразуется в Float.NaN, Double.NaN, Float.POSITIVE_INFINITY или Double.POSITIVE_INFINITY. |
char |
Число (целое число) | Преобразовано в соответствующую кодовую точку Unicode. |
char |
Нецелое число, NaN, Infinity |
Принудительно преобразуется в \u0000. |
boolean |
true/false |
Приводится к типу Java true или false. |
boolean |
Число, строка, объект | Приводится к значению false (включая непустые строки и ненулевые числа). |
String |
Строка | Строковое значение сохраняется. |
String |
Число, логическое значение | Форматируется как строковое представление (например, "42", "true", "false"). |
String |
null/undefined |
null преобразуется в Java null; undefined преобразуется в строковый литерал "undefined". |
String |
Object, ArrayBuffer, TypedArray | Принудительно преобразует в строковый литерал "undefined". |
Массив примитивных типов (например, int[], byte[], boolean[]) или String[] |
Массив ([...]) |
Преобразует в одномерный массив Java целевого типа элемента. В разреженных массивах неназначенные индексы заполняются значениями по умолчанию (0, false, null). |
Массив примитивных типов (например, int[], byte[]) |
TypedArray (Int8Array, Uint8Array, Int32Array, Float64Array) |
Элементы преобразуются в соответствующий примитивный массив Java. |
Многомерный массив (например, int[][]) |
Вложенный массив ([[...]]) |
Не поддерживается. Параметры многомерного массива оцениваются как null. |
ArrayBuffer, DataView |
ArrayBuffer, DataView |
Не поддерживается в виде массивов. Экземпляры ArrayBuffer и DataView оцениваются как null. |
Object или специальный класс |
Объект JavaScript ({...}) |
Не поддерживается. Литералы произвольных объектов JavaScript в Java оцениваются как null. |
Object или специальный класс |
Оболочка внедренного объекта Java | Поддерживается (переход туда и обратно). Передает базовый экземпляр Java методу Java. Вызывает исключение JavaScript, если тип Java не соответствует сигнатуре параметра. |
Типы в рамке (например, Integer, Double, Boolean) |
Число, логическое значение | Не поддерживается. Примитивные типы в упаковке обрабатываются как непрозрачные объекты и оцениваются как null. |
| Любой примитивный тип | null/undefined |
Принудительно задает значения по умолчанию (0, 0.0, \u0000, false). |
Object, String, массив |
null |
Принудительное преобразование в Java null. |
Сопоставление типов возвращаемых значений (Java – JavaScript)
Когда аннотированный метод Java или Kotlin возвращает значение, мост преобразует его в тип JavaScript:
| Тип возвращаемого значения в Java | Значение JavaScript | Свойство typeof в JavaScript |
|---|---|---|
boolean |
true/false |
"boolean" |
byte, short, int, long, float, double |
Число | "number" |
char |
Число (кодовая точка Unicode) | "number" |
String (не нулевое значение) |
Строка | "string" |
String (null) |
undefined |
"undefined" |
void |
undefined |
"undefined" |
Массив Java (например, int[], String[]) |
undefined |
"undefined". Возвращаемые значения в виде массива не поддерживаются. Метод Java не выполняется, и возвращается значение undefined без исключения. |
| Объект Java или пользовательский тип (не null) | Контейнер объекта | "object". Создает оболочку JavaScript для экземпляра Java. Код JavaScript может вызывать любой общедоступный метод этого объекта, аннотированный с помощью @JavascriptInterface. |
Объект Java или специальный тип (null) |
null |
"object" |
Примитив в рамке (например, Integer, Double) |
Контейнер объекта | "object". Возвращается как непрозрачная оболочка объекта Java без доступных методов @JavascriptInterface, поэтому значение нельзя использовать в JavaScript. |
Доступность метода и участника
Мост JavaScript обеспечивает строгие правила доступа к элементам и их видимости, чтобы защитить от непреднамеренного выполнения кода:
- Поля недоступны. Поля Java (включая поля
publicиpublic final) недоступны из JavaScript и оцениваются какundefined. - Требование к аннотациям. В JavaScript доступны только методы, явно аннотированные с помощью
@JavascriptInterface. - Ограничения видимости: методы должны быть
public. Методыprivateиprotectedникогда не предоставляются JavaScript, даже если они имеют аннотацию@JavascriptInterface. - Статические методы. Статические методы, аннотированные с помощью
@JavascriptInterface, можно вызывать из JavaScript. - Наследование и переопределение. Аннотации
@JavascriptInterfaceне наследуются, когда подкласс переопределяет метод. Если подкласс переопределяет аннотированный метод из суперкласса, он должен явно включить аннотацию@JavascriptInterfaceв переопределенный метод, чтобы сделать его доступным для JavaScript. Непереопределенные общедоступные методы, унаследованные от суперкласса, остаются доступными, если они аннотированы в суперклассе. - Защита от рефлексии. Стандартные методы рефлексии Java (например,
getClass()) блокируются и вызывают исключение JavaScript, чтобы предотвратить уязвимости, связанные с удаленным выполнением кода. - Перегрузка методов. Поддерживаются перегруженные методы Java. Мост разрешает вызовы методов только на основе количества переданных аргументов и не учитывает их типы. При вызове перегруженного метода с недопустимым количеством аргументов возникает исключение JavaScript. Если у двух перегрузок одинаковое количество аргументов, одна из них будет выбрана произвольно.
Сводная информация о механизмах подачи жалоб
В таблице ниже приведено сравнение трех основных механизмов реализации встроенного моста:
| Метод | addWebMessageListener |
postWebMessage |
addJavascriptInterface |
|---|---|---|---|
| Реализация | Асинхронный (прослушиватель в основном потоке) | Асинхронный код | Синхронная |
| Безопасность | Максимальное (на основе белого списка) | Высокий (с учетом источника) | Низкий (без проверок источника) |
| Сложность | Средний | Средний | Простая |
| Направление | Двунаправленные | Двунаправленные | Сайт с приложением |
| Минимальная версия WebView | Версия 82 (и Jetpack Webkit 1.3.0) | Версия 45 (и Jetpack Webkit 1.1.0) | Все версии |
| Рекомендуется | Да | Нет | Нет |
передавать большие объемы данных;
При передаче больших объемов данных, например строк размером в несколько мегабайт или двоичных файлов, необходимо тщательно управлять памятью, чтобы избежать ошибок "Приложение не отвечает" (ANR) или сбоев на 32-разрядных устройствах. В этом разделе рассматриваются различные методы и ограничения, связанные с передачей больших объемов данных между хост-приложением и веб-контентом.
Как передавать двоичные данные с помощью массивов байтов
С помощью класса WebMessageCompat можно отправлять массивы byte[] напрямую, а не сериализовать двоичные данные в строки Base64. Поскольку Base64 добавляет к размеру данных примерно 33% избыточности, этот метод значительно эффективнее с точки зрения использования памяти и быстрее.
- Преимущества двоичных данных. Передавайте двоичные данные, например файлы изображений или аудио, между нативным приложением и веб-контентом.
- Ограничение. Даже при использовании массивов байтов система копирует данные через границу межпроцессного взаимодействия (IPC) между приложением и изолированным процессом, который WebView использует для отрисовки веб-контента. Однако для очень больших файлов это все равно требует значительного объема памяти.
В приведенных ниже примерах кода показано, как настроить addWebMessageListener в нативном приложении, чтобы получать сообщения, помеченные как WebMessageCompat.TYPE_ARRAY_BUFFER, и при необходимости отвечать на них двоичными данными, проверяя наличие WebViewFeature.MESSAGE_ARRAY_BUFFER.
Kotlin
fun setupWebView(webView: WebView) { if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { val listener = WebViewCompat.WebMessageListener { view, message, sourceOrigin, isMainFrame, replyProxy -> // Check if the received message is an ArrayBuffer if (message.type == WebMessageCompat.TYPE_ARRAY_BUFFER) { val binaryData: ByteArray = message.arrayBuffer // Process your binary data (image, audio, etc.) println("Received bytes: ${binaryData.size}") // Optional: Send a binary reply back to JavaScript. // This example sends a 3-byte array for simplicity. if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER)) { val replyBytes = byteArrayOf(0x01, 0x02, 0x03) replyProxy.postMessage(replyBytes) } } } // "myBridge" matches the window.myBridge in JavaScript WebViewCompat.addWebMessageListener( webView, "myBridge", setOf("https://example.com"), // Security: restrict origins listener ) } }
Java
public void setupWebView(WebView webView) {
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
WebViewCompat.WebMessageListener listener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
// Check if the received message is an ArrayBuffer
if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
byte[] binaryData = message.getArrayBuffer();
// Process your binary data (image, audio, etc.)
System.out.println("Received bytes: " + binaryData.length);
// Optional: Send a binary reply back to JavaScript.
// This example sends a 3-byte array for simplicity.
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER)) {
byte[] replyBytes = new byte[]{0x01, 0x02, 0x03};
replyProxy.postMessage(replyBytes);
}
}
};
// "myBridge" matches the window.myBridge in JavaScript
WebViewCompat.addWebMessageListener(
webView,
"myBridge",
Set.of("https://example.com"), // Security: restrict origins
listener
);
}
}
В приведенном ниже коде JavaScript показана клиентская реализация addWebMessageListener, позволяющая веб-контенту отправлять и получать двоичные данные (ArrayBuffer) в нативное приложение и из него с помощью прокси-сервера window.myBridge, добавленного в предыдущем примере.
// Function to send an image or binary buffer to the app
async function sendBinaryToApp() {
const response = await fetch('image.jpg');
const buffer = await response.arrayBuffer();
// Check if the injected bridge object exists
if (window.myBridge) {
// You can send the ArrayBuffer directly
window.myBridge.postMessage(buffer);
}
}
// Receiving binary data from the app
if (window.myBridge) {
window.myBridge.onmessage = function(event) {
if (event.data instanceof ArrayBuffer) {
console.log('Received binary data from App, length:', event.data.byteLength);
// Process the binary data (for example, as a Uint8Array)
const bytes = new Uint8Array(event.data);
console.log('First byte:', bytes[0]);
}
};
}
Эффективная загрузка больших объемов данных
Для очень больших файлов (более 10 МБ) используйте метод shouldInterceptRequest для потоковой передачи данных:
- Веб-страница инициирует вызов
fetch()к специальному URL-заполнителю. Например,https://app.local/large-file. - Приложение Android перехватывает этот запрос в
WebViewClient.shouldInterceptRequest. - Приложение возвращает данные в виде
InputStream.
Это позволяет передавать данные частями, а не загружать в память сразу весь полезный объем.
В приведенной ниже функции JavaScript показан клиентский код для эффективной загрузки большого двоичного файла из нативного приложения с помощью стандартного вызова fetch() к специальному URL-плейсхолдеру.
async function fetchBinaryFromApp() {
try {
// This URL doesn't need to exist on the internet
const response = await fetch('https://app.local/data/large-file.bin');
if (!response.ok) throw new Error('Network response was not okay');
// For raw binary data:
const arrayBuffer = await response.arrayBuffer();
console.log('Received binary data, size:', arrayBuffer.byteLength);
// Process buffer (for example, new Uint8Array(arrayBuffer))
/*
// OR for an image:
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);
document.getElementById('myImage').src = imageUrl;
*/
} catch (error) {
console.error('Fetch error:', error);
}
}
В приведенных ниже примерах кода показано, как в нативном приложении с помощью метода WebViewClient.shouldInterceptRequest на Kotlin и Java передать большой двоичный файл, перехватив пользовательский URL-заполнитель, запрошенный веб-контентом.
Kotlin
webView.webViewClient = object : WebViewClient() { override fun shouldInterceptRequest( view: WebView?, request: WebResourceRequest? ): WebResourceResponse? { val url = request?.url ?: return null // Check if this is our custom placeholder URL if (url.host == "app.local" && url.path == "/data/large-file.bin") { try { // 1. Get your data as an InputStream // (from Assets, Files, or a generated byte stream) val inputStream: InputStream = context.assets.open("my_data.pb") // 2. Define Response Headers (Crucial for CORS/Fetch) val headers = mutableMapOf<String, String>() headers["Access-Control-Allow-Origin"] = "*" // Allow fetch from any origin // 3. Return the response return WebResourceResponse( "application/octet-stream", // MIME type (for example, image/jpeg) "UTF-8", // Encoding 200, // Status Code "OK", // Reason Phrase headers, // Custom Headers inputStream // The actual data stream ) } catch (e: Exception) { // Handle exception } } return super.shouldInterceptRequest(view, request) } }
Java
webView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String urlPath = request.getUrl().getPath();
String host = request.getUrl().getHost();
// Check if this is our custom placeholder URL
if ("app.local".equals(host) && "/data/large-file.bin".equals(urlPath)) {
try {
// 1. Get your data as an InputStream
// (from Assets, Files, or a generated byte stream)
InputStream inputStream = getContext().getAssets().open("my_data.pb");
// 2. Define Response Headers (Crucial for CORS/Fetch)
Map<String, String> headers = new HashMap<>();
headers.put("Access-Control-Allow-Origin", "*"); // Allow fetch from any origin
// 3. Return the response
return new WebResourceResponse(
"application/octet-stream", // MIME type (for example, image/jpeg)
"UTF-8", // Encoding
200, // Status Code
"OK", // Reason Phrase
headers, // Custom Headers
inputStream // The actual data stream
);
} catch (Exception e) {
// Handle exception
}
}
return super.shouldInterceptRequest(view, request);
}
});
Соблюдайте рекомендации по безопасности
Чтобы защитить приложение и пользовательские данные, при реализации моста следуйте приведенным ниже рекомендациям.
Принудительное использование HTTPS. Чтобы вредоносный сторонний контент не мог вызывать встроенную логику приложения, разрешите обмен данными только с безопасными источниками.
Используйте правила происхождения. Чтобы обеспечить безопасность, строго определите
allowedOriginRulesи проверьтеsourceOrigin, предоставленный в обратном вызове сообщения. Не используйте подстановочный знак (*), который соответствует всем источникам, в качестве единственного правила для источников, если в этом нет крайней необходимости. Использование подстановочных знаков для субдоменов (например,*.example.com) по-прежнему допустимо и безопасно для сопоставления нескольких субдоменов (например,foo.example.com,bar.example.com).Примечание. Правила происхождения защищают от вредоносных сторонних сайтов и скрытых фреймов, но не от уязвимостей межсайтового скриптинга (XSS) в пределах вашего доверенного домена. Например, если на вашей странице показывается пользовательский контент и она уязвима для сохраненных XSS, злоумышленник может выполнить скрипт, который будет действовать как ваш доверенный источник. Рекомендуем проверять полезную нагрузку сообщений перед выполнением важных операций на платформе.
Минимизируйте поверхность атаки. Предоставляйте доступ только к тем методам или данным, которые необходимы веб-странице.
Проверка функций во время выполнения. Новые API моста, в том числе
addWebMessageListener, входят в библиотеку Jetpack Webkit. Поэтому всегда проверяйте, поддерживается ли ваш регион, с помощьюWebViewFeature.isFeatureSupported(), прежде чем звонить.