123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- //
- // KDIAPManager.m
- // KDChat
- //
- // Created by JYJ on 2019/6/14.
- // Copyright © 2019 dcjf. All rights reserved.
- //
- #import "KDIAPManager.h"
- #import <StoreKit/StoreKit.h>
- //#import "KDMainPresenter.h"
- #import "XSNetwork.h"
- #import "NSBundle+KODLocalizable.h"
- #import "KODCommonConst.h"
- @interface KDIAPManager() <SKPaymentTransactionObserver,SKProductsRequestDelegate> {
- IAPCompletionHandle _handle;
- }
- @property (nonatomic, strong) NSString* productId;
- @property (nonatomic, strong) NSString* orderId;
- /** presenter */
- //请求网络的.
- //@property (nonatomic, strong) KDMainPresenter *presenter;
- @end
- @implementation KDIAPManager
- /**
- 单例模式
-
- @return HZIAPManager
- */
- + (instancetype)shareIAPManager {
- static KDIAPManager *IAPManager = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- IAPManager = [[KDIAPManager alloc] init];
- });
- return IAPManager;
- }
- - (instancetype)init {
- if (self = [super init]) {
- [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- }
- return self;
- }
- - (void)dealloc {
- [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
- }
- #pragma mark -- Method
- /** 检测客户端与服务器漏单情况处理*/
- + (void)checkOrderStatus {
- NSDictionary *orderInfo = [KDIAPManager getReceiptData];
-
- if (orderInfo != nil) {
- NSString *orderId = orderInfo[@"orderId"];
- id receipt = orderInfo[@"receipt"];
- [[KDIAPManager shareIAPManager] verifyPurchaseForServiceWithOrderId:orderId receipt:receipt];
- }
- }
- #pragma mark -- 结束上次未完成的交易
- - (void)removeAllUncompleteTransactionsBeforeNewPurchase {
- NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
- if (transactions.count >= 1) {
- for (SKPaymentTransaction* transaction in transactions) {
- if (transaction.transactionState == SKPaymentTransactionStatePurchased ||
- transaction.transactionState == SKPaymentTransactionStateRestored) {
- [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
- }
- }
- } else {
- NSLog(@"没有历史未消耗订单");
- }
- }
- - (void)startIAPWithOrderId:(NSString *)orderId productID:(NSString *)productID completeHandle: (IAPCompletionHandle)handle {
- _handle = handle;
- if(productID && productID.length > 0) {
- if ([SKPaymentQueue canMakePayments]) {
- [self removeAllUncompleteTransactionsBeforeNewPurchase];
- self.orderId = orderId;
- // 允许内购
- self.productId = productID;
- NSSet *set = [NSSet setWithObjects:productID, nil];
- SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
- request.delegate = self;
- // 获取内购项目信息
- [request start];
- } else {
- // 不允许内购
- [self handleActionWithType:IAPResultNotArrow data:nil];
- }
- } else {
- NSLog(@"内购项目ID错误");
-
- //产品暂时不可用,请检查苹果后台
- NSString *str1 = [NSBundle KOD_localizedStringForKey:ProductNoUseCheckAppleDevelop];
- [XSNetwork errorWithCode:-3 message:str1];
- [self handleActionWithType:IAPResultIDError data:nil];
- }
-
- }
- - (void)handleActionWithType:(IAPResultType)type data:(NSData *)data{
- switch (type) {
- case IAPResultSuccess:
- NSLog(@"购买成功");
- break;
- case IAPResultFailed:
- NSLog(@"购买失败");
- break;
- case IAPResultCancle:
- NSLog(@"用户取消购买");
- break;
- case IAPResultVerFailed:
- NSLog(@"订单校验失败");
- break;
- case IAPResultVerSuccess:
- NSLog(@"订单校验成功");
- break;
- case IAPResultNotArrow:
- NSLog(@"不允许程序内付费");
- break;
- default:
- break;
- }
- if(_handle){
- _handle(type, data);
- }
- }
- #pragma mark -- SKProductsRequestDelegate
- /**
- 收到产品信息的回调
-
- @param request 请求的信息
- @param response 返回的产品信息
- */
- - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
-
- // 商品所在数组
- NSArray *productArr = response.products;
- if (productArr.count > 0) {
- // SKProduct *product = nil;
- for (SKProduct *product in productArr) {
- if ([product.productIdentifier isEqualToString:self.productId]) {
- // product = p;
- SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
- payment.quantity = 1;
- // payment.applicationUsername
-
- // payment.applicationUsername = _orderId;
- // 发起内购
- [[SKPaymentQueue defaultQueue] addPayment:payment];
- break;
- }
- }
- } else {
- [self handleActionWithType:IAPResultIDError data:nil];
- }
-
-
- // if ([response.invalidProductIdentifiers containsObject:self.productId]) {
- // self.callback(nil, [XSNetwork errorWithCode:-3 message:@"产品暂时不可用,请检查苹果后台"]);
- // return;
- // }
- //
- // for (SKProduct* product in response.products) {
- //
- // SKMutablePayment* payment = [SKMutablePayment paymentWithProduct:product];;
- // payment.applicationUsername = self.orderId;
- // [SKPaymentQueue.defaultQueue addPayment:payment];
- // }
-
-
- }
- #pragma mark -- SKPaymentTransactionObserver
- - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
- // 获取结果
- // 验证成功与否都注销交易,否则会出现虚假凭证信息一直验证不通过,每次进程序都得输入苹果账号
- for (SKPaymentTransaction *trans in transactions) {
- switch (trans.transactionState) {
- case SKPaymentTransactionStatePurchasing:
- NSLog(@"商品添加进列表");
- break;
- case SKPaymentTransactionStatePurchased:
- NSLog(@"交易完成");
- [self completeTransaction:trans];
- [[SKPaymentQueue defaultQueue] finishTransaction:trans];
- break;
- case SKPaymentTransactionStateFailed:
- NSLog(@"交易失败");
- [self failedTransaction:trans];
- [[SKPaymentQueue defaultQueue] finishTransaction:trans];
- break;
- case SKPaymentTransactionStateRestored:
- NSLog(@"已经购买过商品");
- [[SKPaymentQueue defaultQueue] finishTransaction:trans]; //消耗型商品不用写
- break;
- case SKPaymentTransactionStateDeferred:
-
- break;
- default:
- break;
- }
- }
- }
- /**
- 内购完成
-
- @param transaction 内购项目体
- */
- - (void)completeTransaction:(SKPaymentTransaction *)transaction {
- NSString *productIdentifier = transaction.payment.productIdentifier;
- NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
- NSData *data = [NSData dataWithContentsOfURL:recepitURL];
- id receiptString = [data base64EncodedStringWithOptions:0];
-
- if ([productIdentifier length] > 0 && data) {
-
- if (receiptString && self.orderId.length > 0) {
- //1.保存订单号和报文到本地.
- [self saveReceiptData:@{@"receipt":receiptString,
- @"orderId":self.orderId ?:@""}];
-
- //2.向自己的服务器验证购买凭证.
- [self verifyPurchaseForServiceWithOrderId:self.orderId
- receipt:receiptString];
- }
-
- } else {
- [self handleActionWithType:IAPResultVerFailed data:nil];
- }
-
-
- // // 自己向苹果发送验证
- // [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
- }
- ///服务器验证购买凭证.
- - (void)verifyPurchaseForServiceWithOrderId:(NSString *)orderId
- receipt:(id)receiptString {
- if (orderId == nil && !receiptString) {
- [self handleActionWithType:IAPResultIDError data:nil];
- return;
- }
-
-
- [XSNetwork payWithReceipt:receiptString orderId:orderId complete:^(id object, NSError *error) {
-
- //TTOO:网络异常,服务器校验receiptString失败,就会出现掉单问题.需要保存订单号到本地,下次启动app,继续校验服务器.
-
- if (error != nil) {
- //订单校验失败.
- [self handleActionWithType:IAPResultVerFailed data:nil];
- }else{
-
- //订单校验成功,删除本地保存的订单号和苹果返回的data凭证.
- [self handleActionWithType:IAPResultSuccess data:nil];
- [self removeLocReceiptData];
- }
- }];
- }
- /**
- 交易失败
-
- @param transaction 内购项目体
- */
- - (void)failedTransaction:(SKPaymentTransaction *)transaction {
- if (transaction.error.code != SKErrorPaymentCancelled) {
- [self handleActionWithType:IAPResultFailed data:nil];
- } else {
- [self handleActionWithType:IAPResultCancle data:nil];
- }
- }
- #pragma mark -- 本地保存一次支付凭证
- static NSString *const kSaveReceiptData = @"kSaveReceiptData";
- - (void)saveReceiptData:(NSDictionary *)receiptData {
- [[NSUserDefaults standardUserDefaults] setValue:receiptData forKey:kSaveReceiptData];
- [[NSUserDefaults standardUserDefaults]synchronize];
- }
- + (NSDictionary *)getReceiptData {
- return [[NSUserDefaults standardUserDefaults] valueForKey:kSaveReceiptData];
- }
- - (void)removeLocReceiptData {
- [[NSUserDefaults standardUserDefaults] removeObjectForKey:kSaveReceiptData];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- /**
- - (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag {
- //交易验证
- NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
- NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
-
- NSError *error;
- NSDictionary *requestContents = @{@"receipt-data": [receipt base64EncodedStringWithOptions:0]};
- NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error];
- if (!requestData) { // 交易凭证为空验证失败
- [self handleActionWithType:IAPResultVerFailed 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];
- storeRequest.timeoutInterval = 20;
- [storeRequest addValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
- NSURLSession *session = [NSURLSession sharedSession];
- NSURLSessionDataTask *task = [session dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
- if (error) {
- // 无法连接服务器,购买校验失败
- [self handleActionWithType:IAPResultVerFailed data:nil];
- } else {
- NSError *error;
- NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
- if (!jsonResponse) {
- // 苹果服务器校验数据返回为空校验失败
- [self handleActionWithType:IAPResultVerFailed 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:IAPResultVerSuccess data:nil];
- }
- }
- }];
- [task resume];
- }
-
- */
- //- (KDMainPresenter *)presenter {
- // if (!_presenter) {
- // self.presenter = [[KDMainPresenter alloc] init];
- // }
- // return _presenter;
- //}
- @end
|