TWA için PostMessage

Sayed El-Abady
Sayed El-Abady

Chrome 115'ten itibaren Güvenilir Web Etkinlikleri (TWA), postMessage'i kullanarak mesaj gönderebilir. Bu dokümanda, uygulamanız ile web arasında iletişim kurmak için gereken kurulum adımlarına yer verilmiştir.

Bu kılavuzun sonunda:

  • İstemci ve web içeriği doğrulamasının işleyiş şeklini anlayın.
  • İstemci ile web içeriği arasındaki iletişim kanalını nasıl başlatacağınızı öğrenin.
  • Web içeriklerine nasıl mesaj göndereceğinizi ve web içeriklerinden nasıl mesaj alacağınızı öğrenin.

Bu kılavuza uymak için şunlara ihtiyacınız vardır:

  • build.gradle dosyanıza en son androidx.browser (min v1.6.0-alpha02) kitaplığını eklemek için:
  • TWA için Chrome 115.0.5790.13 veya sonraki sürümler.

window.postMessage() yöntemi, Window nesneleri arasında kaynaklar arası iletişimi güvenli bir şekilde etkinleştirir. Örneğin, bir sayfa ile oluşturduğu pop-up arasında veya bir sayfa ile içine yerleştirilmiş bir iframe arasında.

Genellikle, farklı sayfalardaki komut dosyalarının birbirine erişmesine yalnızca aynı kaynaktan geldikleri, aynı protokolü, bağlantı noktası numarasını ve ana makineyi paylaştıkları durumlarda izin verilir (aynı kaynak politikası olarak da bilinir). window.postMessage() yöntemi, farklı kaynaklar arasında güvenli bir şekilde iletişim kurmak için kontrollü bir mekanizma sağlar. Bu, sohbet uygulamaları, ortak çalışma araçları ve diğer uygulamaları uygulamak için yararlı olabilir. Örneğin, bir sohbet uygulaması farklı web sitelerinde bulunan kullanıcılar arasında mesaj göndermek için postMessage kullanabilir. Güvenilir Web Etkinlikleri (TWA)'nde postMessage kullanmak biraz karmaşık olabilir. Bu kılavuzda, web sayfasına mesaj göndermek ve web sayfasından mesaj almak için TWA istemcisinde postMessage'i nasıl kullanacağınız açıklanmaktadır.

Uygulamayı web doğrulamasına ekleme

postMessage API, bir kaynak ve bir hedef kaynak olmak üzere iki geçerli kaynağın birbiriyle iletişim kurmasına olanak tanır. Android uygulamasının hedef kaynağa mesaj gönderebilmesi için hangi kaynak kaynağa eşdeğer olduğunu belirtmesi gerekir. Bu işlem, Dijital Öğe Bağlantıları (DAL) ile yapılabilir. Bunun için uygulamanın paket adını assetlinks.json dosyanıza use_as_origin ilişkisiyle eklemeniz gerekir. Böylece dosyanız aşağıdaki gibi görünür:

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

TWA ile ilişkili kaynakta kurulum sırasında MessageEvent.origin alanı için bir kaynak sağlamanız gerektiğini ancak postMessage'nin, Dijital Öğe Bağlantısı içermeyen diğer sitelerle iletişim kurmak için kullanılabileceğini unutmayın. Örneğin, www.example.com alanı size aitse bunu DAL aracılığıyla kanıtlamanız gerekir, ancak başka web siteleriyle de (örneğin, www.wikipedia.org) iletişim kurabilirsiniz.

PostMessageService'i manifest dosyanıza ekleme

postMessage iletişimlerini almak için hizmeti kurmanız gerekir. Bunun için Android manifest dosyanıza PostMessageService kodunu eklemeniz gerekir:

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

CustomTabsSession örneği alma

Hizmeti manifest dosyasına ekledikten sonra, hizmeti bağlamak için CustomTabsClient sınıfını kullanın. Bağlandıktan sonra, sağlanan istemciyi kullanarak aşağıdaki şekilde yeni bir oturum oluşturabilirsiniz. CustomTabsSession, postMessage API'yi işleme konusunda temel sınıftır. Aşağıdaki kod, hizmet bağlandıktan sonra istemcinin yeni bir oturum oluşturmak için nasıl kullanıldığını, bu oturumun postMessage için nasıl kullanıldığını gösterir:

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;
 }
});

Şimdi bu customTabsCallback örneğinin ne olduğunu merak ediyorsunuz, değil mi? Bunu bir sonraki bölümde oluşturacağız.

CustomTabsCallback oluşturma

CustomTabsCallback, CustomTabsClient'ın özel sekmelerindeki etkinliklerle ilgili mesajlar alması için bir geri çağırma sınıfıdır. Bu etkinliklerden biri onPostMessage'tür ve uygulama web'den mesaj aldığında çağrılır. İletişimi başlatmak için postMessage kanalını başlatmak üzere aşağıdaki kodda gösterildiği gibi geri çağırma işlevini istemciye ekleyin.

private final String TAG = "TWA/CCT-PostMessageDemo";

// The origin the TWA is equivalent to, where the Digital Asset Links file
// was created with the "use_as_origin" relationship.
private Uri SOURCE_ORIGIN = Uri.parse("https://source-origin.example.com");

// The origin the TWA will communicate with. In most cases, SOURCE_ORIGIN and
// TARGET_ORIGIN will be the same.
private Uri TARGET_ORIGIN = Uri.parse("https://target-origin.example.com");

// It stores the validation result so you can check on it before requesting
// postMessage channel, since without successful validation it is not possible
// 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.
    }
};

Web'den iletişim kurma

Artık ana makine uygulamamızdan mesaj gönderip alabiliyoruz. Aynı şeyi web'den nasıl yapacağız? İletişimin ana makine uygulamasından başlaması, ardından web sayfasının ilk mesajdan itibaren bağlantı noktasını alması gerekir. Bu bağlantı noktası tekrar iletişim kurmak için kullanılır. JavaScript dosyanız aşağıdaki örneğe benzer:

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);
  };
});

Tam bir örneği burada bulabilirsiniz.

Fotoğraf: Joanna Kosinska, Unsplash