TWA için PostMessage

Sayed El-Abady
Sayed El-Abady

Chrome 115 sürümünden itibaren Güvenilir Web Etkinlikleri (TWA) postMessage kullanarak ileti gönderebilir. Bu dokümanda, uygulamanız ile web arasında iletişim kurmak için gereken kurulum adım adım açıklanmaktadır.

Bu kılavuzun sonunda:

  • İstemci ve web içeriği doğrulamasının nasıl çalıştığını 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önderileceğini ve web içeriğinden nasıl mesaj alacağınızı öğrenin.

Bu kılavuzu izlemek için şunlara ihtiyacınız vardır:

  • build.gradle dosyanıza en yeni 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 bir pop-up arasında veya bir sayfa ile içinde yerleşik bir iframe arasında.

Genellikle farklı sayfalardaki komut dosyalarının birbirine erişmesine izin vermek için sayfaların aynı kaynağa sahip olması ve aynı protokolü, bağlantı noktası numarasını ve ana makineyi paylaşması (aynı kaynak politikası olarak da bilinir) gerekir. 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 daha pek çok uygulama için kullanışlı olabilir. Örneğin, bir sohbet uygulaması farklı web sitelerindeki kullanıcılar arasında mesaj göndermek için postMessage uygulamasını kullanabilir. Güvenilir Web Etkinlikleri (TWA) içinde postMessage kullanımı zor olabilir. Bu kılavuz, TWA istemcisinde postMessage'ı kullanarak web sayfasına ileti göndermek ve web sayfasından ileti almak için nasıl kullanılacağı konusunda size yol gösterir.

Uygulamayı web doğrulamasına ekleyin

postMessage API'si, 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 ileti gönderebilmesi için hangi kaynak kaynağa eşdeğer olduğunu bildirmesi 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 ile ilişkili olarak ekleyerek aşağıdaki gibi olur:

[{
  "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, MessageEvent.origin alanı için bir kaynak sağlanmasının gerekli olduğunu ancak postMessage, Digital Assets Link'i içermeyen diğer sitelerle iletişim kurmak için kullanılabilir. Örneğin, www.example.com sitesinin sahibi sizseniz DAL aracılığıyla bunu kanıtlamanız gerekir, ancak diğer web siteleriyle (örneğin www.wikipedia.org) iletişim kurabilirsiniz.

PostMessageService'i manifest dosyanıza ekleyin

postMessage iletişimini almak için hizmeti ayarlamanız gerekir. Bunun için Android manifest dosyanıza PostMessageService 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 yeni bir oturum oluşturmak için aşağıdaki şekilde kullanabilirsiniz. CustomTabsSession, postMessage API'sinin işlenmesi için kullanılan 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ı ve 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ştur

CustomTabsCallback, CustomTabsClient'ın kendi özel sekmelerindeki etkinliklerle ilgili mesajları almasını sağlayan bir geri çağırma sınıfıdır. Bu etkinliklerden biri olan onPostMessage, uygulama web'den mesaj aldığında çağrılır. İletişimi başlatmak amacıyla postMessage kanalını aşağıdaki kodda gösterildiği gibi başlatmak için istemciye geri çağırmayı 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 barındırıcı uygulamamızdan mesaj gönderip alabiliyoruz. Aynı işlemi web'den nasıl yapabiliriz? İletişimin, barındırıcı uygulamasından başlaması ve ardından web sayfasının bağlantı noktasını ilk mesajdan 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 örneği burada bulabilirsiniz

Fotoğraf: Joanna Kosinska'nın Unsplash'ta