{"id":137900,"date":"2021-03-24T00:00:00","date_gmt":"2021-03-24T00:00:00","guid":{"rendered":"https:\/\/adapty.io\/pl-android-in-app-purchases-google-play-billing-library-part-2\/"},"modified":"2021-03-24T00:00:00","modified_gmt":"2021-03-24T00:00:00","slug":"android-in-app-purchases-google-play-billing-library-part-2","status":"publish","type":"post","link":"https:\/\/adapty.io\/pl\/blog\/android-in-app-purchases-google-play-billing-library-part-2\/","title":{"rendered":"Zakupy w aplikacji na Androida, cz\u0119\u015b\u0107 2: przetwarzanie zakup\u00f3w za pomoc\u0105 Google Play Billing Library"},"content":{"rendered":"\n

W poprzednim artykule stworzyli\u015bmy klas\u0119 wrapper do pracy z Billing Library:<\/p>\n\n\n\n

<\/path><\/path><\/svg><\/span>
import<\/span> <\/span>android.content.Context<\/span><\/span>\nimport<\/span> <\/span>com.android.billingclient.api.*<\/span><\/span>\nclass<\/span> <\/span>BillingClientWrapper<\/span>(<\/span>context<\/span>:<\/span> <\/span>Context<\/span>)<\/span> <\/span>:<\/span> <\/span>PurchasesUpdatedListener<\/span> <\/span>{<\/span><\/span>\n   <\/span>interface<\/span> <\/span>OnQueryProductsListener<\/span> <\/span>{<\/span><\/span>\n       <\/span>fun<\/span> <\/span>onSuccess<\/span>(<\/span>products<\/span>:<\/span> <\/span>List<\/span><<\/span>SkuDetails<\/span>><\/span>)<\/span><\/span>\n       <\/span>fun<\/span> <\/span>onFailure<\/span>(<\/span>error<\/span>:<\/span> <\/span>Error<\/span>)<\/span><\/span>\n   <\/span>}<\/span><\/span>\n   <\/span>class<\/span> <\/span>Error<\/span>(<\/span>val<\/span> <\/span>responseCode<\/span>:<\/span> <\/span>Int<\/span>,<\/span> <\/span>val<\/span> <\/span>debugMessage<\/span>:<\/span> <\/span>String<\/span>)<\/span><\/span>\n   <\/span>private<\/span> <\/span>val<\/span> billingClient <\/span>=<\/span> <\/span>BillingClient<\/span><\/span>\n       <\/span>.<\/span>newBuilder<\/span>(<\/span>context<\/span>)<\/span><\/span>\n       <\/span>.<\/span>enablePendingPurchases<\/span>()<\/span><\/span>\n       <\/span>.<\/span>setListener<\/span>(<\/span>this<\/span>)<\/span><\/span>\n       <\/span>.<\/span>build<\/span>()<\/span><\/span>\n   <\/span>fun<\/span> <\/span>queryProducts<\/span>(<\/span>listener<\/span>:<\/span> <\/span>OnQueryProductsListener<\/span>)<\/span> <\/span>{<\/span><\/span>\n       <\/span>val<\/span> skusList <\/span>=<\/span> <\/span>listOf<\/span>(<\/span>"<\/span>premium_sub_month<\/span>"<\/span>,<\/span> <\/span>"<\/span>premium_sub_year<\/span>"<\/span>,<\/span> <\/span>"<\/span>some_inapp<\/span>"<\/span>)<\/span><\/span>\n       queryProductsForType<\/span>(<\/span><\/span>\n           skusList<\/span>,<\/span><\/span>\n           <\/span>BillingClient<\/span>.<\/span>SkuType<\/span>.<\/span>SUBS<\/span><\/span>\n       <\/span>)<\/span> <\/span>{<\/span> billingResult<\/span>,<\/span> skuDetailsList <\/span>-><\/span><\/span>\n           <\/span>if<\/span> <\/span>(<\/span>billingResult<\/span>.<\/span>responseCode <\/span>==<\/span> <\/span>BillingClient<\/span>.<\/span>BillingResponseCode<\/span>.<\/span>OK<\/span>)<\/span> <\/span>{<\/span><\/span>\n               <\/span>val<\/span> products <\/span>=<\/span> skuDetailsList <\/span>?:<\/span> <\/span>mutableListOf<\/span>()<\/span><\/span>\n               queryProductsForType<\/span>(<\/span><\/span>\n                   skusList<\/span>,<\/span><\/span>\n                   <\/span>BillingClient<\/span>.<\/span>SkuType<\/span>.<\/span>INAPP<\/span><\/span>\n               <\/span>)<\/span> <\/span>{<\/span> billingResult<\/span>,<\/span> skuDetailsList <\/span>-><\/span><\/span>\n                   <\/span>if<\/span> <\/span>(<\/span>billingResult<\/span>.<\/span>responseCode <\/span>==<\/span> <\/span>BillingClient<\/span>.<\/span>BillingResponseCode<\/span>.<\/span>OK<\/span>)<\/span> <\/span>{<\/span><\/span>\n                       products<\/span>.<\/span>addAll<\/span>(<\/span>skuDetailsList <\/span>?:<\/span> <\/span>listOf<\/span>())<\/span><\/span>\n                       listener<\/span>.<\/span>onSuccess<\/span>(<\/span>products<\/span>)<\/span><\/span>\n                   <\/span>}<\/span> <\/span>else<\/span> <\/span>{<\/span><\/span>\n                       listener<\/span>.<\/span>onFailure<\/span>(<\/span><\/span>\n                           <\/span>Error<\/span>(<\/span>billingResult<\/span>.<\/span>responseCode<\/span>,<\/span> billingResult<\/span>.<\/span>debugMessage<\/span>)<\/span><\/span>\n                       <\/span>)<\/span><\/span>\n                   <\/span>}<\/span><\/span>\n               <\/span>}<\/span><\/span>\n           <\/span>}<\/span> <\/span>else<\/span> <\/span>{<\/span><\/span>\n               listener<\/span>.<\/span>onFailure<\/span>(<\/span><\/span>\n                   <\/span>Error<\/span>(<\/span>billingResult<\/span>.<\/span>responseCode<\/span>,<\/span> billingResult<\/span>.<\/span>debugMessage<\/span>)<\/span><\/span>\n               <\/span>)<\/span><\/span>\n           <\/span>}<\/span><\/span>\n       <\/span>}<\/span><\/span>\n   <\/span>}<\/span><\/span>\n   <\/span>private<\/span> <\/span>fun<\/span> <\/span>queryProductsForType<\/span>(<\/span><\/span>\n       <\/span>skusList<\/span>:<\/span> <\/span>List<\/span><<\/span>String<\/span>><\/span>,<\/span><\/span>\n       <\/span>@BillingClient.SkuType<\/span> <\/span>type<\/span>:<\/span> <\/span>String<\/span>,<\/span><\/span>\n       <\/span>listener<\/span>:<\/span> <\/span>SkuDetailsResponseListener<\/span><\/span>\n   <\/span>)<\/span> <\/span>{<\/span><\/span>\n       onConnected <\/span>{<\/span><\/span>\n           billingClient<\/span>.<\/span>querySkuDetailsAsync<\/span>(<\/span><\/span>\n               <\/span>SkuDetailsParams<\/span>.<\/span>newBuilder<\/span>().<\/span>setSkusList<\/span>(<\/span>skusList<\/span>).<\/span>setType<\/span>(<\/span>type<\/span>).<\/span>build<\/span>(),<\/span><\/span>\n               listener<\/span><\/span>\n           <\/span>)<\/span><\/span>\n       <\/span>}<\/span><\/span>\n   <\/span>}<\/span><\/span>\n   <\/span>private<\/span> <\/span>fun<\/span> <\/span>onConnected<\/span>(<\/span>block<\/span>:<\/span> <\/span>()<\/span> <\/span>-><\/span> <\/span>Unit<\/span>)<\/span> <\/span>{<\/span><\/span>\n       billingClient<\/span>.<\/span>startConnection<\/span>(<\/span>object<\/span> <\/span>:<\/span> <\/span>BillingClientStateListener<\/span> {<\/span><\/span>\n           override fun onBillingSetupFinished<\/span>(<\/span>billingResult<\/span>:<\/span> <\/span>BillingResult<\/span>)<\/span> {<\/span><\/span>\n               block<\/span>()<\/span><\/span>\n           }<\/span><\/span>\n           override fun onBillingServiceDisconnected<\/span>()<\/span> {<\/span><\/span>\n               <\/span>\/\/<\/span> <\/span>Try<\/span> to restart the connection on the next request to<\/span><\/span>\n               <\/span>\/\/<\/span> <\/span>Google<\/span> <\/span>Play<\/span> by calling the startConnection<\/span>()<\/span> method<\/span>.<\/span><\/span>\n           }<\/span><\/span>\n       }<\/span>)<\/span><\/span>\n   <\/span>}<\/span><\/span>\n   <\/span>override<\/span> <\/span>fun<\/span> <\/span>onPurchasesUpdated<\/span>(<\/span>billingResult<\/span>:<\/span> <\/span>BillingResult<\/span>,<\/span> <\/span>purchaseList<\/span>:<\/span> <\/span>MutableList<\/span><<\/span>Purchase<\/span>><\/span>?<\/span>)<\/span> <\/span>{<\/span><\/span>\n       <\/span>\/\/ here come callbacks about new purchases<\/span><\/span>\n   <\/span>}<\/span><\/span>\n}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n

Przejd\u017amy do realizacji zakupu i udoskonalmy nasz\u0105 klas\u0119.<\/p>\n\n\n\n\n\n

Projektowanie ekranu subskrypcji<\/h2>\n\n\n\n

Ka\u017cda aplikacja, kt\u00f3ra oferuje zakupy w aplikacji, posiada ekran paywall. Istniej\u0105 pewne Polityki Google<\/a>, kt\u00f3re definiuj\u0105 minimum element\u00f3w i tekst\u00f3w instrukta\u017cowych, kt\u00f3re musz\u0105 by\u0107 obecne na takich ekranach. Oto ich podsumowanie. Na ekranie paywall musisz jasno okre\u015bli\u0107 warunki, koszt i czas trwania subskrypcji, a tak\u017ce okre\u015bli\u0107, czy subskrypcja jest konieczna, aby mo\u017cliwe by\u0142o korzystanie z aplikacji. Nale\u017cy r\u00f3wnie\u017c unika\u0107 zmuszania u\u017cytkownik\u00f3w do wykonywania jakichkolwiek dodatkowych dzia\u0142a\u0144 w celu sprawdzenia warunk\u00f3w. <\/p>\n\n\n\n

Jako przyk\u0142ad pos\u0142u\u017cymy si\u0119 uproszczonym ekranem paywall:<\/p>\n\n\n

\n
\"\"
Przyk\u0142adowy paywall dla Androida<\/em><\/figcaption><\/figure><\/div>\n\n\n

Na ekranie paywall obecne s\u0105 nast\u0119puj\u0105ce elementy:<\/p>\n\n\n\n