@choochmeque/tauri-plugin-iap-api 0.1.0
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.
- package/README.md +168 -0
- package/dist-js/index.cjs +54 -0
- package/dist-js/index.d.ts +66 -0
- package/dist-js/index.js +46 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Tauri Plugin IAP
|
|
2
|
+
|
|
3
|
+
A Tauri plugin for In-App Purchases (IAP) with support for subscriptions on both iOS (StoreKit 2) and Android (Google Play Billing).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Initialize billing/store connection
|
|
8
|
+
- Query products and subscriptions with detailed pricing
|
|
9
|
+
- Purchase subscriptions with platform-specific features
|
|
10
|
+
- Restore previous purchases
|
|
11
|
+
- Get purchase history
|
|
12
|
+
- Real-time purchase state updates via events
|
|
13
|
+
- Automatic transaction verification (iOS)
|
|
14
|
+
- Support for introductory offers and free trials
|
|
15
|
+
|
|
16
|
+
## Platform Support
|
|
17
|
+
|
|
18
|
+
- **iOS**: StoreKit 2 (requires iOS 15.0+)
|
|
19
|
+
- **Android**: Google Play Billing Library v8.0.0
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add the plugin to your Tauri project:
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[dependencies]
|
|
27
|
+
tauri-plugin-iap = { path = "../path-to-plugin" }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Register the plugin in your Tauri app:
|
|
31
|
+
|
|
32
|
+
```rust
|
|
33
|
+
fn main() {
|
|
34
|
+
tauri::Builder::default()
|
|
35
|
+
.plugin(tauri_plugin_iap::init())
|
|
36
|
+
.run(tauri::generate_context!())
|
|
37
|
+
.expect("error while running tauri application");
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### JavaScript/TypeScript
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import {
|
|
47
|
+
initialize,
|
|
48
|
+
getProducts,
|
|
49
|
+
purchase,
|
|
50
|
+
restorePurchases,
|
|
51
|
+
acknowledgePurchase,
|
|
52
|
+
onPurchaseUpdated
|
|
53
|
+
} from 'tauri-plugin-iap-api';
|
|
54
|
+
|
|
55
|
+
// Initialize the billing client
|
|
56
|
+
await initialize();
|
|
57
|
+
|
|
58
|
+
// Get available products
|
|
59
|
+
const products = await getProducts(['subscription_id_1', 'subscription_id_2'], 'subs');
|
|
60
|
+
|
|
61
|
+
// Purchase a subscription
|
|
62
|
+
// On Android: use the offer token from subscriptionOfferDetails
|
|
63
|
+
// On iOS: offer token is not used
|
|
64
|
+
const purchaseResult = await purchase('subscription_id_1', offerToken);
|
|
65
|
+
|
|
66
|
+
// Restore purchases
|
|
67
|
+
const restored = await restorePurchases();
|
|
68
|
+
|
|
69
|
+
// Acknowledge a purchase (Android only, iOS auto-acknowledges)
|
|
70
|
+
await acknowledgePurchase(purchaseResult.purchaseToken);
|
|
71
|
+
|
|
72
|
+
// Listen for purchase updates
|
|
73
|
+
const unlisten = onPurchaseUpdated((purchase) => {
|
|
74
|
+
console.log('Purchase updated:', purchase);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Stop listening
|
|
78
|
+
unlisten();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Platform Setup
|
|
82
|
+
|
|
83
|
+
### iOS Setup
|
|
84
|
+
|
|
85
|
+
1. Configure your app in App Store Connect
|
|
86
|
+
2. Create subscription products with appropriate pricing
|
|
87
|
+
3. Add In-App Purchase capability to your app in Xcode:
|
|
88
|
+
- Open your project in Xcode
|
|
89
|
+
- Select your target
|
|
90
|
+
- Go to "Signing & Capabilities"
|
|
91
|
+
- Click "+" and add "In-App Purchase"
|
|
92
|
+
4. Test with sandbox accounts
|
|
93
|
+
|
|
94
|
+
### Android Setup
|
|
95
|
+
|
|
96
|
+
1. Add your app to Google Play Console
|
|
97
|
+
2. Create subscription products in Google Play Console
|
|
98
|
+
3. Configure your app's billing permissions (already included in the plugin)
|
|
99
|
+
4. Test with test accounts or sandbox environment
|
|
100
|
+
|
|
101
|
+
## API Reference
|
|
102
|
+
|
|
103
|
+
### `initialize()`
|
|
104
|
+
Initializes the billing client connection (required on Android, no-op on iOS).
|
|
105
|
+
|
|
106
|
+
### `getProducts(productIds: string[], productType: 'subs' | 'inapp')`
|
|
107
|
+
Fetches product details from the store.
|
|
108
|
+
|
|
109
|
+
**Returns:**
|
|
110
|
+
- `products`: Array of product objects with:
|
|
111
|
+
- `productId`: Product identifier
|
|
112
|
+
- `title`: Display name
|
|
113
|
+
- `description`: Product description
|
|
114
|
+
- `productType`: Type of product
|
|
115
|
+
- `formattedPrice`: Localized price string
|
|
116
|
+
- `subscriptionOfferDetails`: (subscriptions only) Array of offers
|
|
117
|
+
|
|
118
|
+
### `purchase(productId: string, offerToken?: string)`
|
|
119
|
+
Initiates a purchase flow.
|
|
120
|
+
|
|
121
|
+
**Parameters:**
|
|
122
|
+
- `productId`: The product to purchase
|
|
123
|
+
- `offerToken`: (Android only) The offer token for subscriptions
|
|
124
|
+
|
|
125
|
+
**Returns:** Purchase object with transaction details
|
|
126
|
+
|
|
127
|
+
### `restorePurchases()`
|
|
128
|
+
Queries and returns all active purchases.
|
|
129
|
+
|
|
130
|
+
### `getPurchaseHistory()`
|
|
131
|
+
Returns the complete purchase history.
|
|
132
|
+
|
|
133
|
+
### `acknowledgePurchase(purchaseToken: string)`
|
|
134
|
+
Acknowledges a purchase (required on Android within 3 days, no-op on iOS).
|
|
135
|
+
|
|
136
|
+
### `onPurchaseUpdated(callback: (purchase: Purchase) => void)`
|
|
137
|
+
Listens for purchase state changes.
|
|
138
|
+
|
|
139
|
+
## Differences Between Platforms
|
|
140
|
+
|
|
141
|
+
### iOS (StoreKit 2)
|
|
142
|
+
- Automatic transaction verification
|
|
143
|
+
- No manual acknowledgment needed
|
|
144
|
+
- Supports introductory offers and promotional offers
|
|
145
|
+
- Transaction updates are automatically observed
|
|
146
|
+
- Requires iOS 15.0+
|
|
147
|
+
|
|
148
|
+
### Android (Google Play Billing)
|
|
149
|
+
- Manual acknowledgment required within 3 days
|
|
150
|
+
- Supports multiple subscription offers per product
|
|
151
|
+
- Offer tokens required for subscription purchases
|
|
152
|
+
- More detailed pricing phase information
|
|
153
|
+
|
|
154
|
+
## Testing
|
|
155
|
+
|
|
156
|
+
### iOS
|
|
157
|
+
1. Use sandbox test accounts
|
|
158
|
+
2. Test on physical devices (subscriptions don't work well on simulators)
|
|
159
|
+
3. Clear purchase history in Settings > App Store > Sandbox Account
|
|
160
|
+
|
|
161
|
+
### Android
|
|
162
|
+
1. Upload your app to internal testing track
|
|
163
|
+
2. Add test accounts in Google Play Console
|
|
164
|
+
3. Test with test payment methods
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT or Apache-2.0
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@tauri-apps/api/core');
|
|
4
|
+
var event = require('@tauri-apps/api/event');
|
|
5
|
+
|
|
6
|
+
async function initialize() {
|
|
7
|
+
return await core.invoke('plugin:iap|initialize');
|
|
8
|
+
}
|
|
9
|
+
async function getProducts(productIds, productType = 'subs') {
|
|
10
|
+
return await core.invoke('plugin:iap|get_products', {
|
|
11
|
+
payload: {
|
|
12
|
+
productIds,
|
|
13
|
+
productType,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function purchase(productId, offerToken) {
|
|
18
|
+
return await core.invoke('plugin:iap|purchase', {
|
|
19
|
+
payload: {
|
|
20
|
+
productId,
|
|
21
|
+
offerToken,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function restorePurchases() {
|
|
26
|
+
return await core.invoke('plugin:iap|restore_purchases');
|
|
27
|
+
}
|
|
28
|
+
async function getPurchaseHistory() {
|
|
29
|
+
return await core.invoke('plugin:iap|get_purchase_history');
|
|
30
|
+
}
|
|
31
|
+
async function acknowledgePurchase(purchaseToken) {
|
|
32
|
+
return await core.invoke('plugin:iap|acknowledge_purchase', {
|
|
33
|
+
payload: {
|
|
34
|
+
purchaseToken,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// Event listener for purchase updates
|
|
39
|
+
function onPurchaseUpdated(callback) {
|
|
40
|
+
const unlisten = event.listen('purchaseUpdated', (event) => {
|
|
41
|
+
callback(event.payload);
|
|
42
|
+
});
|
|
43
|
+
return () => {
|
|
44
|
+
unlisten.then((fn) => fn());
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports.acknowledgePurchase = acknowledgePurchase;
|
|
49
|
+
exports.getProducts = getProducts;
|
|
50
|
+
exports.getPurchaseHistory = getPurchaseHistory;
|
|
51
|
+
exports.initialize = initialize;
|
|
52
|
+
exports.onPurchaseUpdated = onPurchaseUpdated;
|
|
53
|
+
exports.purchase = purchase;
|
|
54
|
+
exports.restorePurchases = restorePurchases;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface InitializeResponse {
|
|
2
|
+
success: boolean;
|
|
3
|
+
}
|
|
4
|
+
export interface PricingPhase {
|
|
5
|
+
formattedPrice: string;
|
|
6
|
+
priceCurrencyCode: string;
|
|
7
|
+
priceAmountMicros: number;
|
|
8
|
+
billingPeriod: string;
|
|
9
|
+
billingCycleCount: number;
|
|
10
|
+
recurrenceMode: number;
|
|
11
|
+
}
|
|
12
|
+
export interface SubscriptionOffer {
|
|
13
|
+
offerToken: string;
|
|
14
|
+
basePlanId: string;
|
|
15
|
+
offerId?: string;
|
|
16
|
+
pricingPhases: PricingPhase[];
|
|
17
|
+
}
|
|
18
|
+
export interface Product {
|
|
19
|
+
productId: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
productType: string;
|
|
23
|
+
formattedPrice?: string;
|
|
24
|
+
priceCurrencyCode?: string;
|
|
25
|
+
priceAmountMicros?: number;
|
|
26
|
+
subscriptionOfferDetails?: SubscriptionOffer[];
|
|
27
|
+
}
|
|
28
|
+
export interface GetProductsResponse {
|
|
29
|
+
products: Product[];
|
|
30
|
+
}
|
|
31
|
+
export interface Purchase {
|
|
32
|
+
orderId?: string;
|
|
33
|
+
packageName: string;
|
|
34
|
+
productId: string;
|
|
35
|
+
purchaseTime: number;
|
|
36
|
+
purchaseToken: string;
|
|
37
|
+
purchaseState: number;
|
|
38
|
+
isAutoRenewing: boolean;
|
|
39
|
+
isAcknowledged: boolean;
|
|
40
|
+
originalJson: string;
|
|
41
|
+
signature: string;
|
|
42
|
+
}
|
|
43
|
+
export interface RestorePurchasesResponse {
|
|
44
|
+
purchases: Purchase[];
|
|
45
|
+
}
|
|
46
|
+
export interface PurchaseHistoryRecord {
|
|
47
|
+
productId: string;
|
|
48
|
+
purchaseTime: number;
|
|
49
|
+
purchaseToken: string;
|
|
50
|
+
quantity: number;
|
|
51
|
+
originalJson: string;
|
|
52
|
+
signature: string;
|
|
53
|
+
}
|
|
54
|
+
export interface GetPurchaseHistoryResponse {
|
|
55
|
+
history: PurchaseHistoryRecord[];
|
|
56
|
+
}
|
|
57
|
+
export interface AcknowledgePurchaseResponse {
|
|
58
|
+
success: boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare function initialize(): Promise<InitializeResponse>;
|
|
61
|
+
export declare function getProducts(productIds: string[], productType?: 'subs' | 'inapp'): Promise<GetProductsResponse>;
|
|
62
|
+
export declare function purchase(productId: string, offerToken?: string): Promise<Purchase>;
|
|
63
|
+
export declare function restorePurchases(): Promise<RestorePurchasesResponse>;
|
|
64
|
+
export declare function getPurchaseHistory(): Promise<GetPurchaseHistoryResponse>;
|
|
65
|
+
export declare function acknowledgePurchase(purchaseToken: string): Promise<AcknowledgePurchaseResponse>;
|
|
66
|
+
export declare function onPurchaseUpdated(callback: (purchase: Purchase) => void): () => void;
|
package/dist-js/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
2
|
+
import { listen } from '@tauri-apps/api/event';
|
|
3
|
+
|
|
4
|
+
async function initialize() {
|
|
5
|
+
return await invoke('plugin:iap|initialize');
|
|
6
|
+
}
|
|
7
|
+
async function getProducts(productIds, productType = 'subs') {
|
|
8
|
+
return await invoke('plugin:iap|get_products', {
|
|
9
|
+
payload: {
|
|
10
|
+
productIds,
|
|
11
|
+
productType,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async function purchase(productId, offerToken) {
|
|
16
|
+
return await invoke('plugin:iap|purchase', {
|
|
17
|
+
payload: {
|
|
18
|
+
productId,
|
|
19
|
+
offerToken,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function restorePurchases() {
|
|
24
|
+
return await invoke('plugin:iap|restore_purchases');
|
|
25
|
+
}
|
|
26
|
+
async function getPurchaseHistory() {
|
|
27
|
+
return await invoke('plugin:iap|get_purchase_history');
|
|
28
|
+
}
|
|
29
|
+
async function acknowledgePurchase(purchaseToken) {
|
|
30
|
+
return await invoke('plugin:iap|acknowledge_purchase', {
|
|
31
|
+
payload: {
|
|
32
|
+
purchaseToken,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Event listener for purchase updates
|
|
37
|
+
function onPurchaseUpdated(callback) {
|
|
38
|
+
const unlisten = listen('purchaseUpdated', (event) => {
|
|
39
|
+
callback(event.payload);
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
unlisten.then((fn) => fn());
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { acknowledgePurchase, getProducts, getPurchaseHistory, initialize, onPurchaseUpdated, purchase, restorePurchases };
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@choochmeque/tauri-plugin-iap-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"author": "You",
|
|
5
|
+
"description": "Tauri plugin for in-app purchases",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "./dist-js/index.d.ts",
|
|
8
|
+
"main": "./dist-js/index.cjs",
|
|
9
|
+
"module": "./dist-js/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
"types": "./dist-js/index.d.ts",
|
|
12
|
+
"import": "./dist-js/index.js",
|
|
13
|
+
"require": "./dist-js/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist-js",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"directories": {
|
|
20
|
+
"example": "examples"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/Choochmeque/tauri-plugin-iap.git"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"tauri",
|
|
28
|
+
"iap"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/Choochmeque/tauri-plugin-iap/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/Choochmeque/tauri-plugin-iap#readme",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "rollup -c",
|
|
37
|
+
"prepublishOnly": "pnpm build",
|
|
38
|
+
"pretest": "pnpm build"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@tauri-apps/api": ">=2.0.0-beta.6"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
45
|
+
"rollup": "^4.9.6",
|
|
46
|
+
"tslib": "^2.6.2",
|
|
47
|
+
"typescript": "^5.3.3"
|
|
48
|
+
},
|
|
49
|
+
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f"
|
|
50
|
+
}
|