במאמר הזה מוסבר איך לשלב את ספריית החיוב ב-Google Play באפליקציה כדי להתחיל למכור מוצרים.
מחזור החיים של רכישה
זהו תהליך רכישה אופייני לרכישה חד-פעמית או למינוי.
- מראים למשתמש מה הוא יכול לקנות.
- מפעילים את תהליך הרכישה כדי שהמשתמש יאשר את הרכישה.
- מאמתים את הרכישה בשרת.
- להעביר תוכן למשתמש.
- אישור המסירה של התוכן. במקרה של מוצרי צריכה, צריך לבצע צריכה של הרכישה כדי שהמשתמש יוכל לקנות את הפריט שוב.
המינויים מתחדשים אוטומטית עד שהם מבוטלים. מינוי יכול לעבור בין המצבים הבאים:
- פעיל: המשתמש עומד בתנאים ויש לו גישה למינוי.
- בוטל: המשתמש ביטל את המינוי אבל עדיין יש לו גישה עד שתוקף המינוי יפוג.
- בתקופת חסד: למשתמש הייתה בעיה בתשלום, אבל עדיין יש לו גישה בזמן ש-Google מנסה שוב לחייב את אמצעי התשלום.
- בהמתנה: למשתמש הייתה בעיה בתשלום ואין לו יותר גישה, בזמן ש-Google מנסה לחייב שוב את אמצעי התשלום.
- בהשהיה: המשתמש השהה את הגישה שלו ואין לו גישה עד שהוא יחדש אותה.
- פג תוקף: המשתמש ביטל את המינוי ואיבד את הגישה אליו. המשתמש נחשב כמי שביטל את המינוי בתאריך התפוגה.
הפעלת חיבור ל-Google Play
השלב הראשון בשילוב עם מערכת החיוב של Google Play הוא להוסיף את ספריית החיוב של Google Play לאפליקציה ולהפעיל חיבור.
הוספת התלות בספריית החיובים ב-Google Play
מוסיפים את התלות בספריית החיובים ב-Google Play לקובץ build.gradle
של האפליקציה, כמו שמוצג כאן:
Groovy
dependencies { def billing_version = "8.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "8.0.0" implementation("com.android.billingclient:billing:$billing_version") }
אם אתם משתמשים ב-Kotlin, מודול ה-KTX של ספריית החיובים ב-Google Play כולל תוספים של Kotlin ותמיכה ב-coroutines, שמאפשרים לכם לכתוב קוד Kotlin אידיומטי כשאתם משתמשים בספריית החיובים ב-Google Play. כדי לכלול את התוספים האלה בפרויקט, מוסיפים את התלות הבאה לקובץ build.gradle
של האפליקציה, כמו שמוצג:
Groovy
dependencies { def billing_version = "8.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "8.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
הפעלת BillingClient
אחרי שמוסיפים תלות בספריית החיובים ב-Google Play, צריך לאתחל מופע של BillingClient
. BillingClient
הוא הממשק הראשי לתקשורת בין ספריית החיובים ב-Google Play לבין שאר האפליקציה. BillingClient
מספק שיטות נוחות, סינכרוניות ואסינכרוניות, להרבה פעולות חיוב נפוצות. חשוב לשים לב לנקודות הבאות:
- מומלץ להשאיר פתוח חיבור פעיל אחד של
BillingClient
בכל פעם כדי להימנע מכמה קריאות חוזרות (callback) שלPurchasesUpdatedListener
לאותו אירוע. - מומלץ ליצור חיבור ל-BillingClient כשהאפליקציה מופעלת או מועברת לחזית, כדי להבטיח שהאפליקציה תעבד רכישות בזמן. אפשר לעשות את זה באמצעות
ActivityLifecycleCallbacks
שנרשם על ידיregisterActivityLifecycleCallbacks
והאזנה ל-onActivityResumed כדי לאתחל חיבור כשמזהים לראשונה פעילות שמתחדשת. מידע נוסף על הסיבות לכך שכדאי לפעול לפי השיטה המומלצת הזו זמין בקטע בנושא עיבוד רכישות. חשוב גם לזכור לסיים את החיבור כשסוגרים את האפליקציה.
כדי ליצור BillingClient
, משתמשים ב-newBuilder
. אפשר להעביר כל הקשר אל newBuilder()
, ו-BillingClient
משתמש בו כדי לקבל הקשר של אפליקציה. זה אומר שלא צריך לדאוג לגבי דליפות זיכרון. כדי לקבל עדכונים על רכישות, צריך גם להתקשר אל setListener
ולהעביר הפניה אל PurchasesUpdatedListener
. המאזין הזה מקבל עדכונים על כל הרכישות באפליקציה.
Kotlin
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
Java
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build();
חיבור ל-Google Play
אחרי שיוצרים BillingClient
, צריך ליצור חיבור ל-Google Play.
כדי להתחבר ל-Google Play, מתקשרים למספר startConnection
. תהליך החיבור הוא אסינכרוני, ולכן צריך להטמיע BillingClientStateListener
כדי לקבל קריאה חוזרת (callback) אחרי שההגדרה של הלקוח תושלם והוא יהיה מוכן לשלוח בקשות נוספות.
בנוסף, צריך להטמיע לוגיקה של ניסיון חוזר כדי לטפל במקרים של ניתוקים מ-Google Play.
כדי להטמיע לוגיקה של ניסיון חוזר, צריך לבטל את השיטה של הקריאה החוזרת onBillingServiceDisconnected()
ולוודא שהשיטה BillingClient
קוראת לשיטה startConnection()
כדי להתחבר מחדש ל-Google Play לפני שליחת בקשות נוספות.
בדוגמה הבאה מוצג איך להתחיל חיבור ולבדוק שהוא מוכן לשימוש:
Kotlin
billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(billingResult: BillingResult) { if (billingResult.responseCode == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } override fun onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } })
Java
billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } @Override public void onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } });
חיבור מחדש אוטומטי
עם ההשקה של השיטה enableAutoServiceReconnection()
ב-BillingClient.Builder
בגרסה 8.0.0, Play Billing Library יכולה עכשיו ליצור מחדש באופן אוטומטי את חיבור השירות אם מתבצעת קריאה ל-API בזמן שהשירות מנותק. הדבר עלול להוביל לצמצום התשובות של SERVICE_DISCONNECTED
, כי החיבור מחדש מתבצע באופן פנימי לפני ביצוע הקריאה ל-API.
איך מפעילים חיבור מחדש אוטומטי
כשיוצרים מופע של BillingClient
, משתמשים בשיטה enableAutoServiceReconnection()
ב-BillingClient.Builder
כדי להפעיל חיבור מחדש אוטומטי.
Kotlin
val billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build()
Java
BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build();
הצגת מוצרים שזמינים לקנייה
אחרי שיוצרים חיבור ל-Google Play, אפשר לשלוח שאילתות כדי לראות את המוצרים הזמינים ולהציג אותם למשתמשים.
הצגת פרטי המוצר למשתמשים היא שלב חשוב, כי היא מאפשרת להציג מידע על המוצר בשפה המקומית. לגבי מינויים, צריך לוודא שהצגת המוצרים עומדת בכל כללי המדיניות של Play.
כדי לשלוח שאילתה לגבי פרטי מוצרים בחיוב חד-פעמי, צריך לבצע קריאה ל-method queryProductDetailsAsync
. השיטה הזו יכולה להחזיר כמה מבצעים בהתאם להגדרות המוצר בחיוב חד-פעמי. מידע נוסף על אפשרויות רכישה ומבצעים שונים למוצרים בחיוב חד-פעמי
כדי לטפל בתוצאה של הפעולה האסינכרונית, צריך לציין גם מאזין שמטמיע את הממשק ProductDetailsResponseListener
.
אחר כך אפשר לבטל את onProductDetailsResponse
, שמודיע למאזין כשהשאילתה מסתיימת, כמו בדוגמה הבאה:
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, queryProductDetailsResult -> if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult.getProductDetailsList()) { // Process successfully retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } }
Java
QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build(); billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, QueryProductDetailsResult queryProductDetailsResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult().getProductDetailsList()) { // Process success retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } } } )
כשמבצעים שאילתה לגבי פרטי מוצר, מעבירים מופע של QueryProductDetailsParams
שמציין רשימה של מחרוזות של מזהי מוצרים שנוצרו ב-Google Play Console, יחד עם ProductType
. הערך של המאפיין ProductType
יכול להיות ProductType.INAPP
למוצרים עם חיוב חד-פעמי או ProductType.SUBS
למינויים.
שאילתה עם תוספי Kotlin
אם משתמשים בתוספים של Kotlin, אפשר לשלוח שאילתה לגבי פרטי מוצר חד-פעמי על ידי קריאה לפונקציית התוסף queryProductDetails()
.
queryProductDetails()
משתמשת ב-Kotlin coroutines כדי שלא תצטרכו להגדיר listener נפרד. במקום זאת, הפונקציה מושהית עד שהשאילתה מסתיימת, ואז אפשר לעבד את התוצאה:
suspend fun processPurchases() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("product_id_example")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)
// leverage queryProductDetails Kotlin extension function
val productDetailsResult = withContext(Dispatchers.IO) {
billingClient.queryProductDetails(params.build())
}
// Process the result.
}
במקרים נדירים, חלק מהמכשירים לא תומכים ב-ProductDetails
וב-queryProductDetailsAsync()
, בדרך כלל בגלל גרסאות מיושנות של שירותי Google Play. כדי לספק תמיכה מתאימה לתרחיש הזה, כדאי לעיין במדריך העברה לגרסה 7 של ספריית החיובים ב-Play וללמוד איך להשתמש בתכונות של תאימות לאחור.
עיבוד התוצאה
ספריית החיובים ב-Google Play מאחסנת את תוצאות השאילתה באובייקט QueryProductDetailsResult
. QueryProductDetailsResult
מכיל List
של ProductDetails
אובייקטים. לאחר מכן תוכלו להפעיל מגוון שיטות על כל אובייקט ProductDetails
ברשימה כדי לראות מידע רלוונטי על מוצר חד-פעמי שאוחזר בהצלחה, כמו המחיר או התיאור שלו. כדי לראות את פרטי המוצר הזמינים, אפשר לעיין ברשימת השיטות במחלקה ProductDetails
.
QueryProductDetailsResult
מכיל גם List
של אובייקטים מסוג UnfetchedProduct
. לאחר מכן אפשר לשלוח שאילתה לכל UnfetchedProduct כדי לקבל קוד סטטוס שמתאים לסיבת הכישלון של האחזור.
כדי לראות את פרטי המוצרים הזמינים שלא נשלפו, אפשר לעיין ברשימת השיטות במחלקה UnfetchedProduct
.
לפני שמציעים פריט למכירה, צריך לבדוק שהמשתמש לא כבר בבעלותו. אם למשתמש יש פריט מתכלה שעדיין נמצא בספריית הפריטים שלו, הוא צריך להשתמש בו לפני שהוא יכול לקנות אותו שוב.
לפני שמציעים מינוי, צריך לוודא שהמשתמש לא רשום כבר למינוי. חשוב גם לזכור:
במקרה של מינויים, הפונקציה
queryProductDetailsAsync()
מחזירה פרטים על מוצר המינוי ומקסימום 50 מבצעים שמשתמשים יכולים לממש לכל מינוי. אם המשתמש מנסה לרכוש מבצע שלא עומד בדרישות (לדוגמה, אם באפליקציה מוצגת רשימה לא עדכנית של מבצעים שעומדים בדרישות), מערכת Play מודיעה למשתמש שהוא לא עומד בדרישות, והוא יכול לבחור לרכוש במקום זאת את המינוי הבסיסי.במוצרים חד-פעמיים, השיטה
queryProductDetailsAsync()
מחזירה רק את המבצעים שהמשתמש עומד בדרישות שלהם. אם המשתמש מנסה לרכוש מבצע שהוא לא עומד בתנאים שלו (לדוגמה, אם המשתמש הגיע למגבלת כמות הרכישה), מערכת Play מודיעה למשתמש שהוא לא עומד בתנאים, והמשתמש יכול לבחור לרכוש במקום זאת את המבצע של אפשרות הרכישה.
הפעלת תהליך הרכישה
כדי להתחיל בקשת רכישה מהאפליקציה, קוראים לשיטה launchBillingFlow()
מהשרשור הראשי של האפליקציה. השיטה הזו מקבלת הפניה לאובייקט BillingFlowParams
שמכיל את האובייקט הרלוונטי ProductDetails
שהתקבל מקריאה ל-queryProductDetailsAsync
. כדי ליצור אובייקט BillingFlowParams
, משתמשים במחלקה BillingFlowParams.Builder
.
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user. .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user. .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
השיטה launchBillingFlow()
מחזירה אחד מכמה קודי תגובה שמפורטים בטבלה BillingClient.BillingResponseCode
. חשוב לבדוק את התוצאה הזו כדי לוודא שלא היו שגיאות בהפעלת תהליך הרכישה. הערך BillingResponseCode
של OK
מציין שההפעלה בוצעה בהצלחה.
אם השיחה אל launchBillingFlow()
מצליחה, המערכת מציגה את מסך הרכישה של Google Play. איור 1 מציג מסך רכישה של מינוי:

