הטמעה של החלפת מינויים באמצעות חיוב ב-Google Play

1. מבוא

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

קהל

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

מה תלמדו...

  • איך יוצרים מינויים ב-Play Console.
  • איך בוחרים את ReplacementMode הנכון (לדוגמה, WITH_TIME_PRORATION לעומת DEFERRED) בהתאם למדיניות השדרוג וההורדה של האפליקציה.
  • איך מגדירים את BillingFlowParams בתוך launchBillingFlow כדי להפעיל את תהליך הרכישה ב-Google Play להחלפת תוכנית.
  • איך משתמשים בהתראות בזמן אמת למפתחים (RTDN) וב-API של purchases.subscriptionsv2 כדי לבטל בבטחה גישה ישנה ולהעניק גישה חדשה בבק-אנד

מה תצטרכו

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

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

  • שילוב האפליקציה עם PBL
  • הטמעה של החלפות מינויים

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

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

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

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

תכנות

כדי ליצור את האפליקציה לדוגמה בהתאם לדרישות של ה-codelab:

  1. מורידים את האפליקציה לדוגמה מ-GitHub.
  2. מעדכנים את applicationId בקובץ build.gradle של האפליקציה לדוגמה כך שישקף את מזהה האפליקציה שלכם ב-Play Developer Console.
  3. מבצעים build של האפליקציה לדוגמה.
    הערה: כך מבצעים build של האפליקציה לבדיקה מקומית. עם זאת, הפעלת האפליקציה לא מאחזרת מוצרים ומחירים כי המינויים הנדרשים עדיין לא נוצרו ב-Play Console. בקטע הבא נסביר איך ליצור מינויים ב-Developer Console.

3. יצירת מינויים ב-Play Console

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

יצירת מינוי חדש

כדי ליצור מינוי חדש

  1. פותחים את Play Console ועוברים אל דף המינויים (מונטיזציה באמצעות Play > מוצרים > מינויים).
  2. לוחצים על יצירת מינוי.
  3. מזינים את פרטי המינוי:
    • ProductID : מזינים מזהה מוצר ייחודי. מזינים premium_plan.
    • שם : מזינים שם קצר למינוי. לדוגמה: Premium Plan.
  4. לוחצים על יצירה.

יצירת מינוי Base Plan

  1. פותחים את Play Console ועוברים אל דף המינויים (מונטיזציה באמצעות Play > מוצרים > מינויים).
  2. לצד המינוי שרוצים ליצור בו תוכנית בסיסית, לוחצים על החץ שמאלה כדי לראות את פרטי המינוי.
  3. לוחצים על הוספה של תוכנית בסיסית.
  4. מזינים מזהה של מינוי בסיסי. דוגמה monthly-auto-renewing.
  5. בוחרים את הסוג חידוש אוטומטי.
  6. למינוי הבסיסי שמתחדש אוטומטית, מגדירים את הפרטים הבאים:
    • תקופת החיוב: חודשית.
    • תקופת חסד: 7 ימים.
    • שינויים בתוכנית תשלומים ובמבצע: חיוב בתאריך החיוב.
    • להירשם מחדש: אישור.
  7. בקטע מחיר וזמינות, לוחצים על הגדרת מחירים כדי להגדיר את המחיר של המינוי הבסיסי.
  8. בוחרים באפשרות 'כל המדינות והאזורים' ואז לוחצים על הגדרת מחיר.
  9. מגדירים את המחיר כ-10$ למינוי הבסיסי הזה ולוחצים על עדכון.
  10. אחרי שמגדירים את המחיר של התוכנית הבסיסית, לוחצים על שמירה בפינה השמאלית התחתונה ואז על הפעלה.

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

לצורך ה-codelab הזה, יוצרים עוד שני מינויים עם ההגדרות הבאות:

  • תוכנית בסיסית
    • מזהה המוצר: basic_plan
    • שם: Basic Plan
    • מזהה מינוי בסיסי: monthly-auto-renewing
    • מחיר: ‎$5
  • תוכנית Lite
    • מזהה המוצר: lite_plan
    • שם: Lite Plan
    • מזהה מינוי בסיסי: monthly-auto-renewing
    • מחיר: 3$‎

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

