PostMessage ל-TWA

Sayed El-Abady
Sayed El-Abady

החל מגרסה 115 של Chrome 115, הפעילויות המהימנות באינטרנט (TWA) יכולות לשלוח הודעות באמצעות postMessages. המאמר הזה מסביר את ההגדרה הנדרשת לתקשורת בין האפליקציה שלך לאינטרנט.

בסוף המדריך הזה תלמדו: - תבינו איך פועל האימות של הלקוח ותוכן האינטרנט. - דע כיצד להפעיל את ערוץ התקשורת בין הלקוח לתוכן באינטרנט. - דע איך לשלוח הודעות לתוכן באינטרנט ולקבל ממנו הודעות.

כדי לעקוב אחר המדריך הזה, צריך:

  • כדי להוסיף את הספרייה העדכנית ביותר של androidx.browser (גרסה 1.6.0-alpha02 לפחות) לקובץ ה-build.gradle.
  • Chrome בגרסה 115.0.5790.13 ואילך ל-TWA.

השיטה window.postMessage() מאפשרת תקשורת ממקורות שונים בין אובייקטים ב-Window בצורה בטוחה. לדוגמה, בין דף לבין חלון קופץ שהוא יצר, או בין דף ל-iframe שמוטמע בו.

בדרך כלל, סקריפטים בדפים שונים מורשים לגשת זה לזה רק אם הדפים שהם מקורם באותו מקור, הם חולקים את אותו פרוטוקול, מספר יציאה ואותו מארח (נקרא גם מדיניות המקור הזהה). השיטה window.postMessage() מספקת מנגנון נשלט לצורך תקשורת מאובטחת בין מקורות שונים. האפשרות הזו יכולה להיות שימושית להטמעה של אפליקציות צ'אט, כלי שיתוף פעולה ועוד. לדוגמה, אפליקציית צ'אט יכולה להשתמש ב-postMessage כדי לשלוח הודעות בין משתמשים שנמצאים באתרים שונים. השימוש ב-postMessage בפעילויות באינטרנט מהימנים (TWA) יכול להיות קצת מסובך, המדריך הזה מסביר איך להשתמש ב-postMessage בלקוח TWA כדי לשלוח הודעות ולקבל הודעות בדף האינטרנט.

הוספת האפליקציה לאימות אתרים

כדי שהודעת ה-postMessage תפעל, נדרש קשר חוקי בין אתר לבין אפליקציית פעילות האינטרנט המהימנה שמפעילה את האתר הזה. ניתן לעשות זאת באמצעות קישורי נכסים דיגיטליים (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": [""] }
}]

הערה: צריך לספק מקור שמשויך לשדה MessageEvent.origin עם ההגדרה של המקור המשויך ל-TWA. עם זאת, ניתן להשתמש ב-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 API. הקוד הבא מראה איך ברגע שהשירות יחובר, הלקוח ישמש ליצירת סשן חדש והסשן הזה ישמש ל-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

CustomTabsCallback הוא מחלקה של קריאה חוזרת (callback) עבור 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);
  };
});

אפשר למצוא דוגמה מלאה מלאה כאן

תמונה מאת Joanna Kosinska ב-UnFlood