Flutter中如何验证In App Purchase的订阅支付状态?
Solution for Subscription Status Tracking & Validation with in_app_purchase 3.0.8
Core Issue Breakdown
The buyConsumable/buyNonConsumable methods only return a boolean to confirm if the purchase flow was initiated successfully. All critical purchase status updates (authorized, denied, failed, pending) are delivered via the purchaseStream. You must listen to this stream to track and validate subscription completions.
Step 1: Implement Purchase Stream Listener
Add this logic early in your app (e.g., in the initState of your subscription screen) to capture real-time purchase events:
late StreamSubscription<List<PurchaseDetails>> _purchaseSubscription; @override void initState() { super.initState(); _setupPurchaseStream(); } void _setupPurchaseStream() { final purchaseStream = InAppPurchase.instance.purchaseStream; _purchaseSubscription = purchaseStream.listen( _handlePurchaseUpdates, onError: (error) => _handlePurchaseError(error as IAPError), onDone: () => _purchaseSubscription.cancel(), ); } void _handlePurchaseUpdates(List<PurchaseDetails> purchases) { for (final purchase in purchases) { switch (purchase.status) { case PurchaseStatus.pending: // Show loading state for pending purchases break; case PurchaseStatus.error: _handlePurchaseError(purchase.error!); break; case PurchaseStatus.purchased: case PurchaseStatus.restored: // Validate purchase (client + server-side) _validateSubscription(purchase); // Complete the purchase for non-consumables/subscriptions if (purchase.pendingCompletePurchase) { InAppPurchase.instance.completePurchase(purchase); } break; default: break; } } } void _handlePurchaseError(IAPError error) { String errorMessage; switch (error.code) { case IAPErrorCode.canceled: errorMessage = "Purchase canceled"; break; case IAPErrorCode.paymentInvalid: errorMessage = "Invalid payment method"; break; default: errorMessage = "Purchase failed: ${error.message}"; } // Display error to user (e.g., SnackBar, AlertDialog) } Future<void> _validateSubscription(PurchaseDetails purchase) { // 1. Basic client-side check (not secure alone) if (purchase.productID == "your_subscription_sku") { // Update local UI state temporarily } // 2. Mandatory server-side validation (secure) return _sendPurchaseToBackend(purchase); } Future<void> _sendPurchaseToBackend(PurchaseDetails purchase) { // Send verification data to your backend for validation with Apple/Google // Example: // await http.post( // Uri.parse("https://your-backend.com/verify-subscription"), // body: { // "token": purchase.verificationData.serverVerificationData, // "product_id": purchase.productID, // "user_id": currentUser.id, // }, // ); // Handle backend response to confirm valid subscription } @override void dispose() { _purchaseSubscription.cancel(); super.dispose(); }
Step 2: iOS Configuration
- App Store Connect Setup:
- Navigate to your app → Features → In-App Purchases.
- Create subscription products and ensure they are marked "Ready to Submit" or "Approved".
- Xcode Capabilities:
- Open your project in Xcode → Target → Signing & Capabilities → Add Capability → Enable In-App Purchase.
- Sandbox Testing:
- Create sandbox tester accounts in App Store Connect → Users and Access → Sandbox Testers.
- Sign out of the App Store on your test device, then use the sandbox account when prompted during purchase.
- Restore Purchases:
- Add a "Restore Purchases" button that calls
InAppPurchase.instance.restorePurchases(); restored subscriptions will appear in thepurchaseStream.
- Add a "Restore Purchases" button that calls
Step 3: Android Configuration
- Google Play Console Setup:
- Go to your app → Monetization → Products → Subscriptions.
- Create and activate your subscription products.
- Manifest Permission:
- Add this line to
android/app/src/main/AndroidManifest.xml:<uses-permission android:name="com.android.vending.BILLING" />
- Add this line to
- Test with Internal App Sharing:
- Upload your app to Google Play Console via Internal App Sharing.
- Use a license testing account (added in Play Console → Settings → Account details → License testing) to test purchases.
- Restore Purchases:
- Implement a "Restore Purchases" button that calls
InAppPurchase.instance.restorePurchases()to retrieve past subscriptions.
- Implement a "Restore Purchases" button that calls
Critical Security Notes
- Never trust client-side validation: Users can tamper with local data. Always validate purchase tokens via your backend using Apple's App Store API or Google's Play Developer API.
- Enable Server-to-Server Notifications:
- For iOS: Set up S2S notifications in App Store Connect to receive updates on subscription renewals, cancellations, or expirations.
- For Android: Enable Real-Time Developer Notifications in Google Play Console to track subscription status changes.
内容的提问来源于stack exchange,提问作者Felippe Negrão de Oliveira
相关产品推荐
相关产品推荐