סרטון על יצירת מינוי

בסרטון הבא מוצגים השלבים שמתוארים למעלה ליצירת מינוי ב-Play Console.

4. החלפות מינויים

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

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

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

ספריית החיובים ב-Play מספקת כמה אפשרויות ReplacementMode לשליטה בהתנהגות הזו.

מצבי החלפה זמינים

  • WITH_TIME_PRORATION: שדרוג או שדרוג לאחור של פריט המינוי מתבצעים באופן מיידי. הזמן שנותר יותאם על סמך ההפרש במחיר, וייזקף לזכות המינוי החדש על ידי עדכון תאריך החיוב הבא. זוהי התנהגות ברירת המחדל.
  • CHARGE_PRORATED_PRICE: שדרוג פריט המינוי מתבצע באופן מיידי, ומחזור החיובים נשאר ללא שינוי. לאחר מכן המשתמש יחויב על ההפרש במחיר לתקופה שנותרה.
  • CHARGE_FULL_PRICE: פריט המינוי משודרג או משונמך באופן מיידי, והמשתמש מחויב במחיר מלא על ההרשאה החדשה באופן מיידי. היתרה מהמינוי הקודם מועברת לזכאות זהה, או שהיא מחושבת באופן יחסי לזמן כשעוברים לזכאות אחרת.
  • WITHOUT_PRORATION: השדרוג או השנמוך של פריט המינוי מתבצעים באופן מיידי, והמחיר החדש מחויב כשהמינוי מתחדש. מחזור החיובים נשאר ללא שינוי.
  • DEFERRED: שדרוג או שדרוג לאחור של פריט במינוי מתבצעים רק כשהמינוי מתחדש.

5. WITH_TIME_PRORATION

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

תרחיש לדוגמה

משתמש עובר מתוכנית Basic (4.99$ לחודש) לתוכנית Premium (9.99$ לחודש) ב-15 באפריל, באמצע מחזור החיוב החודשי שלו.

במקרה כזה:

  • המשתמש מקבל גישה למינוי Premium באופן מיידי.
  • מערכת Google Play מחשבת באופן אוטומטי את תקופת החלוקה היחסית. נניח שמערכת Play מחשבת ש-15 הימים שנותרו בתוכנית Basic שווים ל-7 ימים בתוכנית Premium. במקרה כזה, תאריך החיוב הבא יהיה 21 באפריל.
  • לא נדרש תשלום מיידי מהמשתמש.

קטע קוד

// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION;

SubscriptionProductReplacementParams subscriptionProductReplacementParams =
    SubscriptionProductReplacementParams.newBuilder()
        .setOldProductId(oldProductId)
        .setReplacementMode(replacementMode)
        .build();

ProductDetailsParams productDetailsParams =
    ProductDetailsParams.newBuilder()
        .setProductDetails(productDetails)
        .setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
        .setOfferToken(offerToken)
        .build();

List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
        .build();

billingClient.launchBillingFlow(activity, billingFlowParams);

שדרוג עם WITH_TIME_PRORATION

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Premium.

הזכאות של המשתמש משודרגת לתוכנית Premium באופן מיידי. הסכום שהמשתמש צריך לשלם באופן מיידי הוא 0.00 $. הערך שנותר מהמינוי לתוכנית Basic מחולק באופן יחסי לזמן בתוכנית Premium, ולכן תאריך החידוש הבא מוקדם יותר. המשתמש יחויב בסכום החידוש של 9.99 $בתאריך החיוב החדש.

שדרוג לאחור עם WITH_TIME_PRORATION

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Lite.

הזכאות של המשתמש/ת תשודרג לאחור לתוכנית Lite באופן מיידי. הסכום לתשלום מיידי הוא 0.00 $. הערך שנותר בתוכנית Basic מחולק באופן יחסי לזמן בתוכנית Lite, וכך תאריך החידוש הבא נדחה באופן משמעותי. המשתמש יחויב בסכום החידוש של 2.99 $בתאריך החיוב החדש.

סיכום

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

6. CHARGE_PRORATED_PRICE

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

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

תרחיש לדוגמה

