מה חדש ב-Web In Play

מאז שהשקנו את התכונה פעילות באינטרנט מהימנה בשנה שעברה, צוות Chrome ממשיך לעבוד על המוצר כדי שיהיה קל יותר להשתמש בו עם בועות, להוסיף תכונות חדשות כמו שילוב החיוב הקרוב ב-Google Play ולאפשר לו לפעול בפלטפורמות נוספות, כמו ChromeOS. המאמר הזה כולל סיכום של העדכונים האחרונים והעדכונים הצפויים בפעילות באינטרנט המהימנה.

תכונות חדשות של 'בועות הבועה' ו'פעילות מהימנה באינטרנט'

בעזרת בועות תוכלו ליצור אפליקציות שמפעילות את אפליקציות ה-PWA במסגרת פעילות אינטרנט מהימנה, ללא צורך בידע בכלים ספציפיים לפלטפורמה.

תהליך הגדרה פשוט

בעבר, השימוש בבועה נדרש הגדרה ידנית של ערכת הפיתוח של Java ושל ה-SDK של Android, לשניהם יש סבירות גבוהה לשגיאות. הכלי מציע עכשיו הורדה אוטומטית של יחסי התלות החיצוניים כשמריצים אותו בפעם הראשונה.

אם אתם מעדיפים להשתמש בהתקנה קיימת של יחסי התלות, עדיין תוכלו להיעזר בפקודה החדשה doctor כדי לאתר בעיות ולהמליץ על תיקונים להגדרות. עכשיו אפשר לעדכן אותן משורת הפקודה באמצעות הפקודה updateConfig.

אשף משופר

כשיוצרים פרויקט עם init, דרוש מידע לשימוש ב- מגבלות מידע כדי ליצור את האפליקציה ל-Android. הכלי מחלץ ערכים מהמניפסט של אפליקציית האינטרנט ומספק ברירות מחדל כשאפשר.

אפשר לשנות את הערכים האלה כשיוצרים פרויקט חדש, אבל בעבר המשמעות של כל שדה לא הייתה ברורה. תיבות הדו-שיח לאתחול נבנו מחדש עם תיאורים טובים יותר ואימות טוב יותר לכל שדה קלט.

תצוגה: תמיכה במסך מלא ובכיוון

במקרים מסוימים, יכול להיות שתרצו שהאפליקציה תשתמש בכמה שיותר מהמסך. במהלך הפיתוח של אפליקציות PWA, כדי להטמיע את הפעולה הזו צריך להגדיר את השדה display במניפסט של אפליקציית האינטרנט לערך fullscreen.

כשחבילת הבועה מזהה את אפשרות המסך המלא במניפסט של אפליקציית האינטרנט, היא תגדיר את האפליקציה ל-Android כך שתופעל במסך מלא או במצב עשיר, במונחים ספציפיים ל-Android.

השדה orientation במניפסט של אפליקציית האינטרנט מגדיר אם להפעיל את האפליקציה בפריסה לאורך, בפריסה לרוחב או בכיוון שבו המכשיר משתמש כרגע. חבילת הבועות קוראת עכשיו את שדה המניפסט של אפליקציית האינטרנט, ומשתמשת בו כברירת מחדל כשיוצרים את האפליקציה ל-Android.

אתם יכולים להתאים אישית את שתי התצורות במסגרת התהליך של bubblewrap init.

הפלט של AppBundles

App Bundles הוא פורמט פרסום לאפליקציות שמאצילות את יצירת ה-APK הסופית וכניסה ל-Play. בפועל, כך אפשר להציג קבצים קטנים יותר למשתמשים כשהם מורידים את האפליקציה מהחנות.

עכשיו האפליקציה בועות בחבילה מרוכזת בקובץ App Bundle בשם app-release-bundle.aab. עדיף להשתמש בפורמט הזה כשמפרסמים אפליקציות בחנות Play, כי החנות תחייב אותו החל מהמחצית השנייה של 2021.

הקצאת הרשאות לניהול מיקום גיאוגרפי

