flutter - 有人可以帮助我使用 in_app_purchase 插件吗?
问题描述
再会!我正在尝试配置非消耗性产品。我应该何时以及为什么应该完成Purchase以及何时以及为什么应该消费Purchase?另外,我不能让它在两个平台上都能正常工作。
我正在使用带有以下环境的in_app_purchase: ^0.5.1+3插件:
[✓] Flutter (Channel stable, 2.0.4, on macOS 11.2.2 20D80 darwin-x64, locale en-BY)
[✓] Android 工具链 - 为 Android 设备开发(Android SDK 版本 30.0.2)
[✓] Xcode - 为 iOS 和 macOS 开发
[✓] Chrome - 为网络开发
[✓] Android Studio(4.1版)
[✓] VS 代码(版本 1.55.0)
[✓] 连接的设备(1 个可用)
如果有人可以帮助我编写代码,那就太好了。
import 'dart:async';
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase/store_kit_wrappers.dart';
const myProductId = 'remove_ads';
class PaymentProvider with ChangeNotifier {
final _iap = InAppPurchaseConnection.instance;
StreamSubscription<List<PurchaseDetails>> subscription;
bool isAvailable = false;
bool initialized = false;
bool _isPurchased = false;
bool get isPurchased => _isPurchased;
set isPurchased(bool value) {
_isPurchased = value;
notifyListeners();
}
bool _isPurchasePending = false;
bool get isPurchasePending => _isPurchasePending;
set isPurchasePending(bool value) {
_isPurchasePending = value;
notifyListeners();
}
List<ProductDetails> _products = [];
List<ProductDetails> get products => _products;
set products(List value) {
_products = value;
notifyListeners();
}
List<PurchaseDetails> _purchases = [];
List<PurchaseDetails> get purchases => _purchases;
set purchases(List value) {
_purchases = value;
notifyListeners();
}
Future<void> initialize() async {
isAvailable = await _iap.isAvailable();
if (isAvailable) {
await Future.wait([
_getProducts(),
_getPastPurchases(),
]);
await restorePurchase();
subscription = _iap.purchaseUpdatedStream.listen(
_listenToPurchaseUpdated,
onDone: () {
subscription?.cancel();
},
);
initialized = true;
notifyListeners();
}
}
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
purchaseDetailsList.forEach((purchaseDetails) async {
switch (purchaseDetails.status) {
case PurchaseStatus.pending:
isPurchasePending = true;
break;
case PurchaseStatus.error:
if (Platform.isIOS) await _iap.completePurchase(purchaseDetails);
isPurchasePending = false;
break;
case PurchaseStatus.purchased:
var valid = await _verifyPurchase(purchaseDetails);
if (valid) {
_deliverProduct(purchaseDetails);
} else {
_handleInvalidPurchase(purchaseDetails);
}
break;
default:
break;
}
});
}
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) async {
/// ???
return Future<bool>.value(true);
}
void _deliverProduct(PurchaseDetails purchaseDetails) async {
if (purchaseDetails.productID != myProductId) {
purchases.add(purchaseDetails);
}
if (purchaseDetails.pendingCompletePurchase) {
await _iap.completePurchase(purchaseDetails);
}
if (Platform.isAndroid) {
if (purchaseDetails.productID == myProductId) {
await _iap.consumePurchase(purchaseDetails);
}
}
isPurchased = true;
isPurchasePending = false;
}
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
/// ???
}
Future<void> restorePurchase() async {
// if (Platform.isIOS) {
// await SKPaymentQueueWrapper().restoreTransactions();
// }
var purchase = hasPurchased(myProductId);
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
await _iap.completePurchase(purchase);
isPurchased = true;
}
}
PurchaseDetails hasPurchased(String productId) {
return purchases.firstWhereOrNull((_) => _.productID == productId);
}
Future<void> purchaseRemoveAds(ProductDetails product) async {
if (Platform.isIOS) {
var transactions = await SKPaymentQueueWrapper().transactions();
await Future.forEach(transactions, (transaction) async {
await SKPaymentQueueWrapper().finishTransaction(transaction);
});
}
var purchaseParam = PurchaseParam(
productDetails: product,
);
await _iap.buyNonConsumable(purchaseParam: purchaseParam);
}
Future<void> _getProducts() async {
var response = await _iap.queryProductDetails({myProductId});
products = response.productDetails;
}
Future<void> _getPastPurchases() async {
var purchaseResponse = await _iap.queryPastPurchases();
if (purchaseResponse.error != null) {
// handle query past purchase error..
}
for (var purchase in purchaseResponse.pastPurchases) {
if (purchase.pendingCompletePurchase) {
await _iap.completePurchase(purchase);
}
if (Platform.isAndroid && purchase.status == PurchaseStatus.purchased) {
await _iap.consumePurchase(purchase);
}
}
purchases = purchaseResponse.pastPurchases;
}
}
解决方案
推荐阅读
- c# - CefSharp Executescriptasync 返回循环值
- numpy - Numpy,如何检索数组的子数组(特定索引)?
- firebase - 哪个 url 发送 oauth2 访问令牌请求?
- javascript - 如何在 Rmarkdown 中拥有像 Toc2 一样的“可伸缩”目录(在 jupyter 笔记本中)
- python - 类型错误:删除()缺少 1 个必需的位置参数:'indexPosition'
- windows - 如何在本地模拟 Travis CI 窗口构建?
- powershell - 正确编写 Powershell 逻辑表达式?
- javascript - fetch API 可以获取文件的文本吗?
- graphql - 在 DGraph 中定义一个 GraphQL 突变,在另一个节点中添加一个联合类型的节点
- docker - Keycloak Docker 部署