משתמש עם מינוי Basic (במחיר 4.99$ לחודש) מחליט לשדרג למינוי Premium (במחיר 9.99$ לחודש) ב-20 באפריל, כשנותרו לו כ-10 ימים עד לסיום מחזור החיוב החודשי.

במקרה כזה:

  • המשתמש מקבל גישה למינוי Premium באופן מיידי.
  • המשתמש יחויב מיד על ההפרש היחסי עבור 10 הימים שנותרו במחזור החיובים הנוכחי. הסכום הזה שווה בערך ל-2.99$, שזה מחיר התוכנית Premium ל-10 ימים.
  • תאריך החיוב של המשתמש לא משתנה.

קטע קוד

// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE;

SubscriptionProductReplacementParams subscriptionProductReplacementParams =
    SubscriptionProductReplacementParams.newBuilder()
        .setOldProductId(oldProductId)
        .setReplacementMode(replacementMode)
        .build();

ProductDetailsParams productDetailsParams =
    ProductDetailsParams.newBuilder()
        .setProductDetails(productDetails)
        .setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
        .setOfferToken(offerToken)
        .build();

List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
        .build();

billingClient.launchBillingFlow(activity, billingFlowParams);

שדרוג עם חיוב של CHARGE_PRORATED_PRICE

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Premium.

המשתמש ישודרג למינוי Premium באופן מיידי, ותאריך החידוש המקורי יישאר. הסכום שצריך לשלם באופן מיידי הוא ההפרש היחסי בין מחירי התוכניות Premium ו-Basic עבור הימים שנותרו במחזור הנוכחי. בתאריך החידוש, המשתמש יחויב בסכום החידוש המלא של מינוי Premium בסך 9.99$.

שדרוג לאחור עם CHARGE_PRORATED_PRICE

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Lite.

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

סיכום

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

7. CHARGE_FULL_PRICE

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

תרחיש לדוגמה

משתמש מנוי לתוכנית Basic (במחיר של 4.99$ לחודש החל מ-1 באפריל). ב-20 באפריל, המשתמש רוצה לעבור לתוכנית Premium (במחיר של 9.99$ לחודש).

במקרה כזה:

  • המשתמש יחויב באופן מיידי במחיר המלא של מינוי Premium‏ (9.99$).
  • הערך שנותר ממינוי Basic (למשל, ערך של 10 ימים) מומר לזמן שווה ערך במינוי Premium. בדוגמה הזו, 10 ימים של Basic שווים ל-5 ימים של Premium.
  • תאריך החידוש הבא של המשתמש ישתנה כך שיכלול את הזמן היחסי הזה. לכן, תאריך החידוש יהיה 25 במאי (20 באפריל + חודש + 5 ימים).
  • החידושים הבאים יתבצעו מדי חודש החל מ-25 במאי.

קטע קוד

// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE;

SubscriptionProductReplacementParams subscriptionProductReplacementParams =
    SubscriptionProductReplacementParams.newBuilder()
        .setOldProductId(oldProductId)
        .setReplacementMode(replacementMode)
        .build();

ProductDetailsParams productDetailsParams =
    ProductDetailsParams.newBuilder()
        .setProductDetails(productDetails)
        .setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
        .setOfferToken(offerToken)
        .build();

List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
        .build();

billingClient.launchBillingFlow(activity, billingFlowParams);

שדרוג עם חיוב מלא

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Premium.

המשתמש ישודרג לתוכנית Premium באופן מיידי. הסכום שיש לשלם באופן מיידי הוא המחיר המלא של מינוי Premium –‏ 9.99$. השווי היחסי של הזמן שנותר במינוי Basic יומר לזמן במינוי Premium החדש, כך שתאריך החידוש הראשון יידחה מעט. לאחר מכן, סכום החידוש יהיה 9.99 $לכל מחזור.

חזרה לסוג המינוי הקודם עם חיוב מלא

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Lite.

המשתמש/ת ישודרג/ת מיד לתוכנית Lite ויתחיל מחזור חיוב חדש. הסכום שצריך לשלם באופן מיידי הוא מחיר היעד המלא בסך 2.99$. החלק שלא נוצל במינוי Basic יומר לזמן במינוי Lite החדש, ותאריך החידוש הראשון יידחה. לאחר מכן, סכום החידוש יהיה 2.99 $לכל מחזור.

