packwise-skills 1.0.0 → 1.2.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/.cursorrules +23 -23
- package/CLAUDE.md +25 -25
- package/LICENSE +21 -0
- package/README.md +404 -295
- package/audit.md +224 -224
- package/bin/packwise.js +322 -155
- package/install.sh +123 -0
- package/package.json +32 -31
- package/skill.md +944 -719
- package/sub-skills/ai/local-llm.md +183 -183
- package/sub-skills/ai/python-ml.md +164 -164
- package/sub-skills/backend/go-server.md +184 -184
- package/sub-skills/backend/java-spring.md +241 -241
- package/sub-skills/backend/node-server.md +164 -164
- package/sub-skills/backend/php-laravel.md +175 -175
- package/sub-skills/backend/python-server.md +164 -164
- package/sub-skills/backend/rust-backend.md +118 -118
- package/sub-skills/cli/python-cli.md +236 -236
- package/sub-skills/cli/sdk-library.md +497 -497
- package/sub-skills/cloud/ci-cd-pipelines.md +350 -350
- package/sub-skills/cloud/docker.md +191 -191
- package/sub-skills/cloud/kubernetes.md +277 -277
- package/sub-skills/cloud/payment-integration.md +307 -307
- package/sub-skills/cross-platform/multiplatform.md +252 -252
- package/sub-skills/desktop/electron.md +783 -783
- package/sub-skills/desktop/game-dev.md +443 -443
- package/sub-skills/desktop/native-app.md +123 -123
- package/sub-skills/desktop/scenarios.md +443 -443
- package/sub-skills/desktop/smart-platforms.md +324 -324
- package/sub-skills/desktop/tauri.md +428 -428
- package/sub-skills/desktop/vr-ar.md +252 -252
- package/sub-skills/desktop/web-to-desktop.md +153 -153
- package/sub-skills/embedded/car-infotainment.md +129 -129
- package/sub-skills/embedded/esp32.md +184 -184
- package/sub-skills/embedded/ros.md +150 -150
- package/sub-skills/embedded/stm32.md +160 -160
- package/sub-skills/mobile/android.md +322 -322
- package/sub-skills/mobile/capacitor.md +232 -232
- package/sub-skills/mobile/flutter-mobile.md +138 -138
- package/sub-skills/mobile/harmonyos.md +150 -150
- package/sub-skills/mobile/ios.md +245 -245
- package/sub-skills/mobile/react-native.md +443 -443
- package/sub-skills/mobile/wearables.md +230 -230
- package/sub-skills/plugins/browser-extension.md +308 -308
- package/sub-skills/plugins/jetbrains-plugin.md +226 -226
- package/sub-skills/plugins/vscode-extension.md +204 -204
- package/sub-skills/security/security-tools.md +174 -174
- package/sub-skills/web/monorepo.md +274 -274
- package/sub-skills/web/pwa.md +220 -220
- package/sub-skills/web/serverless-edge.md +295 -295
- package/sub-skills/web/spa.md +266 -266
- package/sub-skills/web/ssr.md +228 -228
- package/sub-skills/web/wasm.md +243 -243
|
@@ -1,307 +1,307 @@
|
|
|
1
|
-
# Payment Integration Build Sub-Skill
|
|
2
|
-
|
|
3
|
-
Integrate payment systems into applications during build and packaging.
|
|
4
|
-
|
|
5
|
-
**Current versions**: Stripe API 2024-12 / Alipay / WeChat Pay / Apple IAP / Google Play Billing (2025-2026)
|
|
6
|
-
|
|
7
|
-
## When to Use
|
|
8
|
-
|
|
9
|
-
- SaaS applications with subscription billing
|
|
10
|
-
- E-commerce applications
|
|
11
|
-
- Mobile apps with in-app purchases
|
|
12
|
-
- Marketplace / platform payments
|
|
13
|
-
- Donations / tipping
|
|
14
|
-
|
|
15
|
-
## Payment Platform Comparison
|
|
16
|
-
|
|
17
|
-
| Platform | Coverage | Fee | Best For |
|
|
18
|
-
|----------|----------|-----|---------|
|
|
19
|
-
| Stripe | Global (46+ countries) | 2.9% + $0.30/txn | Global SaaS, web apps |
|
|
20
|
-
| Alipay | China | 0.6% | China market |
|
|
21
|
-
| WeChat Pay | China | 0.6% | China market, mini-programs |
|
|
22
|
-
| PayPal | Global | 2.9% + $0.30/txn | Broad consumer reach |
|
|
23
|
-
| Apple IAP | iOS/macOS | 15–30% | iOS in-app purchases (required) |
|
|
24
|
-
| Google Play Billing | Android | 15–30% | Android in-app purchases (required) |
|
|
25
|
-
| Paddle | Global | 5% + fee | SaaS (handles tax/compliance) |
|
|
26
|
-
| LemonSqueezy | Global | 5% + fee | Digital products, indie SaaS |
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Stripe Integration
|
|
31
|
-
|
|
32
|
-
### Web (Node.js Backend)
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npm install stripe
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
```javascript
|
|
39
|
-
// server/stripe.js
|
|
40
|
-
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
|
|
41
|
-
|
|
42
|
-
// Create checkout session
|
|
43
|
-
app.post('/create-checkout', async (req, res) => {
|
|
44
|
-
const session = await stripe.checkout.sessions.create({
|
|
45
|
-
payment_method_types: ['card'],
|
|
46
|
-
line_items: [{
|
|
47
|
-
price_data: {
|
|
48
|
-
currency: 'usd',
|
|
49
|
-
product_data: { name: 'My Product' },
|
|
50
|
-
unit_amount: 2000, // $20.00
|
|
51
|
-
},
|
|
52
|
-
quantity: 1,
|
|
53
|
-
}],
|
|
54
|
-
mode: 'payment',
|
|
55
|
-
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
|
|
56
|
-
cancel_url: `${process.env.APP_URL}/cancel`,
|
|
57
|
-
});
|
|
58
|
-
res.json({ url: session.url });
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Webhook handler (required for production)
|
|
62
|
-
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
|
63
|
-
const sig = req.headers['stripe-signature'];
|
|
64
|
-
const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
|
|
65
|
-
|
|
66
|
-
switch (event.type) {
|
|
67
|
-
case 'checkout.session.completed':
|
|
68
|
-
// Fulfill order
|
|
69
|
-
break;
|
|
70
|
-
case 'invoice.paid':
|
|
71
|
-
// Update subscription status
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
res.json({ received: true });
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### React Frontend
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
npm install @stripe/stripe-js @stripe/react-stripe-js
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
import { loadStripe } from '@stripe/stripe-js';
|
|
86
|
-
import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
|
|
87
|
-
|
|
88
|
-
const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY);
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Subscription Billing
|
|
92
|
-
|
|
93
|
-
```javascript
|
|
94
|
-
// Create subscription
|
|
95
|
-
const subscription = await stripe.subscriptions.create({
|
|
96
|
-
customer: customerId,
|
|
97
|
-
items: [{ price: 'price_monthly_xxx' }],
|
|
98
|
-
payment_behavior: 'default_incomplete',
|
|
99
|
-
expand: ['latest_invoice.payment_intent'],
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Alipay & WeChat Pay
|
|
106
|
-
|
|
107
|
-
### Stripe + Alipay/WeChat (Recommended for international)
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
// Stripe supports Alipay and WeChat Pay as payment methods
|
|
111
|
-
const session = await stripe.checkout.sessions.create({
|
|
112
|
-
payment_method_types: ['card', 'alipay', 'wechat_pay'],
|
|
113
|
-
// ...
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Native Alipay SDK
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
pip install alipay-sdk-python
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
|
|
125
|
-
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
|
|
126
|
-
|
|
127
|
-
config = AlipayClientConfig()
|
|
128
|
-
config.app_id = "your_app_id"
|
|
129
|
-
config.app_private_key = "your_private_key"
|
|
130
|
-
config.alipay_public_key = "alipay_public_key"
|
|
131
|
-
|
|
132
|
-
client = DefaultAlipayClient(config)
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Native WeChat Pay SDK
|
|
136
|
-
|
|
137
|
-
```xml
|
|
138
|
-
<!-- Java/Maven -->
|
|
139
|
-
<dependency>
|
|
140
|
-
<groupId>com.github.wxpay</groupId>
|
|
141
|
-
<artifactId>wxpay-sdk</artifactId>
|
|
142
|
-
<version>3.4.0</version>
|
|
143
|
-
</dependency>
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## Apple In-App Purchase (IAP)
|
|
149
|
-
|
|
150
|
-
### When Required
|
|
151
|
-
|
|
152
|
-
- Digital content consumed in the app (subscriptions, premium features, virtual goods)
|
|
153
|
-
- **Physical goods**: Use Stripe/PayPal instead
|
|
154
|
-
- **External links**: Apple allows external payment links in some regions (EU, US)
|
|
155
|
-
|
|
156
|
-
### Swift Implementation
|
|
157
|
-
|
|
158
|
-
```swift
|
|
159
|
-
import StoreKit
|
|
160
|
-
|
|
161
|
-
class StoreManager: ObservableObject {
|
|
162
|
-
@Published var products: [Product] = []
|
|
163
|
-
|
|
164
|
-
func loadProducts() async {
|
|
165
|
-
do {
|
|
166
|
-
products = try await Product.products(for: ["com.app.premium_monthly", "com.app.premium_yearly"])
|
|
167
|
-
} catch {
|
|
168
|
-
print("Failed to load products: \(error)")
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
func purchase(_ product: Product) async throws -> Transaction? {
|
|
173
|
-
let result = try await product.purchase()
|
|
174
|
-
switch result {
|
|
175
|
-
case .success(let verification):
|
|
176
|
-
let transaction = try checkVerified(verification)
|
|
177
|
-
await transaction.finish()
|
|
178
|
-
return transaction
|
|
179
|
-
case .userCancelled:
|
|
180
|
-
return nil
|
|
181
|
-
case .pending:
|
|
182
|
-
return nil
|
|
183
|
-
@unknown default:
|
|
184
|
-
return nil
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### App Store Configuration
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
1. App Store Connect → In-App Purchases → Create
|
|
194
|
-
2. Set product ID, price, localization
|
|
195
|
-
3. Submit for review (can take 24-48 hours)
|
|
196
|
-
4. Implement receipt validation on server (recommended)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## Google Play Billing
|
|
202
|
-
|
|
203
|
-
### Kotlin Implementation
|
|
204
|
-
|
|
205
|
-
```kotlin
|
|
206
|
-
// build.gradle.kts
|
|
207
|
-
dependencies {
|
|
208
|
-
implementation("com.android.billingclient:billing-ktx:7.0.0")
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// BillingManager.kt
|
|
212
|
-
class BillingManager(context: Context) {
|
|
213
|
-
private val billingClient = BillingClient.newBuilder(context)
|
|
214
|
-
.setListener { billingResult, purchases ->
|
|
215
|
-
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
|
|
216
|
-
for (purchase in purchases) handlePurchase(purchase)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
.enablePendingPurchases()
|
|
220
|
-
.build()
|
|
221
|
-
|
|
222
|
-
fun startConnection() {
|
|
223
|
-
billingClient.startConnection(object : BillingClientStateListener {
|
|
224
|
-
override fun onBillingSetupFinished(result: BillingResult) {
|
|
225
|
-
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
226
|
-
queryProducts()
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
override fun onBillingServiceDisconnected() { /* retry */ }
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private fun queryProducts() {
|
|
234
|
-
val productList = listOf(
|
|
235
|
-
QueryProductDetailsParams.Product.newBuilder()
|
|
236
|
-
.setProductId("premium_monthly")
|
|
237
|
-
.setProductType(BillingClient.ProductType.SUBS)
|
|
238
|
-
.build()
|
|
239
|
-
)
|
|
240
|
-
val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build()
|
|
241
|
-
billingClient.queryProductDetailsAsync(params) { result, productDetailsList ->
|
|
242
|
-
// Display products to user
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### Google Play Console Configuration
|
|
249
|
-
|
|
250
|
-
```
|
|
251
|
-
1. Google Play Console → Monetize → Products → Subscriptions
|
|
252
|
-
2. Create subscription product with base plan
|
|
253
|
-
3. Set pricing, grace period, offers
|
|
254
|
-
4. Upload app with billing permission
|
|
255
|
-
5. Test with license testers
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Server-Side Receipt Validation (Critical for Security)
|
|
261
|
-
|
|
262
|
-
```javascript
|
|
263
|
-
// Apple receipt validation
|
|
264
|
-
const appleReceiptVerify = require('node-apple-receipt-verify');
|
|
265
|
-
appleReceiptVerify.config({ secret: process.env.APPLE_SHARED_SECRET });
|
|
266
|
-
|
|
267
|
-
const products = await appleReceiptVerify.validate({
|
|
268
|
-
receipt: receiptData,
|
|
269
|
-
verbose: true,
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Google Play receipt validation
|
|
273
|
-
const { google } = require('googleapis');
|
|
274
|
-
const androidpublisher = google.androidpublisher('v3');
|
|
275
|
-
const purchase = await androidpublisher.purchases.subscriptions.get({
|
|
276
|
-
packageName: 'com.example.app',
|
|
277
|
-
subscriptionId: 'premium_monthly',
|
|
278
|
-
token: purchaseToken,
|
|
279
|
-
});
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
## Payment Security Checklist
|
|
285
|
-
|
|
286
|
-
| Requirement | Implementation |
|
|
287
|
-
|-------------|---------------|
|
|
288
|
-
| **Never trust client-side** | Always validate payments server-side |
|
|
289
|
-
| **Webhook signature verification** | Verify Stripe/Alipay webhook signatures |
|
|
290
|
-
| **HTTPS only** | All payment pages must use HTTPS |
|
|
291
|
-
| **PCI compliance** | Use Stripe Elements (no raw card data on your server) |
|
|
292
|
-
| **Idempotency** | Use idempotency keys to prevent double charges |
|
|
293
|
-
| **Receipt validation** | Validate IAP receipts server-side (Apple/Google) |
|
|
294
|
-
| **Fraud detection** | Implement rate limiting; flag suspicious patterns |
|
|
295
|
-
| **Secure key storage** | Use environment variables / secret managers; never commit keys |
|
|
296
|
-
|
|
297
|
-
## Common Pitfalls
|
|
298
|
-
|
|
299
|
-
| Issue | Fix |
|
|
300
|
-
|-------|-----|
|
|
301
|
-
| Apple IAP rejected | Ensure IAP is for digital content; physical goods use other processors |
|
|
302
|
-
| Stripe webhook not receiving | Check webhook URL; verify signature; use Stripe CLI for testing |
|
|
303
|
-
| Double charges | Implement idempotency keys; check payment status before fulfilling |
|
|
304
|
-
| Currency mismatch | Use `currency` consistently; Stripe amounts are in cents |
|
|
305
|
-
| Alipay/WeChat cross-border | Use Stripe's built-in support; or apply for merchant accounts directly |
|
|
306
|
-
| Google Play billing crash | Handle `BillingClientStateListener` disconnection; retry logic |
|
|
307
|
-
| Tax compliance | Use Stripe Tax or Paddle for automatic tax calculation |
|
|
1
|
+
# Payment Integration Build Sub-Skill
|
|
2
|
+
|
|
3
|
+
Integrate payment systems into applications during build and packaging.
|
|
4
|
+
|
|
5
|
+
**Current versions**: Stripe API 2024-12 / Alipay / WeChat Pay / Apple IAP / Google Play Billing (2025-2026)
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
- SaaS applications with subscription billing
|
|
10
|
+
- E-commerce applications
|
|
11
|
+
- Mobile apps with in-app purchases
|
|
12
|
+
- Marketplace / platform payments
|
|
13
|
+
- Donations / tipping
|
|
14
|
+
|
|
15
|
+
## Payment Platform Comparison
|
|
16
|
+
|
|
17
|
+
| Platform | Coverage | Fee | Best For |
|
|
18
|
+
|----------|----------|-----|---------|
|
|
19
|
+
| Stripe | Global (46+ countries) | 2.9% + $0.30/txn | Global SaaS, web apps |
|
|
20
|
+
| Alipay | China | 0.6% | China market |
|
|
21
|
+
| WeChat Pay | China | 0.6% | China market, mini-programs |
|
|
22
|
+
| PayPal | Global | 2.9% + $0.30/txn | Broad consumer reach |
|
|
23
|
+
| Apple IAP | iOS/macOS | 15–30% | iOS in-app purchases (required) |
|
|
24
|
+
| Google Play Billing | Android | 15–30% | Android in-app purchases (required) |
|
|
25
|
+
| Paddle | Global | 5% + fee | SaaS (handles tax/compliance) |
|
|
26
|
+
| LemonSqueezy | Global | 5% + fee | Digital products, indie SaaS |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Stripe Integration
|
|
31
|
+
|
|
32
|
+
### Web (Node.js Backend)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install stripe
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// server/stripe.js
|
|
40
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
|
|
41
|
+
|
|
42
|
+
// Create checkout session
|
|
43
|
+
app.post('/create-checkout', async (req, res) => {
|
|
44
|
+
const session = await stripe.checkout.sessions.create({
|
|
45
|
+
payment_method_types: ['card'],
|
|
46
|
+
line_items: [{
|
|
47
|
+
price_data: {
|
|
48
|
+
currency: 'usd',
|
|
49
|
+
product_data: { name: 'My Product' },
|
|
50
|
+
unit_amount: 2000, // $20.00
|
|
51
|
+
},
|
|
52
|
+
quantity: 1,
|
|
53
|
+
}],
|
|
54
|
+
mode: 'payment',
|
|
55
|
+
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
|
|
56
|
+
cancel_url: `${process.env.APP_URL}/cancel`,
|
|
57
|
+
});
|
|
58
|
+
res.json({ url: session.url });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Webhook handler (required for production)
|
|
62
|
+
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
|
63
|
+
const sig = req.headers['stripe-signature'];
|
|
64
|
+
const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
|
|
65
|
+
|
|
66
|
+
switch (event.type) {
|
|
67
|
+
case 'checkout.session.completed':
|
|
68
|
+
// Fulfill order
|
|
69
|
+
break;
|
|
70
|
+
case 'invoice.paid':
|
|
71
|
+
// Update subscription status
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
res.json({ received: true });
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### React Frontend
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install @stripe/stripe-js @stripe/react-stripe-js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
import { loadStripe } from '@stripe/stripe-js';
|
|
86
|
+
import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
|
|
87
|
+
|
|
88
|
+
const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Subscription Billing
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
// Create subscription
|
|
95
|
+
const subscription = await stripe.subscriptions.create({
|
|
96
|
+
customer: customerId,
|
|
97
|
+
items: [{ price: 'price_monthly_xxx' }],
|
|
98
|
+
payment_behavior: 'default_incomplete',
|
|
99
|
+
expand: ['latest_invoice.payment_intent'],
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Alipay & WeChat Pay
|
|
106
|
+
|
|
107
|
+
### Stripe + Alipay/WeChat (Recommended for international)
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
// Stripe supports Alipay and WeChat Pay as payment methods
|
|
111
|
+
const session = await stripe.checkout.sessions.create({
|
|
112
|
+
payment_method_types: ['card', 'alipay', 'wechat_pay'],
|
|
113
|
+
// ...
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Native Alipay SDK
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pip install alipay-sdk-python
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
|
|
125
|
+
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
|
|
126
|
+
|
|
127
|
+
config = AlipayClientConfig()
|
|
128
|
+
config.app_id = "your_app_id"
|
|
129
|
+
config.app_private_key = "your_private_key"
|
|
130
|
+
config.alipay_public_key = "alipay_public_key"
|
|
131
|
+
|
|
132
|
+
client = DefaultAlipayClient(config)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Native WeChat Pay SDK
|
|
136
|
+
|
|
137
|
+
```xml
|
|
138
|
+
<!-- Java/Maven -->
|
|
139
|
+
<dependency>
|
|
140
|
+
<groupId>com.github.wxpay</groupId>
|
|
141
|
+
<artifactId>wxpay-sdk</artifactId>
|
|
142
|
+
<version>3.4.0</version>
|
|
143
|
+
</dependency>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Apple In-App Purchase (IAP)
|
|
149
|
+
|
|
150
|
+
### When Required
|
|
151
|
+
|
|
152
|
+
- Digital content consumed in the app (subscriptions, premium features, virtual goods)
|
|
153
|
+
- **Physical goods**: Use Stripe/PayPal instead
|
|
154
|
+
- **External links**: Apple allows external payment links in some regions (EU, US)
|
|
155
|
+
|
|
156
|
+
### Swift Implementation
|
|
157
|
+
|
|
158
|
+
```swift
|
|
159
|
+
import StoreKit
|
|
160
|
+
|
|
161
|
+
class StoreManager: ObservableObject {
|
|
162
|
+
@Published var products: [Product] = []
|
|
163
|
+
|
|
164
|
+
func loadProducts() async {
|
|
165
|
+
do {
|
|
166
|
+
products = try await Product.products(for: ["com.app.premium_monthly", "com.app.premium_yearly"])
|
|
167
|
+
} catch {
|
|
168
|
+
print("Failed to load products: \(error)")
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
func purchase(_ product: Product) async throws -> Transaction? {
|
|
173
|
+
let result = try await product.purchase()
|
|
174
|
+
switch result {
|
|
175
|
+
case .success(let verification):
|
|
176
|
+
let transaction = try checkVerified(verification)
|
|
177
|
+
await transaction.finish()
|
|
178
|
+
return transaction
|
|
179
|
+
case .userCancelled:
|
|
180
|
+
return nil
|
|
181
|
+
case .pending:
|
|
182
|
+
return nil
|
|
183
|
+
@unknown default:
|
|
184
|
+
return nil
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### App Store Configuration
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
1. App Store Connect → In-App Purchases → Create
|
|
194
|
+
2. Set product ID, price, localization
|
|
195
|
+
3. Submit for review (can take 24-48 hours)
|
|
196
|
+
4. Implement receipt validation on server (recommended)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Google Play Billing
|
|
202
|
+
|
|
203
|
+
### Kotlin Implementation
|
|
204
|
+
|
|
205
|
+
```kotlin
|
|
206
|
+
// build.gradle.kts
|
|
207
|
+
dependencies {
|
|
208
|
+
implementation("com.android.billingclient:billing-ktx:7.0.0")
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// BillingManager.kt
|
|
212
|
+
class BillingManager(context: Context) {
|
|
213
|
+
private val billingClient = BillingClient.newBuilder(context)
|
|
214
|
+
.setListener { billingResult, purchases ->
|
|
215
|
+
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
|
|
216
|
+
for (purchase in purchases) handlePurchase(purchase)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
.enablePendingPurchases()
|
|
220
|
+
.build()
|
|
221
|
+
|
|
222
|
+
fun startConnection() {
|
|
223
|
+
billingClient.startConnection(object : BillingClientStateListener {
|
|
224
|
+
override fun onBillingSetupFinished(result: BillingResult) {
|
|
225
|
+
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
226
|
+
queryProducts()
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
override fun onBillingServiceDisconnected() { /* retry */ }
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private fun queryProducts() {
|
|
234
|
+
val productList = listOf(
|
|
235
|
+
QueryProductDetailsParams.Product.newBuilder()
|
|
236
|
+
.setProductId("premium_monthly")
|
|
237
|
+
.setProductType(BillingClient.ProductType.SUBS)
|
|
238
|
+
.build()
|
|
239
|
+
)
|
|
240
|
+
val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build()
|
|
241
|
+
billingClient.queryProductDetailsAsync(params) { result, productDetailsList ->
|
|
242
|
+
// Display products to user
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Google Play Console Configuration
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
1. Google Play Console → Monetize → Products → Subscriptions
|
|
252
|
+
2. Create subscription product with base plan
|
|
253
|
+
3. Set pricing, grace period, offers
|
|
254
|
+
4. Upload app with billing permission
|
|
255
|
+
5. Test with license testers
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Server-Side Receipt Validation (Critical for Security)
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// Apple receipt validation
|
|
264
|
+
const appleReceiptVerify = require('node-apple-receipt-verify');
|
|
265
|
+
appleReceiptVerify.config({ secret: process.env.APPLE_SHARED_SECRET });
|
|
266
|
+
|
|
267
|
+
const products = await appleReceiptVerify.validate({
|
|
268
|
+
receipt: receiptData,
|
|
269
|
+
verbose: true,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Google Play receipt validation
|
|
273
|
+
const { google } = require('googleapis');
|
|
274
|
+
const androidpublisher = google.androidpublisher('v3');
|
|
275
|
+
const purchase = await androidpublisher.purchases.subscriptions.get({
|
|
276
|
+
packageName: 'com.example.app',
|
|
277
|
+
subscriptionId: 'premium_monthly',
|
|
278
|
+
token: purchaseToken,
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Payment Security Checklist
|
|
285
|
+
|
|
286
|
+
| Requirement | Implementation |
|
|
287
|
+
|-------------|---------------|
|
|
288
|
+
| **Never trust client-side** | Always validate payments server-side |
|
|
289
|
+
| **Webhook signature verification** | Verify Stripe/Alipay webhook signatures |
|
|
290
|
+
| **HTTPS only** | All payment pages must use HTTPS |
|
|
291
|
+
| **PCI compliance** | Use Stripe Elements (no raw card data on your server) |
|
|
292
|
+
| **Idempotency** | Use idempotency keys to prevent double charges |
|
|
293
|
+
| **Receipt validation** | Validate IAP receipts server-side (Apple/Google) |
|
|
294
|
+
| **Fraud detection** | Implement rate limiting; flag suspicious patterns |
|
|
295
|
+
| **Secure key storage** | Use environment variables / secret managers; never commit keys |
|
|
296
|
+
|
|
297
|
+
## Common Pitfalls
|
|
298
|
+
|
|
299
|
+
| Issue | Fix |
|
|
300
|
+
|-------|-----|
|
|
301
|
+
| Apple IAP rejected | Ensure IAP is for digital content; physical goods use other processors |
|
|
302
|
+
| Stripe webhook not receiving | Check webhook URL; verify signature; use Stripe CLI for testing |
|
|
303
|
+
| Double charges | Implement idempotency keys; check payment status before fulfilling |
|
|
304
|
+
| Currency mismatch | Use `currency` consistently; Stripe amounts are in cents |
|
|
305
|
+
| Alipay/WeChat cross-border | Use Stripe's built-in support; or apply for merchant accounts directly |
|
|
306
|
+
| Google Play billing crash | Handle `BillingClientStateListener` disconnection; retry logic |
|
|
307
|
+
| Tax compliance | Use Stripe Tax or Paddle for automatic tax calculation |
|