已实现Xamarin.iOS应用订阅,如何检测用户取消订阅事件?
在Xamarin.iOS中监听订阅取消事件的实现方案
老哥,首先得明确一点:用户在App Store里直接取消订阅的操作不会触发你现有代码里的SKPaymentTransactionObserver回调——因为这种操作完全在App Store端完成,不会产生新的交易记录。所以我们得换两种思路来捕捉这个事件:
1. 定期主动检查订阅状态(最稳妥的基础方案)
因为取消订阅不会主动通知App,所以我们需要主动去查。通常可以在App启动时、用户进入订阅管理页面时,调用这个检查逻辑。结合你现有的BillingService和CustomPaymentObserver,可以这么改:
先完善你的CustomPaymentObserver实现
确保它能处理所有交易状态(比如购买、恢复、失败这些),代码如下:
internal class CustomPaymentObserver : SKPaymentTransactionObserver { public override void UpdatedTransactions(SKPaymentQueue queue, SKPaymentTransaction[] transactions) { foreach (var transaction in transactions) { switch (transaction.TransactionState) { case SKPaymentTransactionState.Purchased: CompleteTransaction(transaction); break; case SKPaymentTransactionState.Failed: FailedTransaction(transaction); break; case SKPaymentTransactionState.Restored: RestoreTransaction(transaction); break; case SKPaymentTransactionState.Deferred: // 处理延迟交易(比如需要家长审核的情况) break; case SKPaymentTransactionState.Purchasing: // 购买中,可显示加载状态 break; } } } // 复用你已有的交易处理方法 private void CompleteTransaction(SKPaymentTransaction t) { // 你的现有逻辑:保存订阅凭证、标记用户订阅状态等 SKPaymentQueue.DefaultQueue.FinishTransaction(t); } private void FailedTransaction(SKPaymentTransaction t) { // 你的现有失败处理逻辑 SKPaymentQueue.DefaultQueue.FinishTransaction(t); } private void RestoreTransaction(SKPaymentTransaction t) { // 你的现有恢复购买逻辑 SKPaymentQueue.DefaultQueue.FinishTransaction(t); } }
添加订阅状态检查方法
接下来在你的BillingService里加一个方法,用来获取并验证订阅的真实状态:
internal class BillingService : SKProductsRequestDelegate { private BillingService() { /* 你的现有构造逻辑 */ } // 新增:检查订阅状态的方法 public async Task VerifySubscriptionStatusAsync() { var receiptUrl = NSBundle.MainBundle.AppStoreReceiptUrl; // 如果本地没有凭证,触发恢复购买流程 if (!NSFileManager.DefaultManager.FileExists(receiptUrl.Path)) { SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions(); return; } // 把凭证转成Base64字符串,发给后端验证 var receiptData = NSData.FromUrl(receiptUrl); var receiptBase64 = receiptData.Base64EncodedString(NSDataBase64EncodingOptions.EndLineWithLineFeed); // 这里一定要用后端服务器去和App Store验证!本地验证容易被篡改,不安全 var httpClient = new HttpClient(); var requestBody = new StringContent( JsonConvert.SerializeObject(new { Receipt = receiptBase64 }), Encoding.UTF8, "application/json" ); try { var response = await httpClient.PostAsync("你的后端验证接口地址", requestBody); if (response.IsSuccessStatusCode) { var statusResponse = await response.Content.ReadAsStringAsync(); var subscriptionStatus = JsonConvert.DeserializeObject<SubscriptionStatus>(statusResponse); // 判断订阅是否被取消或过期 if (subscriptionStatus.IsCancelled || subscriptionStatus.ExpirationDate < DateTime.UtcNow) { // 触发取消后的逻辑:比如关闭付费功能、通知用户等 HandleSubscriptionCancelled(); } } } catch (Exception ex) { // 处理网络请求异常 Console.WriteLine($"验证订阅状态失败: {ex.Message}"); } } private void HandleSubscriptionCancelled() { // 这里写你订阅取消后的具体业务逻辑 // 比如更新UI、移除付费功能权限、弹出提示等 } // 你的现有方法:CompleteTransaction、FailedTransaction、RestoreTransaction... public void CompleteTransaction(SKPaymentTransaction t) { /* 你的逻辑 */ } public void FailedTransaction(SKPaymentTransaction t) { /* 你的逻辑 */ } public void RestoreTransaction(SKPaymentTransaction t) { /* 你的逻辑 */ } } // 用来接收后端返回的订阅状态模型 public class SubscriptionStatus { public bool IsCancelled { get; set; } public DateTime ExpirationDate { get; set; } // 可以加其他字段:比如订阅类型、自动续期状态等 }
2. 配置App Store Server Notifications(实时通知方案)
如果想要实时获取取消事件,可以用苹果的Server Notifications功能:当用户取消订阅、订阅过期、续期失败等状态变化时,App Store会主动向你的后端服务器发送HTTP通知。
然后你的后端可以通过推送通知(比如APNs)把状态变化告知App,这样就能实时处理取消事件了。这种方式需要后端配置接收通知的端点,并且处理苹果的签名验证,适合对实时性要求高的场景。
关键注意点
- 永远不要本地验证凭证:本地验证的receipt很容易被篡改,必须通过后端服务器调用苹果的验证接口来获取真实状态。
- 定期检查的频率:不用太频繁,比如App启动时查一次,用户进入订阅页面时查一次就够了,避免不必要的网络请求。
内容的提问来源于stack exchange,提问作者Nikola Pavlovic
相关产品推荐
相关产品推荐

