ניתוח של נטישת רכישות מוצרים בחיוב ב-Play

1. מבוא

ב-codelab הזה תתמקדו ביצירת מוצר בחיוב חד-פעמי, בשילוב האפליקציה עם ספריית החיובים ב-Play (PBL) ובניתוח הסיבות לנטישת רכישות.

הערה: כדי להשלים את ה-codelab הזה בהצלחה, אתם צריכים לקבל גישה לתכונה אפשרויות רכישה מרובות ומבצעים על מוצרים חד-פעמיים. התכונה הזו זמינה בתוכנית הגישה המוקדמת (EAP). השימוש בתכונות ובמוצרים בגרסת EAP הוא "כפי שהם" (As is), ויכול להיות שהתמיכה בהם תהיה מוגבלת. כדי לקבל גישה לתכונה בתוכנית הגישה המוקדמת, צריך לשלוח בקשה באמצעות טופס ההתעניינות בתוכנית הגישה המוקדמת למוצרים בחיוב חד-פעמי. עם זאת, אם אתם רוצים לדעת רק איך לנתח נטישות של רכישות באמצעות קודי התגובה של חיוב ב-Play, אתם יכולים לעבור ישירות לקטע ניתוח נטישות של רכישות ב-codelab הזה.

קהל

ה-codelab הזה מיועד למפתחי אפליקציות ל-Android שמשתמשים בספריית החיובים ב-Play (PBL) או שרוצים להשתמש בה כדי לייצר הכנסות ממוצרים חד-פעמיים.

מה תלמדו...

  • איך ליצור מוצרים בחיוב חד-פעמי ב-Google Play Console.
  • איך משלבים את האפליקציה עם PBL.
  • איך מעבדים רכישות של מוצרים בחיוב חד-פעמי שהם מתכלים או לא מתכלים ב-PBL.
  • איך מנתחים נטישות של רכישות.

מה צריך...

2. פיתוח אפליקציה לדוגמה

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

  • שילוב האפליקציה עם PBL
  • אחזור מוצרים בחיוב חד-פעמי
  • הפעלת תהליכי רכישה של מוצרים בחיוב חד-פעמי
  • תרחישי רכישה שמובילים לתשובות הבאות בנוגע לחיוב:
    • BILLING_UNAVAILABLE
    • USER_CANCELLED
    • OK
    • ITEM_ALREADY_OWNED

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

דרישות מוקדמות

לפני שיוצרים ומפעילים את אפליקציית הדוגמה, צריך:

תכנות

המטרה של שלב ה-build הזה היא ליצור קובץ חתום של Android App Bundle של אפליקציית הדוגמה.

כדי ליצור את חבילת האפליקציה ל-Android:

  1. מורידים את האפליקציה לדוגמה מ-GitHub.
  2. יוצרים את אפליקציית הדוגמה. לפני שיוצרים את האפליקציה, משנים את שם החבילה של אפליקציית הדוגמה ואז יוצרים אותה. אם יש לכם חבילות של אפליקציות אחרות ב-Play Console, ודאו ששם החבילה שציינתם לאפליקציית הדוגמה הוא ייחודי.

    הערה: בניית אפליקציית הדוגמה יוצרת רק קובץ APK שאפשר להשתמש בו לבדיקה מקומית. עם זאת, הפעלת האפליקציה לא תביא לטעינת מוצרים ומחירים כי המוצרים לא הוגדרו ב-Play Console, וזה מה שתעשו בהמשך ה-codelab הזה.
  3. יוצרים קובץ Android App Bundle חתום.
    1. יצירת מפתח העלאה ומאגר מפתחות
    2. חתימה על האפליקציה באמצעות מפתח ההעלאה
    3. הגדרת חתימת אפליקציה ב-Play

השלב הבא הוא להעלות את חבילת האפליקציה ל-Android אל Google Play Console.

3. יצירת מוצר בחיוב חד-פעמי ב-Play Console

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

יצירת אפליקציה

כדי ליצור אפליקציה:

  1. מתחברים אל Google Play Console באמצעות חשבון המפתח.
  2. לוחצים על Create app (יצירת אפליקציה). ייפתח הדף Create app (יצירת אפליקציה).
  3. מזינים את שם האפליקציה, בוחרים את שפת ברירת המחדל ופרטים נוספים שקשורים לאפליקציה.
  4. לוחצים על יצירת אפליקציה. כך נוצרת אפליקציה ב-Google Play Console.

עכשיו אפשר להעלות את קובץ ה-App Bundle החתום של האפליקציה לדוגמה.

העלאת קובץ App Bundle חתום

  1. מעלים את ה-App Bundle החתום למסלול בדיקה פנימית ב-Google Play Console. רק אחרי ההעלאה אפשר להגדיר את התכונות שקשורות למונטיזציה ב-Play Console.
  2. לוחצים על בדיקה והפצה > בדיקה > גרסה לבדיקה פנימית > יצירת גרסה חדשה.
  3. מזינים שם לגרסת האפליקציה ומעלים את קובץ ה-App Bundle החתום.
  4. לוחצים על הבא ואז על שמירה ופרסום.

עכשיו אפשר ליצור מוצרים בחיוב חד-פעמי.

יצירת מוצר בחיוב חד-פעמי

כדי ליצור מוצר בחיוב חד-פעמי:

  1. בGoogle Play Console, בתפריט הניווט הימני, עוברים אל מונטיזציה באמצעות Play > מוצרים > מוצרים חד-פעמיים.
  2. לוחצים על יצירת מוצר בחיוב חד-פעמי.
  3. מזינים את פרטי המוצר הבאים:
    • מזהה מוצר: מזינים מזהה מוצר ייחודי. מזינים one_time_product_01.
    • (אופציונלי) תגים: מוסיפים תגים רלוונטיים.
    • שם: מזינים שם למוצר. לדוגמה, Product name.
    • תיאור: מזינים תיאור של המוצר. לדוגמה, Product description.
    • (אופציונלי) מוסיפים תמונה של סמל: מעלים סמל שמייצג את המוצר.
    הערה: לצורך ה-codelab הזה, אפשר לדלג על הגדרת הקטע Tax, compliance, and programs (מיסים, תאימות ותוכניות).
  4. לוחצים על הבא.
  5. מוסיפים אפשרות רכישה ומגדירים את הזמינות שלה באזורים. למוצר בחיוב חד-פעמי צריך להיות לפחות אפשרות רכישה אחת, שבה מוגדר אופן הענקת ההרשאה, המחיר והזמינות האזורית. ב-codelab הזה, נוסיף את האפשרות הרגילה קנייה למוצר.בקטע אפשרות רכישה, מזינים את הפרטים הבאים:
    • המזהה של אפשרות הרכישה: מזינים את המזהה של אפשרות הרכישה. לדוגמה, buy.
    • סוג הרכישה: בוחרים באפשרות קנייה.
    • (אופציונלי) תגים: מוסיפים תגים שספציפיים לאפשרות הרכישה הזו.
    • (אופציונלי) לוחצים על אפשרויות מתקדמות כדי להגדיר את האפשרויות המתקדמות. לצורך ה-codelab הזה, אפשר לדלג על הגדרת האפשרויות המתקדמות.
  6. בקטע זמינות ומחירים, לוחצים על הגדרת מחירים > עריכת מחירים בכמות גדולה.
  7. בוחרים באפשרות מדינה או אזור. הפעולה הזו בוחרת את כל האזורים.
  8. לוחצים על המשך. תיפתח תיבת דו-שיח שבה אפשר להזין מחיר. מזינים 10 USD ולוחצים על אישור.
  9. לוחצים על שמירה ואז על הפעלה. אחרי שמסיימים, אפשרות הרכישה נוצרת ומופעלת.

לצורך ה-codelab הזה, יוצרים עוד 3 מוצרים חד-פעמיים עם מזהי המוצרים הבאים:

  • consumable_product_01
  • consumable_product_02
  • consumable_product_03

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

פותחים את האפליקציה לדוגמה ב-Google Play Console ועוברים אל מוצרים חד-פעמיים > מוצרים > מונטיזציה באמצעות Play. לאחר מכן לוחצים על יצירת מוצר בחיוב חד-פעמי וחוזרים על שלבים 3 עד 9.

סרטון על יצירת מוצר בחיוב חד-פעמי

בסרטון לדוגמה הבא מוצגים השלבים ליצירת מוצר בחיוב חד-פעמי שמתוארים למעלה.

4. שילוב עם PBL

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

כדי לשלב את האפליקציה עם PBL, פועלים לפי השלבים הבאים:

  1. מוסיפים את התלות בספריית החיובים ב-Play לאפליקציית הדוגמה.
    dependencies {
    val billing_version = "8.0.0"
    
    implementation("com.android.billingclient:billing-ktx:$billing_version")
    }
    
  2. מאתחלים את BillingClient. ‫BillingClient הוא ה-SDK של הלקוח שקיים באפליקציה שלכם ומתקשר עם ספריית החיובים ב-Play. בקטע הקוד הבא מוצג איך מאתחלים את לקוח החיוב.
    protected BillingClient createBillingClient() {
    return BillingClient.newBuilder(activity)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
        .enableAutoServiceReconnection()
        .build();
    }
    
  3. מתחברים ל-Google Play.בקטע הקוד הבא מוצג איך מתחברים ל-Google Play.
    public void startBillingConnection(ImmutableList<Product> productList) {
    Log.i(TAG, "Product list sent: " + productList);
    Log.i(TAG, "Starting connection");
    billingClient.startConnection(
        new BillingClientStateListener() {
          @Override
          public void onBillingSetupFinished(BillingResult billingResult) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
              // Query product details to get the product details list.
              queryProductDetails(productList);
            } else {
              // BillingClient.enableAutoServiceReconnection() will retry the connection on
              // transient errors automatically.
              // We don't need to retry on terminal errors (e.g., BILLING_UNAVAILABLE,
              // DEVELOPER_ERROR).
              Log.e(TAG, "Billing connection failed: " + billingResult.getDebugMessage());
              Log.e(TAG, "Billing response code: " + billingResult.getResponseCode());
            }
          }
    
          @Override
          public void onBillingServiceDisconnected() {
            Log.e(TAG, "Billing Service connection lost.");
          }
        });
    }
    
  4. מאחזרים את פרטי המוצר בחיוב חד-פעמי.אחרי שמשלבים את האפליקציה עם PBL, צריך לאחזר את פרטי המוצר בחיוב חד-פעמי אל האפליקציה. בקטע הקוד הבא מוצג איך לאחזר את פרטי המוצר בחיוב חד-פעמי באפליקציה.
    private void queryProductDetails(ImmutableList<Product> productList) {
    Log.i(TAG, "Querying products for: " + productList);
    QueryProductDetailsParams queryProductDetailsParams =
        QueryProductDetailsParams.newBuilder().setProductList(productList).build();
    billingClient.queryProductDetailsAsync(
        queryProductDetailsParams,
        new ProductDetailsResponseListener() {
          @Override
          public void onProductDetailsResponse(
              BillingResult billingResult, QueryProductDetailsResult productDetailsResponse) {
            // check billingResult
            Log.i(TAG, "Billing result after querying: " + billingResult.getResponseCode());
            // process returned productDetailsList
            Log.i(
                TAG,
                "Print unfetched products: " + productDetailsResponse.getUnfetchedProductList());
            setupProductDetailsMap(productDetailsResponse.getProductDetailsList());
            billingServiceClientListener.onProductDetailsFetched(productDetailsMap);
          }
        });
    }
    
    התגובה לבקשה להצגת ProductDetails תהיה דומה לתגובה הבאה:
    {
        "productId": "consumable_product_01",
        "type": "inapp",
        "title": "Shadow Coat (Yolo's Realm | Play Samples)",
        "name": "Shadow Coat",
        "description": "A sleek, obsidian coat for stealth and ambushes",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 1990000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$1.99",
                "offerIdToken": "<--offerIdToken-->",
                "purchaseOptionId": "buy",
                "offerTags": []
            }
        ]
    },
    {
        "productId": "consumable_product_02",
        "type": "inapp",
        "title": "Emperor Den (Yolo's Realm | Play Samples)",
        "name": "Emperor Den",
        "description": "A fair lair glowing with molten rock and embers",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 2990000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$2.99",
                "offerIdToken": "<--offerIdToken-->",
                "purchaseOptionId": "buy",
                "offerTags": []
            }
        ]
    }
    
  5. מפעילים את תהליך החיוב.
    public void launchBillingFlow(String productId) {
    ProductDetails productDetails = productDetailsMap.get(productId);
    if (productDetails == null) {
      Log.e(
          TAG, "Cannot launch billing flow: ProductDetails not found for productId: " + productId);
      billingServiceClientListener.onBillingResponse(
          BillingResponseCode.ITEM_UNAVAILABLE,
          BillingResult.newBuilder().setResponseCode(BillingResponseCode.ITEM_UNAVAILABLE).build());
      return;
    }
    ImmutableList<ProductDetailsParams> productDetailsParamsList =
        ImmutableList.of(
            ProductDetailsParams.newBuilder().setProductDetails(productDetails).build());
    
    BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .build();
    
    billingClient.launchBillingFlow(activity, billingFlowParams);
    }
    
  6. זיהוי רכישות ועיבוד שלהן. בשלב הזה צריך:
    1. אימות הרכישה
    2. הענקת זכאות למשתמש
    3. הודעה למשתמש
    4. הודעה ל-Google על תהליך הרכישה
    מבין השלבים האלה, את השלבים א', ב' ו-ג' צריך לבצע בבק-אנד, ולכן הם לא נכללים ב-Codelab הזה.בקטע הקוד הבא מוצג איך לשלוח ל-Google הודעה על מוצר בחיוב חד-פעמי מתכלה:
    private void handlePurchase(Purchase purchase) {
    // Step 1: Send the purchase to your secure backend to verify the purchase following
    // https://developer.android.com/google/play/billing/security#verify
    
    // Step 2: Update your entitlement storage with the purchase. If purchase is
    // in PENDING state then ensure the entitlement is marked as pending and the
    // user does not receive benefits yet. It is recommended that this step is
    // done on your secure backend and can combine in the API call to your
    // backend in step 1.
    
    // Step 3: Notify the user using appropriate messaging.
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
      for (String product : purchase.getProducts()) {
        Log.d(TAG, product + " purchased successfully! ");
      }
    }
    
    // Step 4: Notify Google the purchase was processed.
    // For one-time products, acknowledge the purchase.
    // This sample app (client-only) uses billingClient.acknowledgePurchase().
    // For consumable one-time products, consume the purchase
    // This sample app (client-only) uses billingClient.consumeAsync()
    // If you have a secure backend, you must acknowledge purchases on your server using the
    // server-side API.
    // See https://developer.android.com/google/play/billing/security#acknowledge
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED && !purchase.isAcknowledged()) {
    
      if (shouldConsume(purchase)) {
        ConsumeParams consumeParams =
            ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
        billingClient.consumeAsync(consumeParams, consumeResponseListener);
    
      } else {
        AcknowledgePurchaseParams acknowledgePurchaseParams =
            AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.getPurchaseToken())
                .build();
        billingClient.acknowledgePurchase(
            acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
      }
     }
    }
    