המשתמשים מצפים שאפליקציות שמותקנות במכשירים שלהם יפעלו בעקביות, בלי קשר לטכנולוגיה. בשימוש בתוך פעילות מהימנה באינטרנט, ניתן עכשיו להקצות את ההרשאה GeoLocation למערכת ההפעלה. כשההרשאה מופעלת, המשתמשים יראו את אותן תיבות הדו-שיח כמו אפליקציות שנבנו באמצעות Kotlin או Java, וימצאו אמצעי בקרה לניהול ההרשאה באותו מקום.

אפשר להוסיף את הפיצ'ר הזה דרך wrapper, ומכיוון שהוא מוסיף יחסי תלות נוספים לפרויקט Android, צריך להפעיל אותה רק כשאפליקציית האינטרנט משתמשת בהרשאה 'מיקום גיאוגרפי'.

קבצים בינאריים שעברו אופטימיזציה

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

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

איך מעדכנים אפליקציה קיימת

אפליקציה שנוצרה על ידי בועת הבועה מורכבת מאפליקציית אינטרנט ומ-wrapper קל ל-Android שפותח את ה-PWA. למרות שאפליקציית PWA שנפתחת בתוך פעילות אינטרנט מהימנה פועלת לפי אותם מחזורי עדכון כמו בכל אפליקציית אינטרנט, אפשר וצריך לעדכן את ה-wrapper המקורי.

צריך לעדכן את האפליקציה כדי לוודא שהיא משתמשת בגרסה האחרונה של ה-wrapper, עם תיקוני הבאגים האחרונים והתכונות הרלוונטיות. אחרי שמותקנת הגרסה האחרונה של wrapper, הפקודה update תחיל את הגרסה האחרונה של ה-wrapper על פרויקט קיים:

npm update -g @bubblewrap/cli
bubblewrap update
bubblewrap build

סיבה נוספת לעדכון האפליקציות האלה היא לוודא ששינויים במניפסט באינטרנט חלים עליהן. לשם כך, משתמשים בפקודה החדשה merge:

bubblewrap merge
bubblewrap update
bubblewrap build

עדכונים בקריטריוני האיכות

ב-Chrome 86 השקנו שינויים בקריטריוני האיכות של פעילות אינטרנט מהימנה, שמוסברים במלואם במאמר שינויים בקריטריונים של איכות של אפליקציות PWA שמשתמשות בפעילות אינטרנט מהימנה.

סיכום קצר הוא שכדאי לוודא שהאפליקציות מטפלות בתרחישים הבאים על מנת למנוע מהן לקרוס:

  • המערכת לא הצליחה לאמת את הקישורים של הנכסים הדיגיטליים בזמן השקת האפליקציה
  • השגיאה: HTTP 200 לא מחזיר בקשה למשאב רשת אופליין
  • החזרה של שגיאת HTTP 404 או 5xx באפליקציה.

מעבר לכך שהאפליקציה צריכה לעבור את האימות של Digital Asset Links (קישורים לנכסים דיגיטליים), היא יכולה לטפל בתרחישים הנותרים:

self.addEventListener('fetch', event => {
  event.respondWith((async () => {
    try {
      return await fetchAndHandleError(event.request);
    } catch {
      // Failed to load from the network. User is offline or the response
      // has a status code that triggers the Quality Criteria.
      // Try loading from cache.
      const cachedResponse = await caches.match(event.request);
      if (cachedResponse) {
        return cachedResponse;
      }
      // Response was not found on the cache. Send the error / offline
      // page. OFFLINE_PAGE should be pre-cached when the service worker
      // is activated.
      return await caches.match(OFFLINE_PAGE);
    }
  })());
});

async function fetchAndHandleError(request) {
  const cache = await caches.open(RUNTIME_CACHE);
  const response = await fetch(request);

  // Throw an error if the response returns one of the status
  // that trigger the Quality Criteria.
  if (response.status === 404 ||
      response.status >= 500 && response.status < 600) {
    throw new Error(`Server responded with status: ${response.status}`);
  }

  // Cache the response if the request is successful.
  cache.put(request, response.clone());
  return response;
}