סיכום

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

8. WITHOUT_PRORATION

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

תרחיש לדוגמה

משתמש מנוי לתוכנית Basic (במחיר של 4.99$ לחודש החל מ-1 באפריל). ב-20 באפריל, המשתמש רוצה לעבור לתוכנית Premium (במחיר של 9.99$ לחודש).

במקרה כזה:

  • המשתמש מקבל גישה למינוי Premium באופן מיידי.
  • המשתמש לא צריך לשלם את המחיר הגבוה יותר של 9.99 $עד לתאריך חידוש המינוי הבא (1 במאי).

קטע קוד

// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION;

SubscriptionProductReplacementParams subscriptionProductReplacementParams =
    SubscriptionProductReplacementParams.newBuilder()
        .setOldProductId(oldProductId)
        .setReplacementMode(replacementMode)
        .build();

ProductDetailsParams productDetailsParams =
    ProductDetailsParams.newBuilder()
        .setProductDetails(productDetails)
        .setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
        .setOfferToken(offerToken)
        .build();

List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
        .build();

billingClient.launchBillingFlow(activity, billingFlowParams);

שדרוג עם WITHOUT_PRORATION

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Premium.

המשתמש משודרג למינוי Premium באופן מיידי, ותאריך החידוש הקיים נשמר. הסכום לתשלום מיידי הוא 0.00 $. למשתמש יש גישה למינוי Premium למשך הזמן שנותר במחזור הנוכחי, לפני המעבר לסכום החידוש החדש של ‎9.99 $בתאריך החיוב הבא.

שנמוך עם WITHOUT_PRORATION

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Lite.

המינוי של המשתמש ישודרג לאחור לתוכנית Lite באופן מיידי, והוא יאבד את התכונות של Basic שעליהן הוא שילם. הסכום לתשלום מיידי הוא 0.00 $. מחזור החיובים ימשיך ללא שינוי, והמשתמש ישלם את המחיר החדש והמוזל של 2.99 $בחידוש המינוי המתוזמן הבא.

סיכום

בקטע הזה ראינו איך WITHOUT_PRORATION מחליף מיד את ההרשאות של המשתמש בלי לחייב אותו על ההזמנה, ומשאיר את מחזור החיוב ללא שינוי.

9. בעיכוב

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

תרחיש לדוגמה

משתמש מנוי לתוכנית Basic (במחיר של 4.99$ לחודש החל מ-1 באפריל). ב-20 באפריל, המשתמש רוצה לעבור לתוכנית Premium (במחיר של 9.99$ לחודש).

במקרה כזה:

  • המשתמש לא יחויב באופן מיידי.
  • המשתמש ימשיך לקבל את התכונות של Basic עד סוף מחזור החיובים הנוכחי (30 באפריל).
  • תוכנית המינוי תשודרג אוטומטית ל-Premium בתאריך החידוש הבא (1 במאי).

קטע קוד

// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.DEFERRED;

SubscriptionProductReplacementParams subscriptionProductReplacementParams =
    SubscriptionProductReplacementParams.newBuilder()
        .setOldProductId(oldProductId)
        .setReplacementMode(replacementMode)
        .build();

ProductDetailsParams productDetailsParams =
    ProductDetailsParams.newBuilder()
        .setProductDetails(productDetails)
        .setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
        .setOfferToken(offerToken)
        .build();

List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
        .build();

billingClient.launchBillingFlow(activity, billingFlowParams);

שדרוג עם DEFERRED

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.DEFERRED.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Premium.

המשתמש יישאר בתוכנית Basic עד סוף מחזור החיובים הנוכחי. הסכום לתשלום מיידי הוא 0.00 $. בתאריך החידוש, ההרשאה שלהם תשודרג למינוי Premium והם יחויבו בסכום החידוש החדש של 9.99$.

שדרוג לאחור עם DEFERRED

