IPAManager.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. //
  2. // IPAManager.m
  3. // MEISHI
  4. //
  5. // Created by CY on 2021/3/5.
  6. // Copyright © 2021 leo. All rights reserved.
  7. //
  8. #import "IPAManager.h"
  9. #import <StoreKit/StoreKit.h>
  10. @interface IPAManager ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>{
  11. NSString *_purchID;
  12. IAPCompletionHandle _handle;
  13. }
  14. @end
  15. @implementation IPAManager
  16. + (instancetype)shareIAPManager{
  17. static IPAManager *iapManager = nil;
  18. static dispatch_once_t onceToken;
  19. dispatch_once(&onceToken,^{
  20. iapManager = [[IPAManager alloc] init];
  21. });
  22. return iapManager;
  23. }
  24. - (instancetype)init{
  25. self = [super init];
  26. if (self) {
  27. // 购买监听写在程序入口,程序挂起时移除监听,这样如果有未完成的订单将会自动执行并回调 paymentQueue:updatedTransactions:方法
  28. [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  29. }
  30. return self;
  31. }
  32. - (void)dealloc{
  33. [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
  34. }
  35. - (void)startPurchWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle{
  36. if (purchID) {
  37. if ([SKPaymentQueue canMakePayments]) {
  38. // 开始购买服务
  39. _purchID = purchID;
  40. _handle = handle;
  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];
  47. }
  48. }
  49. }
  50. - (void)handleActionWithType:(IAPPurchType)type data:(NSString *)data{
  51. #if DEBUG
  52. switch (type) {
  53. case IAPPurchSuccess:
  54. NSLog(@"购买成功");
  55. break;
  56. case IAPPurchFailed:
  57. NSLog(@"购买失败");
  58. break;
  59. case IAPPurchCancle:
  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(_handle){
  76. _handle(type,data);
  77. }
  78. }
  79. #pragma mark - 🍐delegate
  80. // 交易结束
  81. - (void)completeTransaction:(SKPaymentTransaction *)transaction{
  82. // // Your application should implement these two methods.
  83. // NSString * productIdentifier = transaction.payment.productIdentifier;
  84. // NSString * receipt = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
  85. // if ([productIdentifier length] > 0) {
  86. // // 向自己的服务器验证购买凭证
  87. // }
  88. //
  89. [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
  90. }
  91. // 交易失败
  92. - (void)failedTransaction:(SKPaymentTransaction *)transaction{
  93. if (transaction.error.code != SKErrorPaymentCancelled) {
  94. [self handleActionWithType:IAPPurchFailed data:nil];
  95. }else{
  96. [self handleActionWithType:IAPPurchCancle data:nil];
  97. }
  98. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  99. }
  100. - (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag{
  101. //交易验证
  102. NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
  103. NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
  104. if(!receipt){
  105. // 交易凭证为空验证失败
  106. [self handleActionWithType:IAPPurchVerFailed data:nil];
  107. return;
  108. }
  109. // 购买成功将交易凭证发送给服务端进行再次校验
  110. [self handleActionWithType:IAPPurchSuccess data:[receipt base64EncodedStringWithOptions:0]];
  111. // NSError *error;
  112. // NSDictionary *requestContents = @{
  113. // @"receipt-data": [receipt base64EncodedStringWithOptions:0]
  114. // };
  115. // NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
  116. // options:0
  117. // error:&error];
  118. //
  119. // if (!requestData) { // 交易凭证为空验证失败
  120. // [self handleActionWithType:IAPPurchVerFailed data:nil];
  121. // return;
  122. // }
  123. //
  124. // //In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
  125. // //In the real environment, use https://buy.itunes.apple.com/verifyReceipt
  126. //
  127. // NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";
  128. // if (flag) {
  129. // serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";
  130. // }
  131. // NSURL *storeURL = [NSURL URLWithString:serverString];
  132. // NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
  133. // [storeRequest setHTTPMethod:@"POST"];
  134. // [storeRequest setHTTPBody:requestData];
  135. //
  136. // NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  137. // [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
  138. // completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
  139. // if (connectionError) {
  140. // // 无法连接服务器,购买校验失败
  141. // [self handleActionWithType:IAPPurchVerFailed data:nil];
  142. // } else {
  143. // NSError *error;
  144. // NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  145. // if (!jsonResponse) {
  146. // // 苹果服务器校验数据返回为空校验失败
  147. // [self handleActionWithType:IAPPurchVerFailed data:nil];
  148. // }
  149. //
  150. // // 先验证正式服务器,如果正式服务器返回21007再去苹果测试服务器验证,沙盒测试环境苹果用的是测试服务器
  151. // NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
  152. // if (status && [status isEqualToString:@"21007"]) {
  153. // [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
  154. // }else if(status && [status isEqualToString:@"0"]){
  155. // [self handleActionWithType:IAPPurchVerSuccess data:nil];
  156. // }
  157. //#if DEBUG
  158. // NSLog(@"----验证结果 %@",jsonResponse);
  159. //#endif
  160. // }
  161. // }];
  162. // 验证成功与否都注销交易,否则会出现虚假凭证信息一直验证不通过,每次进程序都得输入苹果账号
  163. [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
  164. }
  165. #pragma mark - SKProductsRequestDelegate
  166. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
  167. NSArray *product = response.products;
  168. if([product count] <= 0){
  169. #if DEBUG
  170. NSLog(@"--------------没有商品------------------");
  171. #endif
  172. return;
  173. }
  174. SKProduct *p = nil;
  175. for(SKProduct *pro in product){
  176. if([pro.productIdentifier isEqualToString:_purchID]){
  177. p = pro;
  178. break;
  179. }
  180. }
  181. #if DEBUG
  182. NSLog(@"productID:%@", response.invalidProductIdentifiers);
  183. NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);
  184. NSLog(@"%@",[p description]);
  185. NSLog(@"%@",[p localizedTitle]);
  186. NSLog(@"%@",[p localizedDescription]);
  187. NSLog(@"%@",[p price]);
  188. NSLog(@"%@",[p productIdentifier]);
  189. NSLog(@"发送购买请求");
  190. #endif
  191. SKPayment *payment = [SKPayment paymentWithProduct:p];
  192. [[SKPaymentQueue defaultQueue] addPayment:payment];
  193. }
  194. //请求失败
  195. - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
  196. #if DEBUG
  197. NSLog(@"------------------错误-----------------:%@", error);
  198. #endif
  199. }
  200. - (void)requestDidFinish:(SKRequest *)request{
  201. #if DEBUG
  202. NSLog(@"------------反馈信息结束-----------------");
  203. #endif
  204. }
  205. #pragma mark - SKPaymentTransactionObserver
  206. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
  207. for (SKPaymentTransaction *tran in transactions) {
  208. switch (tran.transactionState) {
  209. case SKPaymentTransactionStatePurchased:
  210. [self completeTransaction:tran];
  211. break;
  212. case SKPaymentTransactionStatePurchasing:
  213. #if DEBUG
  214. NSLog(@"商品添加进列表");
  215. #endif
  216. break;
  217. case SKPaymentTransactionStateRestored:
  218. #if DEBUG
  219. NSLog(@"已经购买过商品");
  220. #endif
  221. // 消耗型不支持恢复购买
  222. [[SKPaymentQueue defaultQueue] finishTransaction:tran];
  223. break;
  224. case SKPaymentTransactionStateFailed:
  225. [self failedTransaction:tran];
  226. break;
  227. default:
  228. break;
  229. }
  230. }
  231. }
  232. @end