כשמשתמשים ב-Service Workers, תיבת עבודה נאפה לפי שיטות מומלצות ומסירה תבנית סטנדרטית. לחלופין, אפשר להשתמש בפלאגין Workbox כדי לטפל בתרחישים האלה:

export class FallbackOnErrorPlugin {
  constructor(offlineFallbackUrl, notFoundFallbackUrl, serverErrorFallbackUrl) {
    this.notFoundFallbackUrl = notFoundFallbackUrl;
    this.offlineFallbackUrl = offlineFallbackUrl;
    this.serverErrorFallbackUrl = serverErrorFallbackUrl;
  }

  checkTrustedWebActivityCrash(response) {
    if (response.status === 404 || response.status >= 500 && response.status <= 600) {
      const type = response.status === 404 ? 'E_NOT_FOUND' : 'E_SERVER_ERROR';
      const error = new Error(`Invalid response status (${response.status})`);
      error.type = type;
      throw error;
    }
  }

  // This is called whenever there's a network response,
  // but we want special behavior for 404 and 5**.
  fetchDidSucceed({response}) {
    // Cause a crash if this is a Trusted Web Activity crash.
    this.checkTrustedWebActivityCrash(response);

    // If it's a good response, it can be used as-is.
    return response;
  }

  // This callback is new in Workbox v6, and is triggered whenever
  // an error (including a NetworkError) is thrown when a handler runs.
  handlerDidError(details) {
    let fallbackURL;
    switch (details.error.details.error.type) {
      case 'E_NOT_FOUND': fallbackURL = this.notFoundFallbackUrl; break;
      case 'E_SERVER_ERROR': fallbackURL = this.serverErrorFallbackUrl; break;
      default: fallbackURL = this.offlineFallbackUrl;
    }

    return caches.match(fallbackURL, {
      // Use ignoreSearch as a shortcut to work with precached URLs
      // that have _WB_REVISION parameters.
      ignoreSearch: true,
    });
  }
}

חיוב ב-Google Play

מעבר למכירת מוצרים דיגיטליים ומינויים בחנות Play לאפליקציה שלך, חיוב ב-Google Play כולל כלים לניהול הקטלוג, המחירים והמינויים, דוחות שימושיים ותהליך תשלום שמופעל על ידי חנות Play שכבר מוכר למשתמשים שלך. זוהי דרישה גם לגבי אפליקציות שמתפרסמות בחנות Play ומוכרות מוצרים דיגיטליים.

Chrome 88 יושק בגרסת מקור לניסיון ב-Android שתאפשר לשלב את האפשרויות Trusted Web Activity, Payment Request API ו-Digital Goods API כדי להטמיע תהליכי רכישה דרך החיוב ב-Google Play. אנחנו צופים שתקופת הניסיון הזו תהיה זמינה גם ל-ChromeOS בגרסה 89.

חשוב: ל-Google Play Billing API יש טרמינולוגיה משלו והיא כוללת רכיבי לקוח ורכיבי קצה עורפי. חלק זה מתייחס רק לחלק קטן מה-API הספציפי לשימוש ב-Digital Goods API וב'פעילות אינטרנט מהימנה'. חשוב לקרוא את משאבי העזרה בנושא חיוב ב-Google Play ולהבין את המושגים שלהם לפני שמשלבים אותם באפליקציה בסביבת ייצור.

התהליך הבסיסי

התפריט של Play Console

כדי לספק מוצרים דיגיטליים דרך חנות Play, צריך להגדיר את הקטלוג בחנות Play ולקשר את חנות Play כאמצעי תשלום מה-PWA.

כשתהיו מוכנים להגדיר את הקטלוג, תוכלו להתחיל במציאת הקטע Products (מוצרים) בתפריט השמאלי ב-Play Console:

כאן תמצאו את האפשרות להציג את המוצרים והמינויים הקיימים מתוך האפליקציה, ותוכלו למצוא גם את לחצן היצירה להוספת מוצרים חדשים.

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

פרטי המוצר

כדי ליצור מוצר חדש מתוך האפליקציה, נדרשים מזהה מוצר, שם, תיאור ומחיר. חשוב ליצור מזהי מוצר משמעותיים שקל לזכור. תצטרכו אותם מאוחר יותר, ואי אפשר לשנות את המזהים האלה אחרי שיוצרים אותם.

כשתיצרו מינויים, תצטרכו גם לציין תקופת חיוב. יש לכם אפשרות לפרט את הטבות המינוי ולהוסיף תכונות כמו תקופת ניסיון בחינם, מחיר היכרות, תקופת חסד ואפשרות להירשם מחדש.

לאחר היצירה של כל מוצר, צריך להפעיל אותם כדי להציג אותם באפליקציה.

אם אתם מעדיפים, תוכלו להוסיף את המוצרים דרך Play Developers API.

אחרי שמגדירים את הקטלוג, השלב הבא הוא להגדיר את תהליך התשלום מ-PWA. כדי לעשות זאת, עליכם להשתמש בשילוב של Digital Goods API ו-Payment Request API.

אחזור מחיר מוצר באמצעות Digital Goods API

כשמשתמשים בחיוב ב-Google Play, חשוב לוודא שהמחיר שמוצג למשתמשים תואם למחיר שמופיע בדף האפליקציה בחנות. סנכרון ידני של המחירים האלה הוא בלתי אפשרי, ולכן ה-Digital Goods API מאפשר לאפליקציית האינטרנט לשלוח שאילתה לספק התשלום המקורי לגבי מחירים:

// The SKU for the product, as defined in the Play Store interface
async function populatePrice(sku) {
  try {
    // Check if the Digital Goods API is supported by the browser.
    if (window.getDigitalGoodsService) {
      // The Digital Goods API can be supported by other Payments provider.
      // In this case, we're retrieving the Google Play Billing provider.
      const service =
          await window.getDigitalGoodsService("https://play.google.com/billing");

      // Fetch product details using the `getDetails()` method.
      const details = await service.getDetails([sku]);

      if (details.length === 0) {
        console.log(`Could not get SKU: "${sku}".`);
        return false;
      }

      // The details will contain both the price and the currenncy.
      item = details[0];
      const value = item.price.value;
      const currency = item.price.currency;

      const formattedPrice = new Intl.NumberFormat(navigator.language, {
        style: 'currency', currency: currency }).format(value);

      // Display the price to the user.
      document.getElementById("price").innerHTML = formattedPrice;
    } else {
      console.error("Could not get price for SKU \"" + sku + "\".");
    }
  } catch (error) {
    console.log(error);
  }
  return false;
}

כדי לזהות תמיכה ב-Digital Goods API, בודקים אם getDigitalGoodsService() זמין באובייקט window.

לאחר מכן קוראים ל-window.getDigitalGoodsService() עם מזהה החיוב ב-Google Play כפרמטר. הפעולה הזו תחזיר מופע שירות של חיוב ב-Google Play, וספקים אחרים יכולים להטמיע תמיכה ב-Digital Goods API שיהיו להם מזהים שונים.

לסיום, קוראים לפונקציה getDetails() לגבי אובייקט החיוב ב-Google Play שמעביר את המק"ט של הפריט כפרמטר. השיטה תחזיר אובייקט מפורט שמכיל גם את המחיר וגם את המטבע של הפריט שאפשר להציג למשתמש.

התחלת תהליך הרכישה

ה-Payment Request API מאפשר תהליכי רכישה באינטרנט ומשמש גם לשילוב החיובים ב-Google Play. אם עדיין לא השתמשתם ב-Payment Request API, תוכלו לקרוא את המאמר הזה בנושא How Payment Request API עובד.

