我正在尝试使用官方 Flutter In-App-Purchase 插件来实现应用内购买。我已经一切正常,但我不知道如何判断用户订阅是否仍然有效或是否已过期。即使我取消了测试订阅,连接并执行
queryPastPurchases()
后获得的值与订阅处于活动状态时相同:
productId: test_subscription_1
transactiondate: 1565682346568
status: null
verificationData
source: IAPSource.GooglePlay
localVerificationData: {
"orderId":"GPA.1234-1234-1234-12345",
"packageName":"com.example.myapp",
"productId":"test_subscription_1",
"purchaseTime":1565682346568,
"purchaseState":0,
"purchaseToken":"<long string>",
"autoRenewing":false
}
serverVerificationData: "<long string>"
我是否应该简单地对我的订阅期进行硬编码,并将当前时间与
purchaseTime
+ 订阅期进行比较?这甚至适用于自动续订吗?如果用户将手机上的日期更改为一年前怎么办?似乎应该有一些值应该给我过期时间或至少一个布尔值 true/false 来指示订阅是否仍然有效?
官方应用内购买插件处理进行购买,但不提供专门处理自动续订订阅所需的所有后端基础设施。
您的问题的简短答案是将此购买信息发送到您的服务器并在那里管理订阅状态。或者,您可以研究像
purchases_flutter
这样的托管解决方案:https://pub.dev/packages/purchases_flutter/
我使用了“purchases_flutter”,过程很简单。您可以通过调用插件自带的方法来检查订阅的状态。查看这篇文章,其中包含一个示例 https://medium.com/flutter-community/in-app-purchases-with-flutter-a-compressive-step-by-step-tutorial-b96065d79a21
对于仍然遇到问题的任何人,有一个简单的解决方案可以在 iOS 上验证收据
这是一个简单的 js 片段,您可以使用它从 Apple 获取实际收据并使用它来验证订阅
注意 您将需要使用苹果开发者帐户为应用程序生成应用程序特定密码
进一步帮助
https://developer.apple.com/documentation/appstorereceipts/expiration_intent
const axios = require('axios');
const iosValidateReceipt = async (transactionReceipt, isTest = true) =>
new Promise(async (resolve, reject) => {
const url = isTest ? 'https://sandbox.itunes.apple.com/verifyReceipt' : 'https://buy.itunes.apple.com/verifyReceipt';
const data = {
'receipt-data': transactionReceipt,
password: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
};
console.log('iosValidateReceipt - input - ', { url, data });
try {
const response = await axios.post(url, data);
console.log('iosValidateReceipt - success - ', JSON.stringify(response.data, null, 2));
resolve(response.data);
} catch (err) {
console.log('iosValidateReceipt - error -', err);
reject(err);
}
});
queryPastPurchases()
可能不再可用,但现在有 restorePurchases()
。
首先,您需要为购买设置侦听器:
late StreamSubscription<List<PurchaseDetails>> subscription;
subscription = InAppPurchase.instance.purchaseStream.listen((purchaseDetailsList) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
// handle pending
} else if (purchaseDetails.status == PurchaseStatus.error) {
// handle error
} else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) {
// handle new or past purchases
}
});
}, onDone: () {
subscription.cancel();
}, onError: (error) {
// handle error
});
之后调用
restorePurchases()
,刚刚创建的监听器将获得过去的购买状态PurchaseStatus.restored
// restore purchases to get past subscriptions
InAppPurchase.instance.restorePurchases();