Google Play מתקשרת אל onPurchasesUpdated()
כדי להעביר את התוצאה של פעולת הרכישה למאזין שמטמיע את הממשק PurchasesUpdatedListener
. המאזין מצוין באמצעות השיטה setListener()
כשמפעילים את הלקוח.
צריך להטמיע את onPurchasesUpdated()
כדי לטפל בקודי תגובה אפשריים. בדוגמה הבאה אפשר לראות איך מבטלים את ההגדרה של onPurchasesUpdated()
:
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
Java
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // Process the purchase as described in the next section. } } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
רכישה מוצלחת יוצרת מסך הצלחה של רכישה ב-Google Play, שדומה לאיור 2.

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

חובה להתייעץ עם Art. 6 (1) (ea) CRD of the Consumer Rights Directive 2011/83/EU כדי לקבוע אם המחיר שאתם מציעים למשתמשים הוא מחיר מותאם אישית.
setIsOfferPersonalized()
מקבלת קלט בוליאני. כשtrue
, הגילוי הנאות מופיע בממשק המשתמש של Play. אם false
, הגילוי הנאות לא יוצג בממשק המשתמש. ערך ברירת המחדל הוא false
.
מידע נוסף זמין במרכז העזרה לצרכנים.
צירוף מזהי משתמשים
כשמפעילים את תהליך הרכישה, האפליקציה יכולה לצרף מזהי משתמשים שיש לכם לגבי המשתמש שמבצע את הרכישה באמצעות obfuscatedAccountId או obfuscatedProfileId. מזהה לדוגמה יכול להיות גרסה מוצפנת של פרטי הכניסה של המשתמש במערכת שלכם. הגדרת הפרמטרים האלה יכולה לעזור ל-Google לזהות הונאות. בנוסף, היא יכולה לעזור לכם לוודא שהרכישות משויכות למשתמש הנכון, כמו שמוסבר במאמר בנושא הענקת הרשאות למשתמשים.
זיהוי ועיבוד של רכישות
הזיהוי והעיבוד של רכישה שמתוארים בקטע הזה רלוונטיים לכל סוגי הרכישות, כולל רכישות מחוץ לאפליקציה כמו מימוש מבצעים.
האפליקציה שלכם מזהה רכישות חדשות ורכישות בהמתנה שהושלמו באחת מהדרכים הבאות:
- כשמתבצעת קריאה ל-
onPurchasesUpdated
כתוצאה מקריאה של האפליקציה ל-launchBillingFlow
(כפי שמוסבר בקטע הקודם), או אם האפליקציה פועלת עם חיבור פעיל לספריית החיובים כשמתבצעת רכישה מחוץ לאפליקציה או כשמסתיימת רכישה בהמתנה. לדוגמה, בן משפחה מאשר רכישה בהמתנה במכשיר אחר. - כשהאפליקציה מפעילה את queryPurchasesAsync כדי לשלוח שאילתה לגבי הרכישות של המשתמש.
במקרה מספר 1, הקריאה ל-onPurchasesUpdated
תתבצע אוטומטית לרכישות חדשות או לרכישות שהושלמו, כל עוד האפליקציה פועלת ויש לה חיבור פעיל לספריית החיוב ב-Google Play. אם האפליקציה לא פועלת או שאין לה חיבור פעיל לספריית החיובים ב-Google Play, הפונקציה onPurchasesUpdated
לא תופעל. חשוב לזכור: מומלץ שאפליקציה תנסה לשמור על חיבור פעיל כל עוד היא פועלת בחזית, כדי שהיא תקבל עדכונים בזמן על רכישות.
בשלב 2, צריך להתקשר אל BillingClient.queryPurchasesAsync() כדי לוודא שהאפליקציה מעבדת את כל הרכישות. מומלץ לעשות זאת כשהאפליקציה יוצרת חיבור לספריית החיובים ב-Google Play (מומלץ לעשות זאת כשהאפליקציה מופעלת או עוברת לחזית, כפי שמתואר במאמר בנושא הפעלת BillingClient). כדי לעשות את זה, צריך לקרוא ל-queryPurchasesAsync כשמקבלים תוצאה מוצלחת ל-onServiceConnected. חשוב לפעול לפי ההמלצה הזו כדי לטפל באירועים ובמצבים כמו:
- בעיות ברשת במהלך הרכישה: משתמש יכול לבצע רכישה בהצלחה ולקבל אישור מ-Google, אבל הקישוריות לרשת במכשיר שלו נקטעת לפני שהמכשיר והאפליקציה מקבלים הודעה על הרכישה דרך
PurchasesUpdatedListener
. - כמה מכשירים: משתמש יכול לקנות פריט במכשיר אחד ואז לצפות לראות את הפריט כשהוא עובר למכשיר אחר.
- טיפול ברכישות שבוצעו מחוץ לאפליקציה: חלק מהרכישות, כמו מימוש מבצעים, יכולות להתבצע מחוץ לאפליקציה.
- טיפול במעברים בין מצבי רכישה: יכול להיות שמשתמש ישלים תשלום על רכישה במצב PENDING (בהמתנה) בזמן שהאפליקציה לא פועלת, ויצפה לקבל אישור על השלמת הרכישה כשהוא יפתח את האפליקציה.
אחרי שהאפליקציה מזהה רכישה חדשה או רכישה שהושלמה, היא צריכה:
- מאמתים את הרכישה.
- הענקת תוכן למשתמשים על רכישות שהושלמו.
- שולחים הודעה למשתמש.
- מודיעים ל-Google שהאפליקציה שלכם עיבדה רכישות שהושלמו.
השלבים האלה מוסברים בפירוט בקטעים הבאים, ולאחר מכן יש קטע שבו מסוכמים כל השלבים.
אימות הרכישה
האפליקציה צריכה תמיד לאמת את הלגיטימיות של הרכישות לפני שהיא מעניקה הטבות למשתמש. כדי לעשות זאת, צריך לפעול לפי ההנחיות שמפורטות במאמר בנושא אימות רכישות לפני הענקת הרשאות. רק אחרי אימות הרכישה, האפליקציה צריכה להמשיך בתהליך הרכישה ולהעניק למשתמש זכויות גישה, כמו שמוסבר בקטע הבא.
הענקת זכאות למשתמש
אחרי שהאפליקציה מאמתת רכישה, היא יכולה להמשיך להעניק את הזכאות למשתמש ולשלוח לו הודעה. לפני שמעניקים זכאות, צריך לוודא שהאפליקציה בודקת שסטטוס הרכישה הוא PURCHASED
. אם הרכישה במצב 'בהמתנה', האפליקציה צריכה להודיע למשתמש שהוא עדיין צריך לבצע פעולות כדי להשלים את הרכישה לפני שתינתן לו הרשאה.
צריך להעניק זכאות רק כשהרכישה עוברת מהסטטוס PENDING (בהמתנה) לסטטוס SUCCESS (הצלחה).
מידע נוסף זמין במאמר בנושא טיפול בעסקאות בהמתנה.
אם צירפתם מזהי משתמשים לרכישה, כמו שמתואר במאמר בנושא צירוף מזהי משתמשים, תוכלו לאחזר אותם ולהשתמש בהם כדי לשייך את הרכישה למשתמש הנכון במערכת שלכם. השיטה הזו שימושית כשמבצעים התאמה של רכישות, במקרים שבהם האפליקציה איבדה את ההקשר לגבי המשתמש שביצע את הרכישה. הערה: לרכישות שבוצעו מחוץ לאפליקציה לא יוגדרו המזהים האלה. במקרה כזה, האפליקציה יכולה להעניק את הזכאות למשתמש המחובר או להציג למשתמש הנחיה לבחור חשבון מועדף.
במקרה של הזמנות מראש, הרכישה נמצאת במצב 'בהמתנה' עד שמגיע מועד הפרסום. הרכישה בהזמנה מראש תושלם בשעת ההשקה והסטטוס ישתנה ל'נרכש' ללא צורך בפעולות נוספות.
הודעה למשתמש
אחרי שהמשתמשים יאשרו את הרכישה, באפליקציה שלך חייבת להופיע הודעה על כך שהרכישה בוצעה בהצלחה. ההודעה הזו מונעת מהמשתמש להתבלבל ולחשוב שהרכישה לא הושלמה בהצלחה, מה שעלול לגרום לו להפסיק להשתמש באפליקציה, לפנות לתמיכה או להתלונן על כך ברשתות החברתיות. חשוב לדעת שהאפליקציה שלך עשויה לזהות עדכוני רכישה בכל שלב במהלך מחזור החיים של האפליקציה. לדוגמה, הורה מאשר רכישה בהמתנה במכשיר אחר. במקרה כזה, יכול להיות שהאפליקציה תרצה לדחות את שליחת ההתראה למשתמש לזמן מתאים. דוגמאות למקרים שבהם מתאים להגדיר עיכוב:
- במהלך חלק הפעולה במשחק או בסצנות מעבר, הצגת הודעה עלולה להסיח את דעתו של המשתמש. במקרה כזה, צריך להודיע למשתמש אחרי שהחלק של הפעולה מסתיים.
- במהלך ההדרכה הראשונית ובחלקים של הגדרת המשתמש במשחק. לדוגמה, יכול להיות שמשתמש ביצע רכישה מחוץ לאפליקציה לפני שהוא התקין אותה. מומלץ להודיע למשתמשים חדשים על התגמול מיד אחרי שהם פותחים את המשחק או במהלך ההגדרה הראשונית של המשתמש. אם באפליקציה נדרש מהמשתמש ליצור חשבון או להתחבר לפני שניתנת לו הרשאה להשתמש בתוכן שרכש, מומלץ להסביר לו מה עליו לעשות כדי לקבל את התוכן שרכש. זה חשוב מאוד כי אם האפליקציה לא תעבד את הרכישה, יתבצע החזר כספי אחרי 3 ימים.
כששולחים למשתמש התראה על רכישה, Google Play ממליצה על המנגנונים הבאים:
- הצגת תיבת דו-שיח בתוך האפליקציה.
- העברת ההודעה לתיבת ההודעות באפליקציה, עם ציון ברור שיש הודעה חדשה בתיבת ההודעות באפליקציה.
- שימוש בהודעת התראה של מערכת ההפעלה.
ההתראה צריכה ליידע את המשתמש על ההטבה שהוא קיבל. לדוגמה, "רכשת 100 מטבעות זהב!". בנוסף, אם הרכישה בוצעה כתוצאה מהטבה של תוכנית כמו Play Pass, האפליקציה מעבירה את המידע הזה למשתמש. לדוגמה, 'התקבלו פריטים! קיבלת עכשיו 100 אבני חן עם Play Pass. Continue". יכול להיות שבכל תוכנית יהיו הנחיות לגבי הטקסט המומלץ להצגה למשתמשים כדי להסביר להם על היתרונות.
הודעה ל-Google שהרכישה עובדה
אחרי שהאפליקציה מעניקה למשתמש זכאות ומעדכנת אותו על העסקה שהושלמה, היא צריכה לעדכן את Google שהרכישה הושלמה בהצלחה. כדי למנוע החזר כספי אוטומטי על הרכישה וביטול הזכאות, צריך לאשר את הרכישה תוך שלושה ימים. בקטעים הבאים מתואר התהליך לאישור סוגים שונים של רכישות.
מוצרים מתכלים
למוצרים מתכלים, אם לאפליקציה שלכם יש בק-אנד מאובטח, מומלץ להשתמש ב-Purchases.products:consume
כדי לצרוך רכישות בצורה מהימנה. כדי לוודא שהרכישה לא נצרכה כבר, בודקים את consumptionState
בתוצאה של הקריאה ל-Purchases.products:get
. אם האפליקציה היא רק צד לקוח בלי קצה עורפי, צריך להשתמש ב-consumeAsync()
מספריית החיובים ב-Google Play. שתי השיטות עומדות בדרישה לאישור הרכישה ומציינות שהאפליקציה העניקה למשתמש זכאות למינוי.
בנוסף, השיטות האלה מאפשרות לאפליקציה להפוך את המוצר החד-פעמי שתואם לטוקן הרכישה שמוזן לזמין לרכישה חוזרת. ב-consumeAsync()
צריך גם להעביר אובייקט שמטמיע את הממשק ConsumeResponseListener
. האובייקט הזה מטפל בתוצאה של פעולת הצריכה. אפשר לבטל את השיטה onConsumeResponse()
, שספריית החיובים ב-Google Play קוראת לה כשהפעולה מסתיימת.
בדוגמה הבאה מוצג שימוש במוצר באמצעות ספריית החיוב ב-Google Play, עם אסימון הרכישה המשויך:
Kotlin
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
Java
ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // Handle the success of the consume operation. } } }; billingClient.consumeAsync(consumeParams, listener);
מוצרים לא מתכלים
כדי לאשר רכישות של מוצרים מתכלים, אם לאפליקציה שלכם יש קצה עורפי מאובטח, מומלץ להשתמש ב-Purchases.products:acknowledge
כדי לאשר רכישות בצורה מהימנה. כדי לוודא שהרכישה לא אושרה בעבר, בודקים את הערך של acknowledgementState
בתוצאה של הקריאה ל-Purchases.products:get
.
אם האפליקציה היא רק צד לקוח, צריך להשתמש ב-BillingClient.acknowledgePurchase()
מספריית החיובים ב-Google Play באפליקציה. לפני אישור רכישה, האפליקציה צריכה לבדוק אם הרכישה כבר אושרה באמצעות השיטה isAcknowledged()
בספריית החיובים ב-Google Play.
בדוגמה הבאה אפשר לראות איך מאשרים רכישה באמצעות ספריית החיוב ב-Google Play:
Kotlin
val client: BillingClient = ... val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ... val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
Java
BillingClient client = ... AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ... AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
מינויים
הטיפול במינויים דומה לטיפול בפריטים לא מתכלים. אם אפשר, כדאי להשתמש ב-Purchases.subscriptions.acknowledge
מ-Google Play Developer API כדי לאשר את הרכישה בצורה מהימנה מהקצה העורפי המאובטח. כדי לוודא שהרכישה לא אושרה בעבר, בודקים את acknowledgementState
במשאב הרכישה מ-Purchases.subscriptions:get
. אפשר גם לאשר מינוי באמצעות BillingClient.acknowledgePurchase()
מתוך ספריית החיוב ב-Google Play אחרי שמסמנים את isAcknowledged()
. צריך לאשר את כל הרכישות הראשוניות של מינויים. אין צורך לאשר חידוש מינוי. מידע נוסף על המקרים שבהם צריך לאשר מינויים זמין במאמר בנושא מכירת מינויים.
Recap
בקטע הקוד הבא מוצג סיכום של השלבים האלה.
Kotlin
fun handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. 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 (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
Java
void handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. 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 (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
כדי לוודא שהטמעתם את השלבים האלה באפליקציה בצורה נכונה, אתם יכולים לפעול לפי מדריך הבדיקה.
טיפול בעסקאות בהמתנה
חנות Google Play תומכת בעסקאות בהמתנה, כלומר בעסקאות שדורשות שלב אחד או יותר בין הרגע שבו המשתמש יוזם רכישה לבין הרגע שבו אמצעי התשלום של הרכישה עובר עיבוד. האפליקציה לא צריכה להעניק זכאות לסוגי הרכישות האלה עד ש-Google תודיע לכם שאמצעי התשלום של המשתמש חויב בהצלחה.
לדוגמה, משתמש יכול להתחיל עסקה על ידי בחירת חנות פיזית שבה הוא ישלם במזומן במועד מאוחר יותר. המשתמש מקבל קוד גם בהתראה וגם באימייל. כשהמשתמש מגיע לחנות הפיזית, הוא יכול למסור את הקוד לקופאי ולשלם במזומן. Google תשלח לכם ולמשתמש הודעה על קבלת התשלום. לאחר מכן האפליקציה יכולה להעניק למשתמש זכאות.
מתקשרים אל enablePendingPurchases()
כחלק מהפעלת BillingClient
כדי להפעיל עסקאות בהמתנה באפליקציה. האפליקציה צריכה להפעיל עסקאות בהמתנה ולתמוך בהן עבור מוצרים בחיוב חד-פעמי. לפני שמוסיפים תמיכה, חשוב להבין את מחזור החיים של הרכישה לעסקאות בהמתנה.
כשהאפליקציה מקבלת רכישה חדשה, דרך PurchasesUpdatedListener
או כתוצאה מקריאה ל-queryPurchasesAsync
, צריך להשתמש בשיטה getPurchaseState()
כדי לקבוע אם מצב הרכישה הוא PURCHASED
או PENDING
. צריך להעניק הרשאה רק כשהסטטוס הוא PURCHASED
.
אם האפליקציה פועלת ויש לכם חיבור פעיל לספריית החיובים ב-Play כשמשתמש משלים רכישה, הפונקציה PurchasesUpdatedListener
נקראת שוב, והערך של PurchaseState
הוא עכשיו PURCHASED
. בשלב הזה, האפליקציה יכולה לעבד את הרכישה באמצעות השיטה הרגילה לזיהוי רכישות ועיבודן. בנוסף, האפליקציה צריכה להפעיל את השיטה queryPurchasesAsync()
בשיטה onResume()
של האפליקציה כדי לטפל ברכישות שעברו למצב PURCHASED
בזמן שהאפליקציה לא פעלה.
כשהרכישה עוברת מסטטוס PENDING
לסטטוס PURCHASED
, לקוח real_time_developer_notifications מקבל התראה ONE_TIME_PRODUCT_PURCHASED
או SUBSCRIPTION_PURCHASED
. אם הרכישה תבוטל, תקבלו התראה ONE_TIME_PRODUCT_CANCELED
או SUBSCRIPTION_PENDING_PURCHASE_CANCELED
. יכול להיות שהסיבה לכך היא שהלקוח לא השלים את התשלום במסגרת הזמן הנדרשת. הערה: תמיד אפשר להשתמש ב-Google Play Developer API כדי לבדוק את הסטטוס הנוכחי של רכישה.
טיפול ברכישות בכמות גדולה
בגרסה 4.0 ואילך של ספריית החיובים ב-Google Play, לקוחות יכולים לרכוש יותר ממוצר חד-פעמי זהה בעסקה אחת על ידי ציון כמות בעגלת הקניות. האפליקציה צריכה לטפל ברכישות בכמות גדולה ולהעניק זכאות על סמך כמות הרכישה שצוינה.
כדי לאפשר רכישות של כמה פריטים, לוגיקת ההקצאה של האפליקציה צריכה לבדוק את כמות הפריטים. אפשר לגשת לשדה quantity
מאחד מממשקי ה-API הבאים:
-
getQuantity()
מספריית החיובים ב-Google Play. -
Purchases.products.quantity
מ-Google Play Developer API
אחרי שמוסיפים לוגיקה לטיפול ברכישות של כמה יחידות, צריך להפעיל את התכונה של רכישת כמה יחידות למוצר המתאים בדף ניהול המוצרים לרכישה חד-פעמית ב-Google Play Console.
שאילתה לגבי הגדרת החיוב של משתמש
getBillingConfigAsync()
מציין את המדינה שבה המשתמש משתמש ב-Google Play.
אפשר לשלוח שאילתה לגבי הגדרות החיוב של המשתמש אחרי יצירת
BillingClient
. בקטע הקוד הבא מוסבר איך לבצע קריאה ל-getBillingConfigAsync()
. מטפלים בתגובה על ידי הטמעה של BillingConfigResponseListener
. המאזין הזה מקבל עדכונים לגבי כל השאילתות של הגדרות החיוב שהופעלו מהאפליקציה.
אם התוצאה של BillingResult
לא מכילה שגיאות, אפשר לבדוק את השדה countryCode
באובייקט BillingConfig
כדי לקבל את המדינה שמוגדרת למשתמש ב-Play.
Kotlin
// Use the default GetBillingConfigParams. val getBillingConfigParams = GetBillingConfigParams.newBuilder().build() billingClient.getBillingConfigAsync(getBillingConfigParams, object : BillingConfigResponseListener { override fun onBillingConfigResponse( billingResult: BillingResult, billingConfig: BillingConfig? ) { if (billingResult.responseCode == BillingResponseCode.OK && billingConfig != null) { val countryCode = billingConfig.countryCode ... } else { // TODO: Handle errors } } })
Java
// Use the default GetBillingConfigParams. GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build(); billingClient.getBillingConfigAsync(getBillingConfigParams, new BillingConfigResponseListener() { public void onBillingConfigResponse( BillingResult billingResult, BillingConfig billingConfig) { if (billingResult.getResponseCode() == BillingResponseCode.OK && billingConfig != null) { String countryCode = billingConfig.getCountryCode(); ... } else { // TODO: Handle errors } } });
תזכורות על עגלות קניות נטושות במסך הבית של Google Play Games (מופעל כברירת מחדל)
מפתחי משחקים שמבצעים מונטיזציה באמצעות מוצרים חד-פעמיים יכולים למכור יחידות לניהול מלאי (SKU) שפעילות ב-Google Play Console מחוץ לאפליקציה שלהם. אחת הדרכים לעשות זאת היא באמצעות התכונה 'תזכורת על נטישת עגלת קניות', שמעודדת משתמשים להשלים רכישות שהם נטשו קודם לכן בזמן שהם גולשים בחנות Google Play. הרכישות האלה מתבצעות מחוץ לאפליקציה, בדף הבית של Google Play Games בחנות Google Play.
התכונה הזו מופעלת כברירת מחדל כדי לעזור למשתמשים להמשיך מאיפה שהם הפסיקו וכדי לעזור למפתחים להגדיל את היקף המכירות. עם זאת, אפשר לבטל את ההסכמה לשימוש בתכונה הזו באפליקציה באמצעות טופס ביטול ההסכמה לשימוש בתכונה 'תזכורת על נטישת עגלת קניות'. במאמר יצירת מוצר מתוך האפליקציה מפורטות שיטות מומלצות לניהול מק"טים ב-Google Play Console.
בתמונות הבאות אפשר לראות את התזכורת על נטישת עגלת קניות בחנות Google Play:

