cafebazaar_billing 1.2.0
cafebazaar_billing: ^1.2.0 copied to clipboard
cafebazaar_billing is a Flutter plugin that acts as a gate to Cafe Bazaar's native Android In-App Billing, so Flutter apps can sell products and subscriptions on the Cafe Bazaar store.
cafebazaar_billing #
cafebazaar_billing is a Flutter plugin that acts as a gate to Cafe Bazaar's native Android In-App Billing. It lets your Flutter app sell products and subscriptions on the Cafe Bazaar store by bridging your Dart code to the Android-native billing implementation.
This package is an independent project — it is not Poolakey and not a wrapper around any other Flutter package.
Android only — Cafe Bazaar is an Android app store.
Table of Contents #
- Features
- Requirements
- Installation
- Quick Start
- Full API Reference
- Data Models
- Error Handling
- Example App
- Troubleshooting & FAQ
- Changelog
- License
Features #
| Feature | Method |
|---|---|
| Connect / disconnect to Bazaar billing service | connect / disconnect |
| Buy consumable / non-consumable products | purchase |
| Buy subscriptions | subscribe |
| Apply developer dynamic pricing | dynamicPriceToken parameter |
| Attach server-verifiable metadata to orders | payload parameter |
| Consume products so they can be re-purchased | consume |
| List user's purchased products | getAllPurchasedProducts |
| Find a purchased product by id | queryPurchasedProduct |
| List user's subscriptions | getAllSubscribedProducts |
| Find a subscription by id | querySubscribedProduct |
| In-app product details (title, price, …) | getInAppSkuDetails |
| Subscription product details | getSubscriptionSkuDetails |
| Trial-subscription availability | checkTrialSubscription |
Requirements #
- Flutter
>= 3.3.0, Dart>= 3.0.6 - Android
minSdk 21 - The Cafe Bazaar app installed on the device
- An RSA public key from your Pishkhan panel (optional — omit only if you verify purchases server-side through Bazaar's REST API)
- Products configured in your Pishkhan panel with matching SKUs
Familiarize yourself with the official flow in the Cafe Bazaar developer documentation.
Installation #
From pub.dev (recommended):
flutter pub add cafebazaar_billing
or add it manually to pubspec.yaml:
dependencies:
cafebazaar_billing: ^1.2.0
Alternative: install from GitHub or a local path
From GitHub:
dependencies:
cafebazaar_billing:
git:
url: https://github.com/mavan-innovative-studio/cafebazaar-billing-package.git
ref: main
Or as a local path:
dependencies:
cafebazaar_billing:
path: ../cafebazaar_billing
Then:
flutter pub get
No extra manifest or Gradle setup is needed — the plugin declares everything required (including the <queries> entry for com.farsitel.bazaar) via its own manifest.
Quick Start #
import 'package:cafebazaar_billing/cafebazaar_billing.dart';
Future<void> buyGems() async {
// 1. Connect (do this once, e.g. after login).
await CafeBazaarBilling.connect(
'YOUR_RSA_PUBLIC_KEY', // null => skips local signature validation
onSucceed: () => print('Connected'),
onFailed: () => print('Connection failed'),
onDisconnected: () {
print('Disconnected — reconnect before buying again');
},
);
// 2. Start a purchase. The Bazaar payment screen opens.
final PurchaseInfo info = await CafeBazaarBilling.purchase(
'gem_pack_100',
payload: 'user:42', // optional, stored with the order
);
print('Purchased: ${info.productId}, token: ${info.purchaseToken}');
// 3. For consumables, consume so the user can buy again.
await CafeBazaarBilling.consume(info.purchaseToken);
// 4. Disconnect when you no longer need billing (e.g. in dispose()).
await CafeBazaarBilling.disconnect();
}
Always wrap billing calls in try/catch; every failure surfaces as a
PlatformException.
Full API Reference #
Import:
import 'package:cafebazaar_billing/cafebazaar_billing.dart';
Connection #
connect()
static Future<void> connect(
String? inAppBillingKey, {
VoidCallback? onSucceed,
VoidCallback? onFailed,
VoidCallback? onDisconnected,
})
Opens the connection to the Bazaar billing service. Call this before any other method.
| Parameter | Description |
|---|---|
inAppBillingKey |
Your RSA public key from Pishkhan. Pass null to disable local signature checks (only safe if you validate purchases via Bazaar's REST API). |
onSucceed |
Connection established — billing methods are now usable. |
onFailed |
Connection attempt failed. |
onDisconnected |
The service dropped (Bazaar killed/uninstalled…). Reconnect before further calls. |
disconnect()
static Future<void> disconnect()
Closes the connection. Call it when leaving a page that does billing (e.g. in dispose()) to avoid leaks.
Purchases & Subscriptions #
purchase()
static Future<PurchaseInfo> purchase(
String productId, {
String payload = '',
String dynamicPriceToken = '',
})
Launches the Bazaar purchase flow for productId. Resolves with the resulting PurchaseInfo; throws a PlatformException if cancelled or failed.
| Parameter | Description |
|---|---|
productId |
The SKU of the product, exactly as configured in Pishkhan. |
payload |
Optional free-form data (e.g. user:42). Stored with the order; read it back from PurchaseInfo.payload or your backend for verification. |
dynamicPriceToken |
Optional token to apply a developer-defined discount/price change for a specific user. See official docs. |
subscribe()
static Future<PurchaseInfo> subscribe(
String productId, {
String payload = '',
String dynamicPriceToken = '',
})
Same contract as purchase(), but for subscription SKUs.
consume()
static Future<bool> consume(String purchaseToken)
Consumes a product using PurchaseInfo.purchaseToken, allowing it to be bought again.
Only call this for consumable items (gems, coins…). Never consume permanent unlocks or subscriptions.
Inventory Queries #
static Future<List<PurchaseInfo>> getAllPurchasedProducts()
static Future<PurchaseInfo?> queryPurchasedProduct(String productId)
static Future<List<PurchaseInfo>> getAllSubscribedProducts()
static Future<PurchaseInfo?> querySubscribedProduct(String productId)
getAll*return the user's full inventory of purchases/subscriptions.query*are convenience lookups returningnullwhen the user does not own the product.
Typical use — restore purchases at app start:
final owned = await CafeBazaarBilling.queryPurchasedProduct('remove_ads');
if (owned != null && owned.purchaseState == PurchaseState.PURCHASED) {
unlockProFeatures();
}
Product Details (SKU) #
static Future<List<SkuDetails>> getInAppSkuDetails(List<String> skuIds)
static Future<List<SkuDetails>> getSubscriptionSkuDetails(List<String> skuIds)
Returns localized titles/prices/descriptions for rendering your own store UI:
final details = await CafeBazaarBilling.getInAppSkuDetails(['gem_pack_100']);
print(details.first.price); // "۱۰۰٬۰۰۰ ریال"
Trial Subscription #
static Future<Map> checkTrialSubscription()
Checks whether the user is still eligible for a free trial:
final trial = await CafeBazaarBilling.checkTrialSubscription();
print(trial['isAvailable']); // bool
print(trial['trialPeriodDays']); // int
Version #
static Future<String> getVersion()
Returns the underlying native billing library version — useful for support tickets and debugging.
Data Models #
PurchaseInfo #
Returned by every purchase/query method.
| Field | Type | Description |
|---|---|---|
orderId |
String |
Unique order id assigned by Bazaar. |
purchaseToken |
String |
Token identifying the purchase — pass to consume() or your backend verification. |
payload |
String |
The payload you attached when purchasing. |
packageName |
String |
Your application id. |
purchaseState |
PurchaseState |
PURCHASED or REFUNDED. |
purchaseTime |
int |
Purchase timestamp (epoch millis). |
productId |
String |
The SKU that was bought. |
originalJson |
String |
Raw JSON from the store — useful for server-side verification. |
dataSignature |
String |
RSA signature of originalJson (empty when local security check is disabled). |
SkuDetails #
Returned by SKU-detail queries.
| Field | Type | Description |
|---|---|---|
sku |
String |
Product id. |
type |
String |
Product type (inapp or subscription). |
price |
String |
Localized price string, ready to display. |
title |
String |
Localized product title. |
description |
String |
Localized description. |
PurchaseState #
enum PurchaseState { PURCHASED, REFUNDED }
Error Handling #
All errors are thrown as PlatformException — branch on e.code:
| Code | Meaning | Suggested action |
|---|---|---|
PAYMENT_CONNECTION_IS_NOT_CONNECTED |
Billing service not connected yet (or dropped). | Call connect() and retry once connected. |
PURCHASE_FAILED |
Generic failure while starting/finishing a purchase. | Log & show a retry dialog. |
PURCHASE_CANCELLED |
User backed out of the Bazaar screen. | Silent or gentle toast — not an error state. |
FAILED_TO_BEGIN_FLOW |
Bazaar could not launch the payment flow. | Check that Bazaar is installed & updated. |
CONSUME_FAILED |
Consumption rejected (already consumed / not owned). | Refresh inventory before retrying. |
QUERY_PURCHASED_PRODUCT_FAILED / QUERY_SUBSCRIBED_PRODUCT_FAILED |
Inventory query failed. | Retry after reconnecting. |
QUERY_GET_IN_APP_SKU_DETAILS_FAILED / QUERY_GET_SUBSCRIPTION_SKU_DETAILS_FAILED |
SKU lookup failed. | Verify the SKUs exist in Pishkhan. |
CHECK_TRIAL_FAILED |
Trial eligibility check failed. | Treat as "no trial info". |
try {
await CafeBazaarBilling.consume(token);
} on PlatformException catch (e) {
switch (e.code) {
case 'PURCHASE_CANCELLED':
break; // user changed their mind
case 'PAYMENT_CONNECTION_IS_NOT_CONNECTED':
await reconnect();
default:
showError(e.message);
}
}
Example App #
A complete, ready-to-run demo lives in example/ featuring:
- Live connection status indicator
- Configurable RSA key + connect/disconnect controls
- Sample product catalog with buy & subscribe actions
- Real-time inventory view with one-tap consume
- Trial-subscription check and version display
- An activity log console showing every event and error code
cd example
flutter pub get
flutter run
A device (or emulator) with the Cafe Bazaar app installed is required for real flows.
Troubleshooting & FAQ #
PAYMENT_CONNECTION_IS_NOT_CONNECTED right after calling purchase
Wait for onSucceed before enabling buy buttons; reconnect on onDisconnected.
Connection fails immediately Cafe Bazaar must be installed and signed-in on the device. Emulators without Play services need the Bazaar APK sideloaded.
Signature verification fails (dataSignature issues)
Make sure the RSA key passed to connect() matches the key of the upload certificate used to sign the app, and that you didn't intend to pass null.
Purchases disappear after reinstall
They don't — restore them with getAllPurchasedProducts() / getAllSubscribedProducts() at startup.
Does it work on iOS / web / desktop?
No. Cafe Bazaar billing is Android-only; calls on other platforms throw MissingPluginException.
Can I verify purchases on my server?
Yes. Send orderId, purchaseToken and originalJson to your backend and validate through Bazaar's REST API; keep connect(null) only if you rely solely on server-side validation.
License #
Distributed under a custom license: free to use, modify and distribute, but provided "as is" — without any warranty, and the author accepts no liability whatsoever for any damage, malfunction or side effects.