sjbillingclient 0.1.3__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sjbillingclient-0.2.0/PKG-INFO +507 -0
- sjbillingclient-0.2.0/README.md +490 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/pyproject.toml +2 -1
- sjbillingclient-0.2.0/sjbillingclient/jclass/purchase.py +16 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jclass/queryproduct.py +9 -1
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/product.py +4 -3
- sjbillingclient-0.2.0/sjbillingclient/tools/__init__.py +447 -0
- sjbillingclient-0.1.3/PKG-INFO +0 -29
- sjbillingclient-0.1.3/README.md +0 -13
- sjbillingclient-0.1.3/sjbillingclient/jclass/purchase.py +0 -8
- sjbillingclient-0.1.3/sjbillingclient/tools/__init__.py +0 -144
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/__init__.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jclass/__init__.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jclass/acknowledge.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jclass/billing.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jclass/consume.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/__init__.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/acknowledge.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/billing.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/consume.py +0 -0
- {sjbillingclient-0.1.3 → sjbillingclient-0.2.0}/sjbillingclient/jinterface/purchases.py +0 -0
@@ -0,0 +1,507 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: sjbillingclient
|
3
|
+
Version: 0.2.0
|
4
|
+
Summary:
|
5
|
+
Author: Kenechukwu Akubue
|
6
|
+
Author-email: kengoon19@gmail.com
|
7
|
+
Requires-Python: >=3.9,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
13
|
+
Requires-Dist: poetry-core (>=2.1.3,<3.0.0)
|
14
|
+
Requires-Dist: pyjnius (>=1.6.1,<2.0.0)
|
15
|
+
Description-Content-Type: text/markdown
|
16
|
+
|
17
|
+
# SJBillingClient (Google Play Billing SDK for Python)
|
18
|
+
|
19
|
+
<!-- GitAds-Verify: 71CCWMQSMVD67LS4WF4N44EXISSL2UTQ -->
|
20
|
+
## GitAds Sponsored
|
21
|
+
[](https://gitads.dev/v1/ad-track?source=simplejnius/sj-android-billingclient@github)
|
22
|
+
|
23
|
+
## Overview
|
24
|
+
|
25
|
+
SJBillingClient is a Python wrapper for the Google Play Billing Library that facilitates in-app purchases and subscriptions in Android applications. It provides a high-level, Pythonic interface to interact with Google Play's billing system, making it easier to implement and manage in-app purchases in Python-based Android apps (like those built with Kivy/Python-for-Android).
|
26
|
+
|
27
|
+
### Key Features
|
28
|
+
|
29
|
+
- **Simplified Billing Integration**: Easy-to-use Python API for Google Play Billing
|
30
|
+
- **Asynchronous Operations**: Non-blocking billing operations
|
31
|
+
- **Comprehensive Purchase Management**: Support for querying, purchasing, consuming, and acknowledging products
|
32
|
+
- **Product Types Support**: Handles both one-time purchases (INAPP) and subscriptions (SUBS)
|
33
|
+
- **Detailed Product Information**: Access to formatted prices, currency codes, and other product details
|
34
|
+
|
35
|
+
## Requirements
|
36
|
+
|
37
|
+
- Python 3.9+
|
38
|
+
- pyjnius 1.6.1+
|
39
|
+
- Android application with Google Play Billing Library (version 8.0.0 recommended)
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
```shell
|
44
|
+
# Using pip
|
45
|
+
pip install sjbillingclient
|
46
|
+
|
47
|
+
# In Buildozer (add to buildozer.spec)
|
48
|
+
requirements = sjbillingclient
|
49
|
+
android.gradle_dependencies = com.android.billingclient:billing:8.0.0
|
50
|
+
```
|
51
|
+
|
52
|
+
## Quick Start
|
53
|
+
|
54
|
+
Here's a basic example of how to initialize the billing client and start a connection:
|
55
|
+
|
56
|
+
```python
|
57
|
+
from sjbillingclient.tools import BillingClient
|
58
|
+
from sjbillingclient.jclass.billing import ProductType, BillingResponseCode
|
59
|
+
|
60
|
+
# Define callback for purchase updates
|
61
|
+
def on_purchases_updated(billing_result, is_null, purchases):
|
62
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
63
|
+
if not is_null:
|
64
|
+
for purchase in purchases:
|
65
|
+
print(f"Purchase: {purchase.getProducts().get(0)}")
|
66
|
+
# Handle purchase here
|
67
|
+
|
68
|
+
# Create billing client
|
69
|
+
client = BillingClient(on_purchases_updated)
|
70
|
+
|
71
|
+
# Start connection
|
72
|
+
client.start_connection(
|
73
|
+
on_billing_setup_finished=lambda result: print(f"Billing setup complete: {result.getResponseCode()}"),
|
74
|
+
on_billing_service_disconnected=lambda: print("Billing service disconnected")
|
75
|
+
)
|
76
|
+
```
|
77
|
+
|
78
|
+
## Usage Examples
|
79
|
+
|
80
|
+
### Querying Product Details
|
81
|
+
|
82
|
+
```python
|
83
|
+
from sjbillingclient.tools import BillingClient
|
84
|
+
from sjbillingclient.jclass.billing import ProductType, BillingResponseCode
|
85
|
+
|
86
|
+
def on_product_details_response(billing_result, product_details_list):
|
87
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
88
|
+
if product_details_list and not product_details_list.isEmpty():
|
89
|
+
# Process product details
|
90
|
+
for i in range(product_details_list.size()):
|
91
|
+
product_detail = product_details_list.get(i)
|
92
|
+
print(f"Product: {product_detail.getProductId()}")
|
93
|
+
|
94
|
+
# Get formatted details
|
95
|
+
details = client.get_product_details(product_detail, ProductType.INAPP)
|
96
|
+
for detail in details:
|
97
|
+
print(f"Price: {detail['formatted_price']}")
|
98
|
+
|
99
|
+
# Query product details
|
100
|
+
client.query_product_details_async(
|
101
|
+
product_type=ProductType.INAPP,
|
102
|
+
products_ids=["product_id_1", "product_id_2"],
|
103
|
+
on_product_details_response=on_product_details_response
|
104
|
+
)
|
105
|
+
```
|
106
|
+
|
107
|
+
### Launching a Purchase Flow
|
108
|
+
|
109
|
+
```python
|
110
|
+
from sjbillingclient.tools import BillingClient
|
111
|
+
from sjbillingclient.jclass.billing import ProductType, BillingResponseCode
|
112
|
+
|
113
|
+
def on_product_details_response(billing_result, product_details_list):
|
114
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
115
|
+
if product_details_list and not product_details_list.isEmpty():
|
116
|
+
# Launch billing flow with the first product
|
117
|
+
product_detail = product_details_list.get(0)
|
118
|
+
result = client.launch_billing_flow([product_detail])
|
119
|
+
print(f"Launch billing flow result: {result.getResponseCode()}")
|
120
|
+
|
121
|
+
# Query product details and then launch purchase
|
122
|
+
client.query_product_details_async(
|
123
|
+
product_type=ProductType.INAPP,
|
124
|
+
products_ids=["product_id"],
|
125
|
+
on_product_details_response=on_product_details_response
|
126
|
+
)
|
127
|
+
```
|
128
|
+
|
129
|
+
### Consuming a Purchase
|
130
|
+
|
131
|
+
```python
|
132
|
+
from sjbillingclient.tools import BillingClient
|
133
|
+
from sjbillingclient.jclass.billing import BillingResponseCode
|
134
|
+
|
135
|
+
def on_consume_response(billing_result, purchase_token):
|
136
|
+
print(f"Consume result: {billing_result.getResponseCode()}")
|
137
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
138
|
+
print(f"Successfully consumed: {purchase_token}")
|
139
|
+
|
140
|
+
# Consume a purchase
|
141
|
+
client.consume_async(purchase, on_consume_response)
|
142
|
+
```
|
143
|
+
|
144
|
+
### Acknowledging a Purchase
|
145
|
+
|
146
|
+
```python
|
147
|
+
from sjbillingclient.tools import BillingClient
|
148
|
+
from sjbillingclient.jclass.billing import BillingResponseCode
|
149
|
+
|
150
|
+
def on_acknowledge_purchase_response(billing_result):
|
151
|
+
print(f"Acknowledge result: {billing_result.getResponseCode()}")
|
152
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
153
|
+
print("Successfully acknowledged purchase")
|
154
|
+
|
155
|
+
# Acknowledge a purchase
|
156
|
+
client.acknowledge_purchase(purchase.getPurchaseToken(), on_acknowledge_purchase_response)
|
157
|
+
```
|
158
|
+
|
159
|
+
### Kivy Integration Example
|
160
|
+
|
161
|
+
Here's a complete example of integrating SJBillingClient with a Kivy application:
|
162
|
+
|
163
|
+
#### Python Code (main.py)
|
164
|
+
|
165
|
+
```python
|
166
|
+
from os.path import join, dirname, basename
|
167
|
+
from kivy.app import App
|
168
|
+
from kivy.lang import Builder
|
169
|
+
from kivy.uix.screenmanager import ScreenManager, Screen
|
170
|
+
from sjbillingclient.jclass.billing import BillingResponseCode, ProductType
|
171
|
+
from sjbillingclient.tools import BillingClient
|
172
|
+
|
173
|
+
Builder.load_file(join(dirname(__file__), basename(__file__).split(".")[0] + ".kv"))
|
174
|
+
|
175
|
+
|
176
|
+
class HomeScreen(Screen):
|
177
|
+
"""
|
178
|
+
A screen that demonstrates Google Play Billing integration with Kivy.
|
179
|
+
|
180
|
+
This screen provides functionality to make in-app purchases and subscriptions
|
181
|
+
using the Google Play Billing Library through the SJBillingClient wrapper.
|
182
|
+
|
183
|
+
Attributes:
|
184
|
+
billing_client (BillingClient): The client used to interact with Google Play Billing.
|
185
|
+
"""
|
186
|
+
billing_client = None
|
187
|
+
|
188
|
+
def support(self):
|
189
|
+
"""
|
190
|
+
Initializes the billing client and starts a connection to the Google Play Billing service.
|
191
|
+
|
192
|
+
This method is called when the user wants to make a purchase or subscription.
|
193
|
+
If a billing client already exists, it ends the connection before creating a new one.
|
194
|
+
"""
|
195
|
+
if self.billing_client:
|
196
|
+
self.billing_client.end_connection()
|
197
|
+
|
198
|
+
self.billing_client = BillingClient(on_purchases_updated=self.on_purchases_updated)
|
199
|
+
self.billing_client.start_connection(
|
200
|
+
on_billing_setup_finished=self.on_billing_setup_finished,
|
201
|
+
on_billing_service_disconnected=lambda: print("disconnected")
|
202
|
+
)
|
203
|
+
|
204
|
+
def on_purchases_updated(self, billing_result, null, purchases):
|
205
|
+
"""
|
206
|
+
Callback method that is called when purchases are updated.
|
207
|
+
|
208
|
+
This method handles the result of a purchase flow, either acknowledging
|
209
|
+
a subscription or consuming a one-time purchase.
|
210
|
+
|
211
|
+
Args:
|
212
|
+
billing_result: The result of the billing operation.
|
213
|
+
null: Boolean indicating if the purchases list is null.
|
214
|
+
purchases: List of purchases that were updated.
|
215
|
+
"""
|
216
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK and not null:
|
217
|
+
for purchase in purchases:
|
218
|
+
if self.ids.subscribe.active:
|
219
|
+
self.billing_client.acknowledge_purchase(
|
220
|
+
purchase_token=purchase.getPurchaseToken(),
|
221
|
+
on_acknowledge_purchase_response=self.on_acknowledge_purchase_response
|
222
|
+
)
|
223
|
+
else:
|
224
|
+
self.billing_client.consume_async(purchase, self.on_consume_response)
|
225
|
+
print(billing_result.getResponseCode(), billing_result.getDebugMessage())
|
226
|
+
|
227
|
+
def on_acknowledge_purchase_response(self, billing_result):
|
228
|
+
"""
|
229
|
+
Callback method that is called when a purchase acknowledgement is complete.
|
230
|
+
|
231
|
+
Args:
|
232
|
+
billing_result: The result of the acknowledgement operation.
|
233
|
+
"""
|
234
|
+
print(billing_result.getDebugMessage())
|
235
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
236
|
+
self.toast("Thank you for subscribing to buy us a cup of coffee! monthly")
|
237
|
+
|
238
|
+
def on_consume_response(self, billing_result):
|
239
|
+
"""
|
240
|
+
Callback method that is called when a purchase consumption is complete.
|
241
|
+
|
242
|
+
Args:
|
243
|
+
billing_result: The result of the consumption operation.
|
244
|
+
"""
|
245
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
246
|
+
self.toast("Thank you for buying us a cup of coffee!")
|
247
|
+
|
248
|
+
def on_product_details_response(self, billing_result, product_details_result):
|
249
|
+
"""
|
250
|
+
Callback method that is called when product details are retrieved.
|
251
|
+
|
252
|
+
This method processes the product details and launches the billing flow.
|
253
|
+
|
254
|
+
Args:
|
255
|
+
billing_result: The result of the product details query.
|
256
|
+
product_details_result: The result containing product details and unfetched products.
|
257
|
+
"""
|
258
|
+
product_details_list = product_details_result.getProductDetailsList()
|
259
|
+
unfetched_product_list = product_details_result.getUnfetchedProductList()
|
260
|
+
|
261
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
262
|
+
for product_details in product_details_list:
|
263
|
+
self.billing_client.get_product_details(
|
264
|
+
product_details,
|
265
|
+
ProductType.SUBS if self.ids.subscribe.active else ProductType.INAPP)
|
266
|
+
for unfetched_product in unfetched_product_list:
|
267
|
+
print(self.billing_client.get_unfetched_product(unfetched_product))
|
268
|
+
self.billing_client.launch_billing_flow(product_details=product_details_list)
|
269
|
+
|
270
|
+
def on_billing_setup_finished(self, billing_result):
|
271
|
+
"""
|
272
|
+
Callback method that is called when the billing setup is complete.
|
273
|
+
|
274
|
+
This method queries product details if the billing setup was successful.
|
275
|
+
|
276
|
+
Args:
|
277
|
+
billing_result: The result of the billing setup operation.
|
278
|
+
"""
|
279
|
+
product_id = self.ids.btn.product_id
|
280
|
+
if billing_result.getResponseCode() == BillingResponseCode.OK:
|
281
|
+
self.billing_client.query_product_details_async(
|
282
|
+
product_type=ProductType.SUBS if self.ids.subscribe else ProductType.INAPP,
|
283
|
+
products_ids=[product_id],
|
284
|
+
on_product_details_response=self.on_product_details_response,
|
285
|
+
)
|
286
|
+
|
287
|
+
def toast(self, message):
|
288
|
+
"""
|
289
|
+
Display a toast message.
|
290
|
+
|
291
|
+
This is a simple implementation that just prints the message.
|
292
|
+
In a real app, you would use platform-specific toast functionality.
|
293
|
+
|
294
|
+
Args:
|
295
|
+
message: The message to display.
|
296
|
+
"""
|
297
|
+
# Implementation of toast message (platform specific)
|
298
|
+
print(message)
|
299
|
+
|
300
|
+
|
301
|
+
class BillingApp(App):
|
302
|
+
"""
|
303
|
+
Main application class for the SJBillingClient demo.
|
304
|
+
|
305
|
+
This class sets up the application and creates the screen manager
|
306
|
+
with the HomeScreen.
|
307
|
+
"""
|
308
|
+
def build(self):
|
309
|
+
"""
|
310
|
+
Build the application UI.
|
311
|
+
|
312
|
+
Returns:
|
313
|
+
ScreenManager: The root widget of the application.
|
314
|
+
"""
|
315
|
+
# Create screen manager
|
316
|
+
sm = ScreenManager()
|
317
|
+
sm.add_widget(HomeScreen(name='home'))
|
318
|
+
return sm
|
319
|
+
|
320
|
+
|
321
|
+
if __name__ == '__main__':
|
322
|
+
BillingApp().run()
|
323
|
+
```
|
324
|
+
|
325
|
+
#### Kivy Layout File (main.kv)
|
326
|
+
|
327
|
+
```kivy
|
328
|
+
<HomeScreen>:
|
329
|
+
BoxLayout:
|
330
|
+
orientation: 'vertical'
|
331
|
+
padding: '20dp'
|
332
|
+
spacing: '10dp'
|
333
|
+
|
334
|
+
Label:
|
335
|
+
text: 'SJBillingClient Demo'
|
336
|
+
font_size: '24sp'
|
337
|
+
size_hint_y: None
|
338
|
+
height: '50dp'
|
339
|
+
|
340
|
+
BoxLayout:
|
341
|
+
orientation: 'horizontal'
|
342
|
+
size_hint_y: None
|
343
|
+
height: '50dp'
|
344
|
+
|
345
|
+
Label:
|
346
|
+
text: 'Subscribe'
|
347
|
+
size_hint_x: 0.5
|
348
|
+
|
349
|
+
CheckBox:
|
350
|
+
id: subscribe
|
351
|
+
size_hint_x: 0.5
|
352
|
+
active: False
|
353
|
+
|
354
|
+
Button:
|
355
|
+
id: btn
|
356
|
+
text: 'Buy Coffee'
|
357
|
+
product_id: 'coffee_product_id'
|
358
|
+
size_hint_y: None
|
359
|
+
height: '60dp'
|
360
|
+
on_release: root.support()
|
361
|
+
|
362
|
+
Widget:
|
363
|
+
# Spacer
|
364
|
+
```
|
365
|
+
|
366
|
+
This example demonstrates:
|
367
|
+
|
368
|
+
1. A `HomeScreen` class that extends `Screen` and handles all billing operations
|
369
|
+
2. A `BillingApp` class that sets up the Kivy application and screen manager
|
370
|
+
3. A Kivy layout file that defines the UI with:
|
371
|
+
- A checkbox to toggle between one-time purchase and subscription
|
372
|
+
- A button to initiate the purchase flow
|
373
|
+
|
374
|
+
The `support` method is called when the button is pressed, which initializes the billing client and starts the connection. The various callback methods handle different stages of the billing process, including:
|
375
|
+
- Handling purchase updates with `on_purchases_updated`
|
376
|
+
- Acknowledging subscription purchases with `acknowledge_purchase`
|
377
|
+
- Consuming one-time purchases with `consume_async`
|
378
|
+
- Processing product details with `on_product_details_response`, including handling unfetched products
|
379
|
+
- Querying product details with `query_product_details_async`
|
380
|
+
|
381
|
+
This example is designed to be copy-and-paste runnable, with no need for the user to add or remove anything to test it.
|
382
|
+
|
383
|
+
## API Reference
|
384
|
+
|
385
|
+
### BillingClient
|
386
|
+
|
387
|
+
The main class for interacting with Google Play Billing.
|
388
|
+
|
389
|
+
#### Constructor
|
390
|
+
|
391
|
+
- `__init__(on_purchases_updated, enable_one_time_products=True, enable_prepaid_plans=False)`:
|
392
|
+
- Initializes a new BillingClient instance
|
393
|
+
- `on_purchases_updated`: Callback function that will be triggered when purchases are updated
|
394
|
+
- `enable_one_time_products`: Boolean to enable one-time products (default: True)
|
395
|
+
- `enable_prepaid_plans`: Boolean to enable prepaid plans (default: False)
|
396
|
+
|
397
|
+
#### Connection Methods
|
398
|
+
|
399
|
+
- `start_connection(on_billing_setup_finished, on_billing_service_disconnected)`:
|
400
|
+
- Starts a connection with the billing client
|
401
|
+
- `on_billing_setup_finished`: Callback when billing setup is complete
|
402
|
+
- `on_billing_service_disconnected`: Callback when billing service is disconnected
|
403
|
+
|
404
|
+
- `end_connection()`:
|
405
|
+
- Ends the connection with the billing client
|
406
|
+
|
407
|
+
#### Product Details Methods
|
408
|
+
|
409
|
+
- `query_product_details_async(product_type, products_ids, on_product_details_response)`:
|
410
|
+
- Queries product details asynchronously
|
411
|
+
- `product_type`: Type of products (INAPP or SUBS)
|
412
|
+
- `products_ids`: List of product IDs to query
|
413
|
+
- `on_product_details_response`: Callback for product details response
|
414
|
+
|
415
|
+
- `get_product_details(product_details, product_type)`:
|
416
|
+
- Gets formatted product details
|
417
|
+
- `product_details`: Product details object
|
418
|
+
- `product_type`: Type of product (INAPP or SUBS)
|
419
|
+
- Returns a list of dictionaries with product details
|
420
|
+
|
421
|
+
- `get_unfetched_product(unfetched_product)`:
|
422
|
+
- Gets details about an unfetched product
|
423
|
+
- `unfetched_product`: Unfetched product object
|
424
|
+
- Returns a dictionary with product ID, type, and status code
|
425
|
+
|
426
|
+
#### Purchase Methods
|
427
|
+
|
428
|
+
- `launch_billing_flow(product_details, offer_token=None)`:
|
429
|
+
- Launches the billing flow for purchase
|
430
|
+
- `product_details`: List of product details objects
|
431
|
+
- `offer_token`: Optional token for subscription offers
|
432
|
+
|
433
|
+
- `consume_async(purchase, on_consume_response)`:
|
434
|
+
- Consumes a purchase asynchronously
|
435
|
+
- `purchase`: Purchase object to consume
|
436
|
+
- `on_consume_response`: Callback for consume response
|
437
|
+
|
438
|
+
- `acknowledge_purchase(purchase_token, on_acknowledge_purchase_response)`:
|
439
|
+
- Acknowledges a purchase
|
440
|
+
- `purchase_token`: Token of the purchase to acknowledge
|
441
|
+
- `on_acknowledge_purchase_response`: Callback for acknowledge response
|
442
|
+
|
443
|
+
### PendingPurchasesParams
|
444
|
+
|
445
|
+
Parameters for handling pending purchases.
|
446
|
+
|
447
|
+
#### Methods
|
448
|
+
|
449
|
+
- `newBuilder()`: Creates a new builder for PendingPurchasesParams
|
450
|
+
- `build()`: Builds the PendingPurchasesParams object
|
451
|
+
- `enableOneTimeProducts()`: Enables one-time products
|
452
|
+
- `enablePrepaidPlans()`: Enables prepaid plans
|
453
|
+
|
454
|
+
### QueryProductDetailsParams
|
455
|
+
|
456
|
+
Parameters for querying product details.
|
457
|
+
|
458
|
+
#### Methods
|
459
|
+
|
460
|
+
- `newBuilder()`: Creates a new builder for QueryProductDetailsParams
|
461
|
+
- `setProductList(product_list)`: Sets the list of products to query
|
462
|
+
- `build()`: Builds the QueryProductDetailsParams object
|
463
|
+
|
464
|
+
### QueryProductDetailsResult
|
465
|
+
|
466
|
+
Result of a product details query.
|
467
|
+
|
468
|
+
#### Methods
|
469
|
+
|
470
|
+
- `getProductDetailsList()`: Gets the list of product details
|
471
|
+
- `getUnfetchedProductList()`: Gets the list of unfetched products
|
472
|
+
|
473
|
+
### ProductType
|
474
|
+
|
475
|
+
Constants for product types:
|
476
|
+
|
477
|
+
- `ProductType.INAPP`: One-time purchases
|
478
|
+
- `ProductType.SUBS`: Subscriptions
|
479
|
+
|
480
|
+
### BillingResponseCode
|
481
|
+
|
482
|
+
Constants for billing response codes:
|
483
|
+
|
484
|
+
- `BillingResponseCode.OK`: Success (0)
|
485
|
+
- `BillingResponseCode.USER_CANCELED`: User canceled (1)
|
486
|
+
- `BillingResponseCode.SERVICE_UNAVAILABLE`: Service unavailable (2)
|
487
|
+
- `BillingResponseCode.BILLING_UNAVAILABLE`: Billing unavailable (3)
|
488
|
+
- `BillingResponseCode.ITEM_UNAVAILABLE`: Item unavailable (4)
|
489
|
+
- `BillingResponseCode.DEVELOPER_ERROR`: Developer error (5)
|
490
|
+
- `BillingResponseCode.ERROR`: General error (6)
|
491
|
+
- `BillingResponseCode.ITEM_ALREADY_OWNED`: Item already owned (7)
|
492
|
+
- `BillingResponseCode.ITEM_NOT_OWNED`: Item not owned (8)
|
493
|
+
- `BillingResponseCode.SERVICE_DISCONNECTED`: Service disconnected (10)
|
494
|
+
- `BillingResponseCode.FEATURE_NOT_SUPPORTED`: Feature not supported (12)
|
495
|
+
|
496
|
+
## Contributing
|
497
|
+
|
498
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
499
|
+
|
500
|
+
## License
|
501
|
+
|
502
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
503
|
+
|
504
|
+
## Author
|
505
|
+
|
506
|
+
Kenechukwu Akubue <kengoon19@gmail.com>
|
507
|
+
|