כדי לדמות את התרחיש הזה:

  • ב-MainActivity של האפליקציה לדוגמה, מעדכנים את replacementMode בקטע הקוד ל-SubscriptionProductReplacementParams.ReplacementMode.DEFERRED.
  • מבצעים בנייה מחדש של האפליקציה ומפעילים אותה.
  • מבטלים את המינויים הקיימים (אם יש כאלה) מחנות Google Play ומחכים שהם יסתיימו.
  • רוכשים את מינוי Basic.
  • מעבר לתוכנית Lite.

המשתמש יישאר בתוכנית Basic עד סוף מחזור החיובים הנוכחי. הסכום לתשלום מיידי הוא 0.00 $. בתאריך החידוש, הזכאות שלהם משודרגת לתוכנית Lite והם יחויבו בסכום החידוש החדש של 2.99$.

סיכום

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

10. עיבוד בקצה העורפי ובצד הלקוח

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

תרחיש לדוגמה

  • למשתמש יש מינוי חודשי ל-Basic (product_id‏ basic_plan ו-purchase_token‏ basic_purchase_token_123).
  • המשתמש עובר לתוכנית Premium באמצעות מצב החלפה מיידית (אחד מהמצבים WITHOUT_PRORATION, ‏WITH_TIME_PRORATION, ‏CHARGE_PRORATED_PRICE, ‏CHARGE_FULL_PRICE)
  • אחרי שההחלפה של המינוי מצליחה, Google מתייחסת למינוי כמינוי חדש ויוצרת אסימון רכישה חדש ושונה לתוכנית פרימיום (‏product_id premium_plan ו-purchase_token premium_purchase_token_123).

עיבוד בצד הלקוח

onPurchasesUpdated

כשהרכישה החלופית תושלם, יופעל PurchasesUpdatedListener. למרות שזה היה מעבר, מערכת Google Play מתייחסת לתוכנית Premium כרכישה חדשה לגמרי.

האפליקציה תקבל אובייקט Purchase שמכיל את premium_purchase_token_123 אסימון הרכישה ואת product_id premium_plan. צריך להתייחס לזה בדיוק כמו למנוי חדש: לאמת את הטוקן ולהכין את הקרקע למתן גישה

@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {
        for (Purchase purchase : purchases) {
            // purchase.getPurchaseToken() = premium_purchase_token_123
            // purchase.getProducts() will contain premium_plan
            // Verify the purchase and grant entitlement
            handleNewPurchase(purchase);
        }
    }
}

queryPurchasesAsync

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

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

עיבוד בקצה העורפי (RTDN)

כשמתבצעת החלפה, Google Play שולחת התראה בזמן אמת למפתחים (RTDN) לנושא Pub/Sub שהגדרתם.

  • במקרה של החלפה מיידית, Google שולחת SUBSCRIPTION_PURCHASED RTDN עם טוקן הרכישה החדש.דוגמה למטען RTDN
    {
      "version":"1.0",
      "packageName":"com.google.play.billing.samples.subscriptions",
      "eventTimeMillis":"...",
      "subscriptionNotification":
      {
        "version":"1.0",
        "notificationType":4, // SUBSCRIPTION_PURCHASED
        "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription
      }
    }
    
  • כשהשרת מקבל את אסימון הרכישה החדש מ-RTDN, צריך להפעיל את API‏ purchases.subscriptionsV2 עם אסימון הרכישה החדש כדי לאחזר את פרטי הרכישה. תגובת ה-API מכילה את השדה linkedPurchaseToken שמשמש כדי לקבוע אם אסימון הרכישה מתייחס לרכישת מינוי חדש או להחלפת מינוי.
  • במקרה של החלפת מינוי, linkedPurchaseToken מתייחס לטוקן הרכישה של המינוי הישן. בדוגמה הזו, התשובה תהיה basic_purchase_token_123.דוגמה לתשובה GET purchases.subscriptionsV2
    curl \
    'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/<application_id>/purchases/subscriptionsv2/tokens/premium_purchase_token_123' \
    --header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
    --header 'Accept: application/json'
    
    {
      "kind": "androidpublisher#subscriptionPurchaseV2",
      "startTime": "...",
      "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
      "latestOrderId": "GPA.<order_id>",
      "linkedPurchaseToken": "basic_purchase_token_123", // The purchase token of the subscription that was replaced (Basic Plan in this case)
      "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
      "lineItems": [
        {
          "productId": "premium_plan", // productID of the new subscription (Premium Plan in this case)
          "expiryTime": "....",
          "autoRenewingPlan": {...},
          "offerDetails": {
            "basePlanId": "monthly-auto-renewing" // base plan ID of the new subscription
          },
          "itemReplacement": { // Details about the subscription replacement
            "productId": "subscription_basic", // productID of the old subscription (Basic Plan in this case)
            "replacementMode": "CHARGE_PRORATED_PRICE", // Replacement strategy used for this subscription change
            "basePlanId": "monthly-auto-renewing" // base plan ID of the old subscription 
          },
          "offerPhase": {...}
        }
      ],
      "etag": "<etag_value>"
    }
    
  • חובה לאשר את הרכישה החדשה של Premium. אפשר לעשות את זה באפליקציה או בשרת העורפי. אם לא נאשר את הרכישה תוך 3 ימים, יינתן החזר כספי וההרשאה תבוטל. לפרטים נוספים על עיבוד רכישות ואישור שלהן, אפשר לעיין במסמכי התיעוד למפתחים.