כדי להשתמש ב-API עם חיוב ב-Google Play, תצטרכו להוסיף אמצעי תשלום שיש בו מטאוד נתמך שנקרא https://play.google.com/billing, ולהוסיף את המק"ט כחלק מהנתונים של אמצעי התשלום:

const supportedInstruments = [{
  supportedMethods: "https://play.google.com/billing",
  data: {
    sku: sku
  }
}];

לאחר מכן, בונים אובייקט PaymentRequest כרגיל ומשתמשים ב-API כרגיל

const request = new PaymentRequest(supportedInstruments, details);

אישור הרכישה

לאחר השלמת העסקה, תצטרכו להשתמש ב-Digital Goods API כדי לאשר את התשלום. אובייקט התגובה מה-PaymentRequest יכיל אסימון שבו תשתמשו כדי לאשר את הטרנזקציה:

const response = await request.show();
const token = response.details.token;
const service =
          await window.getDigitalGoodsService("https://play.google.com/billing");
await service.acknowledge(token, 'onetime');

ל-Digital Goods API ול-Payment Request API אין מידע על זהות המשתמש. כתוצאה מכך, אתם אחראים לשייך את הרכישה למשתמש בקצה העורפי ולהבטיח שיש לו גישה לפריטים שנרכשו. כאשר משייכים את הרכישה למשתמש, חשוב לשמור את אסימון הרכישה, כי ייתכן שתצטרכו אותו כדי לאמת אם הרכישה בוטלה או אם קיבלתם החזר כספי, או אם המינוי עדיין פעיל. מומלץ לעיין ב-Real Time Developer Notifications API וב-Google Play Developer API, כי הם מספקים נקודות קצה לטיפול בבקשות התמיכה בקצה העורפי שלכם.

בדיקה אם קיימות הרשאות קיימות

יכול להיות שמשתמש מימש קוד הטבה או שיש לו מינוי למוצר שלך. כדי לוודא שלמשתמש יש את ההרשאות המתאימות, אפשר לקרוא לפקודה listPurchases() בשירות המוצרים הדיגיטליים. הפעולה הזו תחזיר את כל הרכישות שהלקוח ביצע באפליקציה, וזהו גם המקום לאשר רכישות שלא אושרו, כדי לוודא שהמשתמש יממש את ההרשאות שלו בצורה נכונה.

const purchases = await itemService.listPurchases();
for (p of purchases) {
  if (!p.acknowledged) {
    await itemService.acknowledge(p.purchaseToken, 'onetime');
  }
}

העלאה לחנות Play של ChromeOS

פעילויות אינטרנט מהימנות זמינות גם החל מגרסה 85 של Chrome בחנות Play של ChromeOS. תהליך הרישום של האפליקציה בחנות זהה ב-ChromeOS וב-Android.

לאחר יצירת ה-App Bundle, ב-Play Console יוצגו השלבים הנדרשים כדי להציג את האפליקציה בחנות Play. במסמכי התיעוד של Play Console אפשר למצוא עזרה בנושא יצירת דף האפליקציה, ניהול קובצי ה-APK והגדרות אחרות, וכן הוראות לבדיקה ולהפצה של האפליקציה בצורה בטוחה.

כדי להגביל את האפליקציה רק למכשירי Chromebook, צריך להוסיף את הדגל --chromeosonly כשמאתחלים את האפליקציה בגופן בועות:

bubblewrap init --manifest="https://example.com/manifest.json" --chromeosonly

כשמפתחים אפליקציה באופן ידני, בלי חבילת בועות, צריך להוסיף את הדגל uses-feature למניפסט של Android:

<uses-feature  android:name="org.chromium.arc" android:required="true"/>

אם דף האפליקציה שלך משותף עם אפליקציה ל-Android, גרסת החבילה היחידה של ChromeOS תמיד צריכה להיות גבוהה יותר מגרסת החבילה של האפליקציה ל-Android. ניתן להגדיר את גרסת החבילה של ChromeOS למספר גבוה בהרבה מגרסת Android, כך שלא צריך לעדכן את שתי הגרסאות בכל גרסה.