123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- //
- // IPAManager.m
- // MEISHI
- //
- // Created by CY on 2021/3/5.
- // Copyright © 2021 leo. All rights reserved.
- //
- #import "IPAManager.h"
- #import <StoreKit/StoreKit.h>
- @interface IPAManager ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>{
- NSString *_purchID;
- IAPCompletionHandle _handle;
- }
- @end
- @implementation IPAManager
- + (instancetype)shareIAPManager{
-
- static IPAManager *iapManager = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken,^{
- iapManager = [[IPAManager alloc] init];
- });
- return iapManager;
- }
- - (instancetype)init{
- self = [super init];
- if (self) {
- // 购买监听写在程序入口,程序挂起时移除监听,这样如果有未完成的订单将会自动执行并回调 paymentQueue:updatedTransactions:方法
- [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- }
- return self;
- }
-
- - (void)dealloc{
- [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
- }
-
-
- - (void)startPurchWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle{
- if (purchID) {
- if ([SKPaymentQueue canMakePayments]) {
- // 开始购买服务
- _purchID = purchID;
- _handle = handle;
- NSSet *nsset = [NSSet setWithArray:@[purchID]];
- SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
- request.delegate = self;
- [request start];
- }else{
- [self handleActionWithType:IAPPurchNotArrow data:nil];
- }
- }
- }
- - (void)handleActionWithType:(IAPPurchType)type data:(NSString *)data{
- #if DEBUG
- switch (type) {
- case IAPPurchSuccess:
- NSLog(@"购买成功");
- break;
- case IAPPurchFailed:
- NSLog(@"购买失败");
- break;
- case IAPPurchCancle:
- NSLog(@"用户取消购买");
- break;
- case IAPPurchVerFailed:
- NSLog(@"订单校验失败");
- break;
- case IAPPurchVerSuccess:
- NSLog(@"订单校验成功");
- break;
- case IAPPurchNotArrow:
- NSLog(@"不允许程序内付费");
- break;
- default:
- break;
- }
- #endif
- if(_handle){
- _handle(type,data);
- }
- }
- #pragma mark - 🍐delegate
- // 交易结束
- - (void)completeTransaction:(SKPaymentTransaction *)transaction{
- // // Your application should implement these two methods.
- // NSString * productIdentifier = transaction.payment.productIdentifier;
- // NSString * receipt = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
- // if ([productIdentifier length] > 0) {
- // // 向自己的服务器验证购买凭证
- // }
- //
- [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
- }
-
- // 交易失败
- - (void)failedTransaction:(SKPaymentTransaction *)transaction{
- if (transaction.error.code != SKErrorPaymentCancelled) {
- [self handleActionWithType:IAPPurchFailed data:nil];
- }else{
- [self handleActionWithType:IAPPurchCancle data:nil];
- }
-
- [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- }
-
- - (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag{
- //交易验证
- NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
- NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
-
- if(!receipt){
- // 交易凭证为空验证失败
- [self handleActionWithType:IAPPurchVerFailed data:nil];
- return;
- }
- // 购买成功将交易凭证发送给服务端进行再次校验
- [self handleActionWithType:IAPPurchSuccess data:[receipt base64EncodedStringWithOptions:0]];
-
- // NSError *error;
- // NSDictionary *requestContents = @{
- // @"receipt-data": [receipt base64EncodedStringWithOptions:0]
- // };
- // NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
- // options:0
- // error:&error];
- //
- // if (!requestData) { // 交易凭证为空验证失败
- // [self handleActionWithType:IAPPurchVerFailed data:nil];
- // return;
- // }
- //
- // //In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
- // //In the real environment, use https://buy.itunes.apple.com/verifyReceipt
- //
- // NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";
- // if (flag) {
- // serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";
- // }
- // NSURL *storeURL = [NSURL URLWithString:serverString];
- // NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
- // [storeRequest setHTTPMethod:@"POST"];
- // [storeRequest setHTTPBody:requestData];
- //
- // NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- // [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
- // completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- // if (connectionError) {
- // // 无法连接服务器,购买校验失败
- // [self handleActionWithType:IAPPurchVerFailed data:nil];
- // } else {
- // NSError *error;
- // NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
- // if (!jsonResponse) {
- // // 苹果服务器校验数据返回为空校验失败
- // [self handleActionWithType:IAPPurchVerFailed data:nil];
- // }
- //
- // // 先验证正式服务器,如果正式服务器返回21007再去苹果测试服务器验证,沙盒测试环境苹果用的是测试服务器
- // NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
- // if (status && [status isEqualToString:@"21007"]) {
- // [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
- // }else if(status && [status isEqualToString:@"0"]){
- // [self handleActionWithType:IAPPurchVerSuccess data:nil];
- // }
- //#if DEBUG
- // NSLog(@"----验证结果 %@",jsonResponse);
- //#endif
- // }
- // }];
-
-
- // 验证成功与否都注销交易,否则会出现虚假凭证信息一直验证不通过,每次进程序都得输入苹果账号
- [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- }
-
- #pragma mark - SKProductsRequestDelegate
- - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
- NSArray *product = response.products;
- if([product count] <= 0){
- #if DEBUG
- NSLog(@"--------------没有商品------------------");
- #endif
- return;
- }
-
- SKProduct *p = nil;
- for(SKProduct *pro in product){
- if([pro.productIdentifier isEqualToString:_purchID]){
- p = pro;
- break;
- }
- }
-
- #if DEBUG
- NSLog(@"productID:%@", response.invalidProductIdentifiers);
- NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);
- NSLog(@"%@",[p description]);
- NSLog(@"%@",[p localizedTitle]);
- NSLog(@"%@",[p localizedDescription]);
- NSLog(@"%@",[p price]);
- NSLog(@"%@",[p productIdentifier]);
- NSLog(@"发送购买请求");
- #endif
-
- SKPayment *payment = [SKPayment paymentWithProduct:p];
- [[SKPaymentQueue defaultQueue] addPayment:payment];
- }
-
- //请求失败
- - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
- #if DEBUG
- NSLog(@"------------------错误-----------------:%@", error);
- #endif
- }
-
- - (void)requestDidFinish:(SKRequest *)request{
- #if DEBUG
- NSLog(@"------------反馈信息结束-----------------");
- #endif
- }
-
- #pragma mark - SKPaymentTransactionObserver
- - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
- for (SKPaymentTransaction *tran in transactions) {
- switch (tran.transactionState) {
- case SKPaymentTransactionStatePurchased:
- [self completeTransaction:tran];
- break;
- case SKPaymentTransactionStatePurchasing:
- #if DEBUG
- NSLog(@"商品添加进列表");
- #endif
- break;
- case SKPaymentTransactionStateRestored:
- #if DEBUG
- NSLog(@"已经购买过商品");
- #endif
- // 消耗型不支持恢复购买
- [[SKPaymentQueue defaultQueue] finishTransaction:tran];
- break;
- case SKPaymentTransactionStateFailed:
- [self failedTransaction:tran];
- break;
- default:
- break;
- }
- }
- }
- @end
|