סיכום

בקטע הזה מוסבר איך לטפל בהחלפות מינויים מיידיות גם בצד הלקוח וגם בקצה העורפי שלכם. הבנתם שב-Google Play המינוי החדש נחשב לרכישה חדשה לגמרי, ולכן מונפק אסימון רכישה חדש. בצד הלקוח, צריך לעבד את הרכישה החדשה באמצעות PurchasesUpdatedListener ולעדכן את ההרשאות על סמך התגובה מ-queryPurchasesAsync. בצד השרת, צריך להאזין ל-SUBSCRIPTION_PURCHASED RTDNs עבור האסימון החדש, להשתמש ב-API‏ purchases.subscriptionsv2 כדי לזהות את linkedPurchaseToken של המינוי הישן ולבטל מיד את הגישה שמשויכת לאסימון הישן, תוך מתן ההרשאה החדשה. חשוב לזכור לאשר תמיד את הרכישה החדשה.

11. עיבוד החלפות שנדחו

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

תרחיש לדוגמה

  • למשתמש יש מינוי חודשי ל-Basic (product_id‏ basic_plan ו-purchase_token‏ basic_purchase_token_123) שיתחדש ב-15 באפריל.
  • ב-1 באפריל, המשתמש מחליט לעבור לתוכנית Premium באמצעות ReplacementMode.DEFERRED.
  • ‫Google יוצרת באופן מיידי טוקן רכישה חדש לתוכנית Premium (product_id‏ premium_plan ו-purchase_token‏ premium_purchase_123), אבל הסכום שיחויב מהמשתמש והזכאות מתוזמנים ל-15 באפריל.

עיבוד החלפה שנדחתה

1. מיד אחרי שתהליך הרכישה מסתיים בהצלחה (באפליקציה)

  • PurchasesUpdatedListener מופעל אחרי שתהליך הרכישה מסתיים. האפליקציה תקבל אובייקט Purchase שמכיל את טוקן הרכישה החדש premium_purchase_token_123, אבל הערך של product_id עדיין יפנה אל basic_plan הישן כי למשתמש יש זכאות רק למינוי Basic. צריך להתייחס לזה בדיוק כמו לרכישה חדשה ולאשר את הטוקן.
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {
            for (Purchase purchase : purchases) {
                // purchase.getPurchaseToken() = premium_purchase_token_123
                // purchase.getProducts() will contain basic_plan
                // Verify and acknowledge the purchase
                handleNewPurchase(purchase);
            }
        }
    }
    
  • queryPurchasesAsync מחזירה את הרכישה עם אסימון הרכישה החדש (premium_purchase_token_123) באופן מיידי, ואת ההרשאה המקורית (basic_plan) שמשויכת אליה. אתם יכולים להסתמך על זה כדי להמשיך להעניק למשתמש זכאות לתוכנית Basic.

