PostMessage لـ TWA

Sayed El-Abady
Sayed El-Abady

من خلال الإصدار 115 من Chrome، يمكن لأنشطة الويب الموثوق بها (TWA) إرسال الرسائل باستخدام postMessage. يرشدك هذا المستند إلى خطوات الإعداد اللازمة للربط بين تطبيقك والويب.

بنهاية هذا الدليل، ستكون قادرًا على:

  • فهم كيفية عمل العميل والتحقق من محتوى الويب.
  • التعرف على كيفية تهيئة قناة الاتصال بين العميل ومحتوى الويب.
  • التعرف على كيفية إرسال الرسائل إلى محتوى الويب وتلقيها منه.

لاتّباع هذا الدليل، ستحتاج إلى ما يلي:

  • لإضافة أحدث مكتبة androidx.browser (الحد الأدنى v1.6.0-alpha02) إلى ملف version.
  • إصدار Chrome 115.0.5790.13 أو إصدار أحدث لتطبيق TWA

تتيح طريقة window.postMessage() بأمان التواصل المشترك بين كائنات النافذة. على سبيل المثال، بين صفحة ونافذة منبثقة ظهرت، أو بين صفحة وإطار iframe مضمّن بداخلها.

لا يُسمح عادةً للنصوص البرمجية في الصفحات المختلفة بالوصول إلى بعضها إلا إذا كانت الصفحات التي تم إنشاؤها من المصدر نفسه تتشارك البروتوكول نفسه ورقم المنفذ والمضيف نفسه (تُعرف أيضًا باسم سياسة المصدر نفسه). توفّر طريقة window.postMessage() آلية خاضعة للرقابة للتواصل بأمان بين المصادر المختلفة. ويمكن أن يكون هذا مفيدًا في تنفيذ تطبيقات الدردشة والأدوات التعاونية وغيرها. على سبيل المثال، يمكن لتطبيق محادثة استخدام postMessage لإرسال الرسائل بين المستخدمين في مواقع إلكترونية مختلفة. قد يكون استخدام السمة postMessage في أنشطة الويب الموثوق بها (TWA) صعبًا بعض الشيء، ويرشدك هذا الدليل إلى طريقة استخدام postMessage في برنامج TWA لإرسال الرسائل إلى صفحة الويب وتلقّيها من صفحة الويب.

إضافة التطبيق إلى التحقق من الويب

تسمح واجهة برمجة التطبيقات postMessage لمصدرَين صالحَين بالتواصل لبعضهما، وهما المصدر والأصل المستهدف. ولكي يتمكّن تطبيق Android من إرسال رسائل إلى المصدر الهدف، يحتاج التطبيق إلى توضيح أصل المصدر المكافئ له. ويمكن إجراء ذلك باستخدام روابط مواد العرض الرقمية (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 هي الفئة الأساسية للتعامل مع واجهة برمجة التطبيقات 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. سننشئ هذا في القسم التالي.

إنشاء معاودة الاتصال في علامة التبويب المخصّصة

CustomTabsCallback هي فئة معاودة اتصال لبرنامج CustomTabsClient لتلقّي رسائل بشأن الأحداث في علامات التبويب المخصّصة. أحد هذه الأحداث هو "onPostMessage" ويتم الاتصال به عندما يتلقّى التطبيق رسالة من الويب. أضِف رمز معاودة الاتصال إلى العميل لإعداد قناة postMessage لبدء الاتصال، كما هو موضّح في الرمز التالي.

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

التواصل من الويب

يمكننا الآن إرسال الرسائل واستلامها من التطبيق المضيف، فكيف يمكننا تنفيذ الإجراء نفسه من الويب؟ يجب أن يبدأ التواصل من التطبيق المضيف، ثم يجب أن تحصل صفحة الويب على المنفذ من الرسالة الأولى. يتم استخدام هذا المنفذ للتواصل مرة أخرى. سيظهر ملف 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);
  };
});

يمكنك الاطّلاع على نموذج كامل هنا.

صورة من تصوير جوانا كوسينسكا على موقع Unسبلاش