IAPManager.m 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //
  2. // IAPManager.m
  3. // jiaPei
  4. //
  5. // Created by 张嵘 on 2022/9/21.
  6. // Copyright © 2022 JCZ. All rights reserved.
  7. //
  8. #import "IAPManager.h"
  9. #import <Foundation/Foundation.h>
  10. #import <StoreKit/StoreKit.h>
  11. @interface IAPManager()<SKPaymentTransactionObserver,SKProductsRequestDelegate>{
  12. NSString *_currentPurchasedID;
  13. IAPCompletionHandle _iAPCompletionHandle;
  14. }
  15. @end
  16. @implementation IAPManager
  17. + (instancetype)shareIAPManager {
  18. static IAPManager *iAPManager = nil;
  19. static dispatch_once_t onceToken;
  20. dispatch_once(&onceToken,^{
  21. iAPManager = [[IAPManager alloc] init];
  22. });
  23. return iAPManager;
  24. }
  25. - (instancetype)init{
  26. self = [super init];
  27. if (self) {
  28. [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  29. }
  30. return self;
  31. }
  32. - (void)dealloc{
  33. [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
  34. }
  35. - (void)startPurchaseWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle{
  36. if (purchID) {
  37. if ([SKPaymentQueue canMakePayments]) {
  38. _currentPurchasedID = purchID;
  39. _iAPCompletionHandle = handle;
  40. //从App Store中检索关于指定产品列表的本地化信息
  41. NSSet *nsset = [NSSet setWithArray:@[purchID]];
  42. SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
  43. request.delegate = self;
  44. [request start];
  45. }else{
  46. [self handleActionWithType:IAPPurchNotArrow data:nil transactionIdentifier:nil isTest:NO];
  47. }
  48. }
  49. }
  50. - (void)handleActionWithType:(IAPPurchType)type data:(NSData *)data transactionIdentifier:(NSString *)transactionIdentifier isTest:(BOOL)isTest {
  51. #if DEBUG
  52. switch (type) {
  53. case IAPPurchSuccess:
  54. NSLog(@"购买成功");
  55. break;
  56. case IAPPurchFailed:
  57. NSLog(@"购买失败");
  58. break;
  59. case IAPPurchCancel:
  60. NSLog(@"用户取消购买");
  61. break;
  62. case IAPPurchVerFailed:
  63. NSLog(@"订单校验失败");
  64. break;
  65. case IAPPurchVerSuccess:
  66. NSLog(@"订单校验成功");
  67. break;
  68. case IAPPurchNotArrow:
  69. NSLog(@"不允许程序内付费");
  70. break;
  71. default:
  72. break;
  73. }
  74. #endif
  75. if(_iAPCompletionHandle){
  76. _iAPCompletionHandle(type,data,transactionIdentifier,isTest);
  77. }
  78. }
  79. - (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)isTestServer {
  80. //交易验证
  81. NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
  82. NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
  83. if(!receipt){
  84. // 交易凭证为空验证失败
  85. [self handleActionWithType:IAPPurchVerFailed data:nil transactionIdentifier:nil isTest:isTestServer];
  86. return;
  87. }
  88. // 购买成功将交易凭证发送给服务端进行再次校验
  89. [self handleActionWithType:IAPPurchSuccess data:receipt transactionIdentifier:transaction.transactionIdentifier isTest:isTestServer];
  90. NSError *error;
  91. NSDictionary *requestContents = @{
  92. @"receipt-data": [receipt base64EncodedStringWithOptions:0]
  93. };
  94. NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
  95. options:0
  96. error:&error];
  97. if (!requestData) { // 交易凭证为空验证失败
  98. [self handleActionWithType:IAPPurchVerFailed data:nil transactionIdentifier:nil isTest:isTestServer];
  99. return;
  100. }
  101. NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";
  102. if (isTestServer) {
  103. serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";
  104. }
  105. NSURL *storeURL = [NSURL URLWithString:serverString];
  106. NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
  107. [storeRequest setHTTPMethod:@"POST"];
  108. [storeRequest setHTTPBody:requestData];
  109. [[NSURLSession sharedSession] dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  110. if (error) {
  111. // 无法连接服务器,购买校验失败
  112. [self handleActionWithType:IAPPurchVerFailed data:nil transactionIdentifier:nil isTest:isTestServer];
  113. } else {
  114. NSError *error;
  115. NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  116. if (!jsonResponse) {
  117. // 服务器校验数据返回为空校验失败
  118. [self handleActionWithType:IAPPurchVerFailed data:nil transactionIdentifier:nil isTest:isTestServer];
  119. }
  120. NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
  121. if(status && [status isEqualToString:@"0"]){
  122. [self handleActionWithType:IAPPurchVerSuccess data:nil transactionIdentifier:nil isTest:isTestServer];
  123. } else if (status && [status isEqualToString:@"21007"]) {
  124. [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
  125. } else {
  126. [self handleActionWithType:IAPPurchVerFailed data:nil transactionIdentifier:nil isTest:isTestServer];
  127. }
  128. #if DEBUG
  129. NSLog(@"----验证结果 %@",jsonResponse);
  130. #endif
  131. }
  132. }];
  133. // 验证成功与否都注销交易,否则会出现虚假凭证信息一直验证不通过,每次进程序都得输入苹果账号
  134. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  135. }
  136. #pragma mark - SKProductsRequestDelegate
  137. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
  138. NSArray *product = response.products;
  139. if([product count] <= 0){
  140. #if DEBUG
  141. NSLog(@"--------------没有商品------------------");
  142. #endif
  143. return;
  144. }
  145. SKProduct *p = nil;
  146. for(SKProduct *pro in product){
  147. if([pro.productIdentifier isEqualToString:_currentPurchasedID]){
  148. p = pro;
  149. break;
  150. }
  151. }
  152. #if DEBUG
  153. NSLog(@"productID:%@", response.invalidProductIdentifiers);
  154. NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);
  155. NSLog(@"产品描述:%@",[p description]);
  156. NSLog(@"产品标题%@",[p localizedTitle]);
  157. NSLog(@"产品本地化描述%@",[p localizedDescription]);
  158. NSLog(@"产品价格:%@",[p price]);
  159. NSLog(@"产品productIdentifier:%@",[p productIdentifier]);
  160. #endif
  161. SKPayment *payment = [SKPayment paymentWithProduct:p];
  162. [[SKPaymentQueue defaultQueue] addPayment:payment];
  163. }
  164. //请求失败
  165. - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
  166. #if DEBUG
  167. NSLog(@"------------------从App Store中检索关于指定产品列表的本地化信息错误-----------------:%@", error);
  168. #endif
  169. }
  170. - (void)requestDidFinish:(SKRequest *)request{
  171. #if DEBUG
  172. NSLog(@"------------requestDidFinish-----------------");
  173. #endif
  174. }
  175. #pragma mark - SKPaymentTransactionObserver
  176. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
  177. for (SKPaymentTransaction *tran in transactions) {
  178. switch (tran.transactionState) {
  179. case SKPaymentTransactionStatePurchased:
  180. [self verifyPurchaseWithPaymentTransaction:tran isTestServer:NO];
  181. break;
  182. case SKPaymentTransactionStatePurchasing:
  183. #if DEBUG
  184. NSLog(@"商品添加进列表");
  185. #endif
  186. break;
  187. case SKPaymentTransactionStateRestored:
  188. #if DEBUG
  189. NSLog(@"已经购买过商品");
  190. #endif
  191. // 消耗型不支持恢复购买
  192. [[SKPaymentQueue defaultQueue] finishTransaction:tran];
  193. break;
  194. case SKPaymentTransactionStateFailed:
  195. [self failedTransaction:tran];
  196. break;
  197. default:
  198. break;
  199. }
  200. }
  201. }
  202. // 交易失败
  203. - (void)failedTransaction:(SKPaymentTransaction *)transaction{
  204. if (transaction.error.code != SKErrorPaymentCancelled) {
  205. [self handleActionWithType:IAPPurchFailed data:nil transactionIdentifier:nil isTest:NO];
  206. }else{
  207. [self handleActionWithType:IAPPurchCancel data:nil transactionIdentifier:nil isTest:NO];
  208. }
  209. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  210. }
  211. @end
  212. /* 调用支付方法
  213. - (void)purchaseWithProductID:(NSString *)productID{
  214. [[IAPManager shareIAPManager] startPurchaseWithID:productID completeHandle:^(IAPPurchType type,NSData *data) {
  215. }];
  216. }
  217. */