PostMessage для TWA, PostMessage для TWA

Сайед Эль-Абади
Sayed El-Abady

Из Chrome 115 Trusted Web Activity (TWA) может отправлять сообщения с помощью postMessages. В этой статье описывается настройка, необходимая для связи между вашим приложением и Интернетом.

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

Чтобы следовать этому руководству, вам понадобится:

  • Чтобы добавить последнюю версию библиотеки androidx.browser (минимум v1.6.0-alpha02) в файл build.gradle.
  • Версия Chrome 115.0.5790.13 или более поздняя для TWA.

Метод window.postMessage() безопасно обеспечивает связь между источниками между объектами Window . Например, между страницей и всплывающим окном, которое она создала, или между страницей и встроенным в нее iframe.

Обычно сценариям на разных страницах разрешен доступ друг к другу только в том случае, если страницы, на которых они происходят, имеют один и тот же источник, используют один и тот же протокол, номер порта и хост (также известное как политика одного и того же происхождения ). Метод window.postMessage() предоставляет управляемый механизм для безопасного взаимодействия между различными источниками. Это может быть полезно для реализации приложений чата, инструментов для совместной работы и т. д. Например, приложение чата может использовать postMessage для отправки сообщений между пользователями, находящимися на разных веб-сайтах. Использование postMessage в доверенных веб-действиях (TWA) может быть немного сложным. В этом руководстве рассказывается, как использовать postMessage в клиенте TWA для отправки сообщений на веб-страницу и получения сообщений с нее.

Добавьте приложение в веб-проверку

Чтобы postMessage работал, требуется действительная связь между веб-сайтом и приложением Trusted Web Activity, запускающим этот сайт. Это можно сделать с помощью Digital Asset Links (DAL), добавив имя пакета приложения в файл assetlinks.json с отношением как use_as_origin , так что это будет следующим образом:

[{
  "relation": ["delegate_permission/common.use_as_origin"],
  "target" : { "namespace": "android_app", "package_name": "com.example.app", "sha256_cert_fingerprints": [""] }
}]

Обратите внимание, что при настройке источника, связанного с TWA, необходимо указать источник для поля MessageEvent.origin , но postMessage можно использовать для связи с другими сайтами, которые не включают ссылку на цифровые активы. Например, если вы являетесь владельцем www.example.com вам придется доказать это через DAL, но вы можете общаться с любыми другими веб-сайтами, например www.wikipedia.org .

Добавьте PostMessageService в свой манифест.

Чтобы получать сообщение postMessage , вам необходимо настроить службу. Для этого добавьте PostMessageService в манифест Android:

<service android:name="androidx.browser.customtabs.PostMessageService"
android:exported="true"/>

Получите экземпляр CustomTabsSession.

После добавления службы в манифест используйте класс CustomTabsClient для привязки службы. После подключения вы можете использовать предоставленный клиент для создания нового сеанса следующим образом. CustomTabsSession — это основной класс для обработки API postMessage. Следующий код показывает, как после подключения службы клиент используется для создания нового сеанса, этот сеанс используется для postMessage :

private CustomTabsClient mClient;
private CustomTabsSession mSession;

// We use this helper method to return the preferred package to use for
// Custom Tabs.
String packageName = CustomTabsClient.getPackageName(this, null);

// Binding the service to (packageName).
CustomTabsClient.bindCustomTabsService(this, packageName, new CustomTabsServiceConnection() {
 @Override
 public void onCustomTabsServiceConnected(@NonNull ComponentName name,
     @NonNull CustomTabsClient client) {
   mClient = client;

   // Note: validateRelationship requires warmup to have been called.
   client.warmup(0L);

   mSession = mClient.newSession(customTabsCallback);
 }

 @Override
 public void onServiceDisconnected(ComponentName componentName) {
   mClient = null;
 }
});

Теперь вам интересно, что это за экземпляр customTabsCallback верно? Мы создадим это в следующем разделе.

Создать обратный вызов CustomTabs

CustomTabsCallback — это класс обратного вызова для CustomTabsClient, позволяющий получать сообщения о событиях на их пользовательских вкладках. Одним из этих событий является onPostMessage , и оно вызывается, когда приложение получает сообщение из Интернета. Добавьте обратный вызов клиенту, чтобы инициализировать канал postMessage для начала связи, как показано в следующем коде.

private final String TAG = "TWA/CCT-PostMessageDemo";
private Uri SOURCE_ORIGIN = Uri.parse("my-app-origin-uri");
private Uri TARGET_ORIGIN = Uri.parse("website-you-are-communicating-with");

// It stores the validation result so you can check on it before requesting postMessage channel, since without successful validation it is not posible to use postMessage.
boolean mValidated;

CustomTabsCallback customTabsCallback = new CustomTabsCallback() {

// Listens for the validation result, you can use this for any kind of
// logging purposes.
 @Override
 public void onRelationshipValidationResult(int relation, @NonNull Uri requestedOrigin,
     boolean result, @Nullable Bundle extras) {
   // If this fails:
   // - Have you called warmup?
   // - Have you set up Digital Asset Links correctly?
   // - Double check what browser you're using.
   Log.d(TAG, "Relationship result: " + result);
   mValidated = result;
 }

// Listens for any navigation happens, it waits until the navigation finishes
// then requests post message channel using
// CustomTabsSession#requestPostMessageChannel(sourceUri, targetUri, extrasBundle)

// The targetOrigin in requestPostMessageChannel means that you can be certain their messages are delivered only to the website you expect.
 @Override
 public void onNavigationEvent(int navigationEvent, @Nullable Bundle extras) {
   if (navigationEvent != NAVIGATION_FINISHED) {
     return;
   }

   if (!mValidated) {
     Log.d(TAG, "Not starting PostMessage as validation didn't succeed.");
   }

   // If this fails:
   // - Have you included PostMessageService in your AndroidManifest.xml ?
boolean result = mSession.requestPostMessageChannel(SOURCE_ORIGIN, TARGET_ORIGIN, new Bundle());
   Log.d(TAG, "Requested Post Message Channel: " + result);
 }

// This gets called when the channel we requested is ready for sending/receiving messages.
 @Override
 public void onMessageChannelReady(@Nullable Bundle extras) {
   Log.d(TAG, "Message channel ready.");

   int result = mSession.postMessage("First message", null);
   Log.d(TAG, "postMessage returned: " + result);
 }

// Listens for upcoming messages from Web.
 @Override
 public void onPostMessage(@NonNull String message, @Nullable Bundle extras) {
   super.onPostMessage(message, extras);
// Handle the received message.

 }
};

Общение через Интернет

Теперь мы можем отправлять и получать сообщения из нашего хост-приложения. Как нам сделать то же самое через Интернет? Связь должна начинаться с хост-приложения, затем веб-страница должна получить порт из первого сообщения. Этот порт используется для обратной связи. Ваш файл JavaScript будет выглядеть примерно так:

window.addEventListener("message", function (event) {
  // We are receiveing messages from any origin, you can check of the origin by
  // using event.origin

  // get the port then use it for communication.
  var port = event.ports[0];
  if (typeof port === 'undefined') return;

  // Post message on this port.
  port.postMessage("Test")

  // Receive upcoming messages on this port.
  port.onmessage = function(event) {
    console.log("[PostMessage1] Got message" + event.data);
  };
});

Полный образец вы можете найти здесь.

Фото Джоанны Косинской на Unsplash