5. ניתוח של נטישת רכישות

עד עכשיו, התגובות של החיובים ב-Play שהוצגו ב-codelab התמקדו בתרחישים מוגבלים כמו התגובות USER_CANCELLED,‏ BILLING_UNAVAILABLE,‏ OK ו-ITEM_ALREADY_OWNED. עם זאת, מערכת החיוב ב-Play יכולה להחזיר 13 קודי תגובה שונים שיכולים להיות מופעלים על ידי גורמים שונים בעולם האמיתי.

בקטע הזה מוסברות הסיבות לתשובות השגיאה USER_CANCELLED ו-BILLING_UNAVAILABLE, ומוצעות פעולות תיקון אפשריות שאפשר לבצע.

קוד שגיאה בתגובה USER_CANCELED

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

סיבות אפשריות

אילו פעולות אפשר לבצע?

  • יכול להיות שהמשתמשים האלה הם בעלי כוונת רכישה נמוכה ורגישים למחירים.
  • הרכישה בהמתנה או שהתשלום נדחה.

קוד שגיאה בתגובה BILLING_UNAVAILABLE

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

סיבות אפשריות

אילו פעולות אפשר לבצע?

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

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

אסטרטגיות לניסיון חוזר של קודי שגיאה בתגובה

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

במקרה של שגיאות שמתרחשות כשהמשתמש נמצא בסשן, מומלץ להשתמש באסטרטגיית ניסיון חוזר פשוטה עם מספר מקסימלי מוגדר של ניסיונות, כדי למזער את ההפרעה לחוויית המשתמש. לעומת זאת, עבור פעולות ברקע כמו אישור רכישות חדשות, שלא דורשות ביצוע מיידי, מומלץ להשתמש בגישה של השהיה מעריכית לפני ניסיון חוזר (exponential backoff).

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

6. השלבים הבאים

מסמכי עזר

7. מעולה!

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

סקר

נשמח לקבל ממך משוב על ה-Codelab הזה. כדאי להקדיש כמה דקות למילוי הסקר שלנו.