Skip to content

Commit d1a3a9f

Browse files
committed
Merge branch 'main' into windows-support
# Conflicts: # Cargo.toml
2 parents b94108d + 3c3c873 commit d1a3a9f

File tree

11 files changed

+278
-42
lines changed

11 files changed

+278
-42
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tauri-plugin-iap"
3-
version = "0.2.1"
3+
version = "0.3.2"
44
authors = ["You"]
55
description = "A Tauri v2 plugin that enables In-App Purchases (IAP)"
66
edition = "2021"
@@ -11,7 +11,7 @@ license = "MIT"
1111
repository = "https://github.com/Choochmeque/tauri-plugin-iap"
1212

1313
[features]
14-
default = ["unstable"]
14+
default = []
1515
unstable = [
1616
"dep:swift-bridge",
1717
"dep:serde_json",

README.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ A Tauri plugin for In-App Purchases (IAP) with support for subscriptions on both
2020
- Real-time purchase state updates via events
2121
- Automatic transaction verification (iOS)
2222
- Support for introductory offers and free trials
23+
- Fraud prevention with obfuscated account/profile IDs (Android)
24+
- App account token support for tracking (iOS)
25+
- Automatic offer token selection (Android)
2326

2427
## Platform Support
2528

@@ -42,7 +45,7 @@ Add the plugin to your Tauri project's `Cargo.toml`:
4245

4346
```toml
4447
[dependencies]
45-
tauri-plugin-iap = "0.1"
48+
tauri-plugin-iap = "0.3"
4649
```
4750

4851
Configure the plugin permissions in your `capabilities/default.json`:
@@ -98,9 +101,24 @@ if (status.isOwned && status.purchaseState === PurchaseState.PURCHASED) {
98101
}
99102

100103
// Purchase a subscription or in-app product
101-
// On Android: use the offer token from subscriptionOfferDetails
102-
// On iOS: offer token is not used
103-
const purchaseResult = await purchase('subscription_id_1', 'subs', offerToken);
104+
// Simple purchase (will use first available offer on Android if not specified)
105+
const purchaseResult = await purchase('subscription_id_1', 'subs');
106+
107+
// With specific offer token (Android)
108+
const purchaseResult = await purchase('subscription_id_1', 'subs', {
109+
offerToken: product.subscriptionOfferDetails[0].offerToken
110+
});
111+
112+
// With fraud prevention (Android)
113+
const purchaseResult = await purchase('subscription_id_1', 'subs', {
114+
obfuscatedAccountId: 'hashed_account_id',
115+
obfuscatedProfileId: 'hashed_profile_id'
116+
});
117+
118+
// With app account token (iOS - must be valid UUID)
119+
const purchaseResult = await purchase('subscription_id_1', 'subs', {
120+
appAccountToken: '550e8400-e29b-41d4-a716-446655440000'
121+
});
104122

105123
// Restore purchases (specify product type)
106124
const restored = await restorePurchases('subs');
@@ -154,13 +172,17 @@ Fetches product details from the store.
154172
- `formattedPrice`: Localized price string
155173
- `subscriptionOfferDetails`: (subscriptions only) Array of offers
156174

157-
### `purchase(productId: string, productType: 'subs' | 'inapp' = 'subs', offerToken?: string)`
158-
Initiates a purchase flow.
175+
### `purchase(productId: string, productType: 'subs' | 'inapp' = 'subs', options?: PurchaseOptions)`
176+
Initiates a purchase flow with enhanced options for fraud prevention and account management.
159177

160178
**Parameters:**
161179
- `productId`: The product to purchase
162180
- `productType`: Type of product ('subs' for subscriptions, 'inapp' for one-time purchases), defaults to 'subs'
163-
- `offerToken`: (Android only) The offer token for subscriptions
181+
- `options`: Optional purchase parameters:
182+
- `offerToken`: (Android) Specific offer to purchase. If not provided, uses first available offer
183+
- `obfuscatedAccountId`: (Android) Hashed account ID for fraud prevention
184+
- `obfuscatedProfileId`: (Android) Hashed profile ID for fraud prevention
185+
- `appAccountToken`: (iOS) UUID string for account tracking and fraud prevention
164186

165187
**Returns:** Purchase object with transaction details
166188

android/src/main/java/IapPlugin.kt

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class PurchaseArgs {
3030
var productId: String = ""
3131
var productType: String = "subs" // "subs" or "inapp"
3232
var offerToken: String? = null
33+
var obfuscatedAccountId: String? = null
34+
var obfuscatedProfileId: String? = null
3335
}
3436

3537
@InvokeArg
@@ -217,24 +219,31 @@ class IapPlugin(private val activity: Activity): Plugin(activity), PurchasesUpda
217219
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && productDetailsResult.productDetailsList.isNotEmpty()) {
218220
val productDetails = productDetailsResult.productDetailsList[0]
219221

220-
val productDetailsParamsList = if (args.offerToken != null) {
221-
listOf(
222-
BillingFlowParams.ProductDetailsParams.newBuilder()
223-
.setProductDetails(productDetails)
224-
.setOfferToken(args.offerToken!!)
225-
.build()
226-
)
227-
} else {
228-
listOf(
229-
BillingFlowParams.ProductDetailsParams.newBuilder()
230-
.setProductDetails(productDetails)
231-
.build()
232-
)
233-
}
222+
// Get offer token from args or from first available subscription offer
223+
val offerToken = args.offerToken ?:
224+
productDetails.subscriptionOfferDetails?.firstOrNull()?.offerToken
225+
226+
val productDetailsParamsBuilder = BillingFlowParams.ProductDetailsParams.newBuilder()
227+
.setProductDetails(productDetails)
228+
229+
offerToken?.let { productDetailsParamsBuilder.setOfferToken(it) }
230+
231+
val productDetailsParamsList = listOf(productDetailsParamsBuilder.build())
234232

235-
val billingFlowParams = BillingFlowParams.newBuilder()
233+
val billingFlowParamsBuilder = BillingFlowParams.newBuilder()
236234
.setProductDetailsParamsList(productDetailsParamsList)
237-
.build()
235+
236+
// Add obfuscated account ID if provided
237+
args.obfuscatedAccountId?.let { accountId ->
238+
billingFlowParamsBuilder.setObfuscatedAccountId(accountId)
239+
}
240+
241+
// Add obfuscated profile ID if provided
242+
args.obfuscatedProfileId?.let { profileId ->
243+
billingFlowParamsBuilder.setObfuscatedProfileId(profileId)
244+
}
245+
246+
val billingFlowParams = billingFlowParamsBuilder.build()
238247

239248
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
240249

0 commit comments

Comments
 (0)