IAPManager.m 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #import "IAPManager.h"
  2. #import <StoreKit/StoreKit.h>
  3. @interface IAPManager ()<SKProductsRequestDelegate, SKPaymentTransactionObserver>
  4. @property (nonatomic, strong) NSArray<SKProduct *> *products;
  5. @property (nonatomic, strong) NetHttpsManager *httpsManager;
  6. @property (nonatomic, copy) IAPCompletionBlock completionBlock;
  7. @end
  8. @implementation IAPManager
  9. + (instancetype)sharedManager {
  10. static IAPManager *manager;
  11. static dispatch_once_t onceToken;
  12. dispatch_once(&onceToken, ^{
  13. manager = [[self alloc] init];
  14. [[SKPaymentQueue defaultQueue] addTransactionObserver:manager];
  15. });
  16. return manager;
  17. }
  18. #pragma mark - 获取商品信息
  19. - (void)fetchProducts:(NSArray<NSString *> *)productIds {
  20. NSSet *productIDs = [NSSet setWithArray:productIds];
  21. SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIDs];
  22. request.delegate = self;
  23. [request start];
  24. NSLog(@"fetchProducts: %@",productIDs);
  25. }
  26. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
  27. self.products = response.products;
  28. SKProduct *p = response.products.firstObject;
  29. NSLog(@"商品: %@, 价格: %@", p.localizedTitle, p.price);
  30. if (!p) {
  31. [[BGHUDHelper sharedInstance] tipMessage:ASLocalizedString(@"无法获取产品信息,购买失败。")];
  32. [SVProgressHUD dismiss];
  33. if (self.completionBlock) self.completionBlock(NO, 0, nil);
  34. return;
  35. }
  36. SKPayment *payment = [SKPayment paymentWithProduct:p];
  37. [[SKPaymentQueue defaultQueue] addPayment:payment];
  38. }
  39. #pragma mark - 购买
  40. - (void)buyProduct:(NSString *)productId completion:(IAPCompletionBlock)completion {
  41. _completionBlock = completion;
  42. if ([SKPaymentQueue canMakePayments]) {
  43. [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeClear];
  44. [SVProgressHUD showWithStatus:ASLocalizedString(@"正在提交iTunes Store,请等待...")];
  45. [self fetchProducts:@[productId]];
  46. } else {
  47. [FanweMessage alert:ASLocalizedString(@"您已禁止应用内付费购买商品")];
  48. }
  49. }
  50. #pragma mark - 交易回调
  51. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
  52. for (SKPaymentTransaction *transaction in transactions)
  53. {
  54. switch (transaction.transactionState)
  55. {
  56. case SKPaymentTransactionStatePurchased://交易完成
  57. NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier);
  58. [self completeTransaction:transaction];
  59. break;
  60. case SKPaymentTransactionStateFailed://交易失败
  61. NSLog(@"%@", ASLocalizedString(@"交易失败"));
  62. [self failedTransaction:transaction];
  63. break;
  64. case SKPaymentTransactionStateRestored://恢复已购买商品
  65. NSLog(@"%@", ASLocalizedString(@"恢复已购买商品"));
  66. [self restoreTransaction:transaction];
  67. [queue finishTransaction:transaction];
  68. break;
  69. case SKPaymentTransactionStatePurchasing:
  70. break;
  71. case SKPaymentTransactionStateDeferred:
  72. break;
  73. }
  74. }
  75. }
  76. #pragma mark - 掉单检查
  77. - (void)checkUnfinishedTransactions {
  78. NSArray *transactions = [SKPaymentQueue defaultQueue].transactions;
  79. for (SKPaymentTransaction *transaction in transactions) {
  80. if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
  81. [self completeTransaction:transaction]; // 再次验证并发货
  82. }
  83. }
  84. }
  85. - (void)completeTransaction:(SKPaymentTransaction *)transaction
  86. {
  87. NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
  88. NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
  89. NSString *receiptString = [receiptData base64EncodedStringWithOptions:0];
  90. if ([receiptString length] > 0) {
  91. // 保存本地(掉单恢复使用)
  92. [[NSUserDefaults standardUserDefaults] setObject:receiptString forKey:@"lastReceipt"];
  93. [[NSUserDefaults standardUserDefaults] synchronize];
  94. // 向自己的服务器验证购买凭证
  95. [self shoppingTransaction:transaction receiptString:receiptString retryCount:3];
  96. } else {
  97. [SVProgressHUD dismiss];
  98. [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  99. if (self.completionBlock) self.completionBlock(NO, 0, nil);
  100. }
  101. }
  102. #pragma mark -- 向自己的服务器验证购买凭证
  103. - (void)shoppingTransaction:(SKPaymentTransaction *)transaction receiptString:(NSString *)receiptString retryCount:(NSInteger)retryCount
  104. {
  105. retryCount--;
  106. if (retryCount <= 0) {
  107. [SVProgressHUD dismiss];
  108. [FanweMessage alert:ASLocalizedString(@"支付失败")];
  109. return;
  110. }
  111. NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0];
  112. // if (_is_vip)
  113. // {
  114. // [dict setObject:@"vip_pay" forKey:@"ctl"];
  115. // }
  116. // else
  117. // {
  118. [dict setObject:@"pay" forKey:@"ctl"];
  119. // }
  120. [dict setObject:@"iappay" forKey:@"act"];
  121. NSString *userid = [IMAPlatform sharedInstance].host.imUserId;
  122. [dict setObject:userid forKey:@"user_id"];
  123. [dict setObject:receiptString forKey:@"receipt-data"];
  124. [self.httpsManager POSTWithParameters:dict SuccessBlock:^(NSDictionary *responseJson) {
  125. [SVProgressHUD dismiss];
  126. NSInteger diamonds = [[responseJson objectForKey:@"total_diamonds"] integerValue];
  127. if (self.completionBlock) self.completionBlock(YES, diamonds, nil);
  128. [FanweMessage alert:ASLocalizedString(@"充值成功")];
  129. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  130. [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"lastReceipt"];
  131. } FailureBlock:^(NSError *error) {
  132. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  133. [self shoppingTransaction:transaction receiptString:receiptString retryCount:retryCount];
  134. });
  135. }];
  136. }
  137. - (void)failedTransaction:(SKPaymentTransaction *)transaction
  138. {
  139. [SVProgressHUD dismiss];
  140. if(transaction.error.code == SKErrorPaymentCancelled)
  141. {
  142. [FanweMessage alert:ASLocalizedString(@"您已经取消交易")];
  143. }
  144. else
  145. {
  146. [FanweMessage alert:ASLocalizedString(@"购买失败")];
  147. }
  148. [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  149. if (self.completionBlock) self.completionBlock(NO, 0, nil);
  150. }
  151. - (void)restoreTransaction:(SKPaymentTransaction *)transaction
  152. {
  153. // 对于已购商品,处理恢复购买的逻辑
  154. //[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  155. [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
  156. }
  157. #pragma mark - 恢复购买
  158. - (void)handleRestore:(SKPaymentTransaction *)transaction {
  159. NSLog(@"恢复购买: %@", transaction.payment.productIdentifier);
  160. }
  161. - (void)restorePurchases {
  162. [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
  163. }
  164. - (NetHttpsManager *)httpsManager
  165. {
  166. if (!_httpsManager)
  167. {
  168. _httpsManager = [NetHttpsManager manager];
  169. }
  170. return _httpsManager;
  171. }
  172. @end