2. מיד אחרי שתהליך הרכישה מסתיים בהצלחה (בק-אנד)

  • הודעת RTDN מסוג SUBSCRIPTION_PURCHASED נשלחת מיד אחרי תהליך הרכישה של טוקן הרכישה החדש (premium_purchase_token_123).דוגמה למטען ייעודי (payload) של RTDN
    {
      "version":"1.0",
      "packageName":"com.google.play.billing.samples.subscriptions",
      "eventTimeMillis":"...",
      "subscriptionNotification":
      {
        "version":"1.0",
        "notificationType":4, // SUBSCRIPTION_PURCHASED
        "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription
      }
    }
    
  • מתקשרים אל GET purchases.subscriptionsv2 עם אסימון הרכישה החדש כדי לאחזר את פרטי הרכישה. התשובה מכילה 2 פריטים.
    • אחד מייצג את המינוי הישן (המינוי הבסיסי) ויש לו expiryTime עתידי. המינוי הישן לא יחודש, ובמקומו יופיע deferredItemReplacement עם המינוי החדש (תוכנית פרימיום). המשמעות היא שהחלפה של ההרשאה הישנה נמצאת בהמתנה עד שתוקף ההרשאה יפוג.
    • אחד שמייצג את המינוי החדש שנרכש. לא הוגדר ערך ל-expiryTime
    דוגמה לתגובה מה-API
    {
      "kind": "androidpublisher#subscriptionPurchaseV2",
      "startTime": "2026-05-07T15:50:11.383Z",
      "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
      "latestOrderId": "GPA.<order_id>",
      "linkedPurchaseToken": "basic_purchase_token_123",
      "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
      "lineItems": [
        {
          "productId": "premium_plan", // Premium Plan has no expiry time
          "autoRenewingPlan": {...},
          "offerDetails": {...},
          "itemReplacement": {. // Subscription replacement details
            "productId": "basic_plan",
            "replacementMode": "DEFERRED",
            "basePlanId": "monthly-auto-renewing"
          },
          "offerPhase": {}
        },
        {
          "productId": "basic_plan", // Subscription to be replaced
          "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time in the future
          "autoRenewingPlan": {},
          "offerDetails": {...},
          "deferredItemReplacement": { // identifier indicating this subscription will be replaced upon renewal
            "productId": "subscription_premium"
          },
          "latestSuccessfulOrderId": "GPA.<order_id>",
          "itemReplacement": {...},
        }
      ],
      "etag": "<etag>"
    }
    
  • חובה לאשר את אסימון הרכישה החדש. אפשר לעשות את זה באפליקציה או בשרת העורפי. לפרטים נוספים על עיבוד רכישות ואישור שלהן, אפשר לעיין במסמכי התיעוד למפתחים.
  • הודעת RTDN מסוג SUBSCRIPTION_EXPIRED נשלחת עבור טוקן הרכישה הישן (basic_purchase_token_123).דוגמה למטען ייעודי (payload) של RTDN
    {
      "version":"1.0",
      "packageName":"com.google.play.billing.samples.subscriptions",
      "eventTimeMillis":"...",
      "subscriptionNotification":
      {
        "version":"1.0",
        "notificationType":13, // SUBSCRIPTION_EXPIRED
        "purchaseToken":"basic_purchase_token_123" //purchase token for the old subscription
      }
    }
    
  • כשמתקשרים אל GET purchases.subscriptionsv2 API עם אסימון הרכישה הישן, הוא מופיע כאסימון שפג תוקפו (SUBSCRIPTION_STATE_EXPIRED). הזכאות למינוי הישן מועברת לרכישה החדשה למשך הזמן שנותר.

3. בתאריך ההחלפה – החידוש הראשון אחרי תהליך הרכישה (אפליקציה)

  • queryPurchasesAsync מחזירה את הרכישה עם אסימון הרכישה החדש (premium_purchase_token_123) והמינוי החדש שמשויך אליה (premium_plan).
  • תהליך הרכישה החדש אמור להיות כבר מעובד כשהתהליך מסתיים בהצלחה, ולא צריך לבצע פעולה מיוחדת מלבד לוודא שהמשתמש קיבל גישה למינוי הנכון.

4. בתאריך ההחלפה – החידוש הראשון אחרי תהליך הרכישה (בקצה העורפי)

  • ב-ReplacementMode.DEFERRED, חידושים ראשונים מתבצעים בהתאם להתנהגות הרגילה של כל חידוש אחר שמעבד SUBSCRIPTION_RENEWED RTDNs. במקרה כזה, לא צריך להשתמש בלוגיקה מיוחדת כדי להחליף את התמונות.
  • מתקשרים אל GET purchases.subscriptionsv2 עם אסימון הרכישה החדש כדי לאחזר את פרטי הרכישה. התשובה מכילה 2 פריטים.
    • אחד מייצג את המינוי הישן (התוכנית הבסיסית) וכולל את הערך expiryTime שחל בעבר. למינוי הישן לא יהיה יותר ערך בשדה deferredItemReplacement.
    • אחד שמייצג את המינוי החדש עם expiryTime בעתיד והשדה autoRenewEnabled מוגדר ל-true.
    תגובה לדוגמה מ-API
    {
      "kind": "androidpublisher#subscriptionPurchaseV2",
      "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
      "latestOrderId": "GPA.<order_id>..0",
      "linkedPurchaseToken": "basic_purchase_token_123", // purchase token of the old subscription
      "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
      "lineItems": [
        {
          "productId": "premium_plan", // New subscription
          "expiryTime": "2026-05-07T16:00:09.437Z", // Expiry time set in the future
          "autoRenewingPlan": {
            "autoRenewEnabled": true, // Auto Renewing Flag set to True
            "recurringPrice": {...}
          },
          "offerDetails": {...},
          "latestSuccessfulOrderId": "GPA.<order_id>..0",
          "itemReplacement": {. // Details of the subscription replacement
            "productId": "basic_plan",
            "replacementMode": "DEFERRED",
            "basePlanId": "monthly-auto-renewing"
          },
          "offerPhase": {...}
        },
        {
          "productId": "basic_plan", // Old subscription, Does not contains the deferredItemReplacement field
          "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time set in the past
          "autoRenewingPlan": {},
          "offerDetails": {...},
          "latestSuccessfulOrderId": "GPA.<order_id>..0",
          "itemReplacement": {...},
        }
      ],
      "etag": "<etag>"
    }
    

סיכום

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

12. החלפת מינוי – סביבת Playground

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

הגדרה

כדי להשתמש בתכונה Replacement Playground, אתם צריכים לוודא את הדברים הבאים:

  • הערך packageId בקובץ build.gradle תואם לאפליקציה שהוגדרה ב-Google Play Console.
  • חשבון למטרות בדיקה שלכם רשום כבודק רישיונות ב-Google Play Console. מידע נוסף על בדיקת רישיונות זמין במאמר בנושא בדיקת הטמעת החיוב באפליקציה.

החלפת מינוי – סביבת Playground

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

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

  1. עוברים לכרטיסייה Playground (סביבת משחקים).
  2. אם יש לכם מינוי פעיל: הוא יסומן. זהו המינוי שיוחלף.

דף הבית של Playground

  1. אם אין לכם מינוי פעיל: אתם צריכים לרכוש מינוי.
    • כברירת מחדל, ב-Playground מופיעים מינויי Basic, ‏ Premium ו-Lite שנוצרו בשביל ה-Codelab הזה.
    • כדי לבצע בדיקה עם תוכניות אחרות שהוגדרו ב-Play Console, לוחצים על הוספת תוכנית בהתאמה אישית, מחפשים לפי productId וbasePlanId.
    • רוכשים את המינוי שנבחר.
    • עכשיו אמור להופיע המינוי הפעיל החדש שנרכש על ידי המשתמש. הוספת מינוי בהתאמה אישית
  2. בוחרים את מינוי היעד שאליו המשתמש רוצה לעבור .
  3. בוחרים מצב החלפה למעבר.

בחירת מצב החלפה

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

עגלת קניות לחיוב על החלפת מינוי

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

ניהול מינויים בחנות Play

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

מסמכי עזר

14. מזל טוב

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

מה למדתם

  • איך מגדירים את SubscriptionProductReplacementParams עם מצבי החלפה ספציפיים.
  • ההבדל בין שדרוגים מיידיים לבין שדרוגים לאחור שמתבצעים במועד מאוחר יותר.
  • איך משביתים אסימוני מינוי ישנים באמצעות linkedPurchaseToken באמצעות RTDNs.

סקר

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