123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- //
- // XYAppStorePayHelpler.m
- // Starbuds
- //
- // Created by 翟玉磊 on 2020/1/18.
- // Copyright © 2020 翟玉磊. All rights reserved.
- //
- #import "XYAppStorePayHelpler.h"
- #import <StoreKit/StoreKit.h>
- #define PayErrorCode 999 //支付默认操作code
- @interface XYAppStorePayHelpler ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
- /// 当前购买的商品id
- @property (nonatomic, readwrite, copy) NSString *itemId;
- @property (nonatomic, readwrite, copy) NSString *orderId;
- /// 支付成功的回调
- @property (nonatomic, readwrite, copy) PayHelplerSuccessBlock successHandler;
- /// 支付成功的回调
- @property (nonatomic, readwrite, copy) PayHelplerFailureBlock failureHandler;
- /// 当前选中的支付类型
- @property (nonatomic, readwrite, assign) NSInteger currentPayType;
- /// 当前的支付状态
- @property (nonatomic, readwrite, assign) NSInteger payStatus;
- @end
- @implementation XYAppStorePayHelpler
- - (void)dealloc {
- [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
- }
- - (instancetype)init {
- if (self = [super init]) {
- // 开启监听苹果支付
- [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- }
- return self;
- }
- - (void)initValue {
- self.currentPayType = 101;
- self.payStatus = PayErrorCode;
- self.orderId = nil;
- self.itemId = nil;
- }
- /// 回去订单支付信息和支付参数
- /// @param orderId 订单Id
- /// @param payType 支付方式 101苹果支付 201支付宝 301微信
- /// @param itemId 商品id
- /// @param successHandler 请求成功
- /// @param failureHandler 请求失败
- - (void)addPayOrderWithOrderId:(NSString *)orderId payType:(NSInteger)payType itemId:(NSString *)itemId successHandler:(nonnull PayHelplerSuccessBlock)successHandler failureHandler:(nonnull PayHelplerFailureBlock)failureHandler {
- // 重置默认信息
- [self initValue];
- if ([APP_Channel_Id isEqualToString:@"21"]) {
- // TimiAppStore
- self.itemId = [NSString stringWithFormat:@"TM_%@", itemId];
- }else if ([APP_Channel_Id isEqualToString:@"275963954855936"]) {
- // TmAppStore
- self.itemId = [NSString stringWithFormat:@"Tm_%@", itemId];
- }
- else {
- self.itemId = [itemId copy];
- }
- self.orderId = [orderId copy];
- self.currentPayType = payType;
- self.successHandler = successHandler;
- self.failureHandler = failureHandler;
-
- [self appStorePay];
- }
- /// 苹果支付
- - (void)appStorePay {
- // 判断app是否允许apple支付
- [MBProgressHUD showActivityMessage:kLocalizedString(@"请稍等...")];
- if ([SKPaymentQueue canMakePayments] && StringIsNotEmpty(self.itemId)) {
- // 这里的itemId就对应着苹果后台的商品ID,他们是通过这个ID进行联系的。
- NSArray *product = [[NSArray alloc] initWithObjects:self.itemId,nil];
- NSSet *nsset = [NSSet setWithArray:product];
- //SKProductsRequest参考链接:https://developer.apple.com/documentation/storekit/skproductsrequest
- //SKProductsRequest 一个对象,可以从App Store检索有关指定产品列表的本地化信息。
- SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];// 初始化请求
- request.delegate = self;
- [request start];// 开始请求
- }else {
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUD];
- !self.failureHandler?:self.failureHandler(PayErrorCode, @"不支持苹果支付", self.currentPayType);
- });
- }
- }
- #pragma mark ------ SKProductsRequestDelegate
- // 接收到产品的返回信息,然后用返回的商品信息进行发起购买请求
- - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
- NSArray *product = response.products;
-
- SKProduct *requestProduct = nil;
- for (SKProduct *pro in product) {
- // NSLog(@"%@", [pro description]);
- // NSLog(@"%@", [pro localizedTitle]);
- // NSLog(@"%@", [pro localizedDescription]);
- // NSLog(@"%@", [pro price]);
- // NSLog(@"%@", [pro productIdentifier]);
- // 如果后台消费条目的ID与我这里需要请求的一样(用于确保订单的正确性)
- if([pro.productIdentifier isEqualToString:self.itemId]){
- requestProduct = pro;
- break;
- }
- }
- if (requestProduct) {
- // 发送购买请求,创建票据 这个时候就会有弹框了
- SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
- //将票据加入到交易队列
- [[SKPaymentQueue defaultQueue] addPayment:payment];
- }else {
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUD];
- !self.failureHandler?:self.failureHandler(PayErrorCode, @"没有该项目", self.currentPayType);
- });
- }
- }
- #pragma mark ------ SKRequestDelegate (@protocol SKProductsRequestDelegate <SKRequestDelegate>)
- //请求失败
- - (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
- // NSLog(@"error:%@", error);
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUD];
- !self.failureHandler?:self.failureHandler(error.code, @"支付失败", self.currentPayType);
- });
- }
- //反馈请求的产品信息结束后
- - (void)requestDidFinish:(SKRequest *)request{
- // NSLog(@"信息反馈结束");
- }
- #pragma mark ------ SKPaymentTransactionObserver 监听购买结果
- // 13.监听购买结果
- - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction
- {
- for (SKPaymentTransaction *tran in transaction){
- // NSLog(@"%@",tran.payment.applicationUsername);
- switch (tran.transactionState) {
- case SKPaymentTransactionStatePurchasing:
- // NSLog(@"商品添加进列表");
- // dispatch_async(dispatch_get_main_queue(), ^{
- // [MBProgressHUD showActivityMessage:kLocalizedString(@"请稍等...")];
- // });
- break;
- case SKPaymentTransactionStatePurchased:{
- // NSLog(@"交易完成");
- // 购买后告诉交易队列,把这个成功的交易移除掉。
- //走到这就说明这单交易走完了,无论成功失败,所以要给它移出。finishTransaction
- // [MBProgressHUD showActivityMessage:kLocalizedString(@"请稍等...")];
- [self completeTransaction:tran];//这儿出了问题抛异常,导致下面一句代码没执行
- [[SKPaymentQueue defaultQueue] finishTransaction:tran];
- }
- break;
-
- case SKPaymentTransactionStateFailed:
- // NSLog(@"交易失败");
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUD];
- !self.failureHandler?:self.failureHandler(PayErrorCode, @"交易失败", self.currentPayType);
- [[SKPaymentQueue defaultQueue] finishTransaction:tran];
- });
- }
- break;
-
- case SKPaymentTransactionStateRestored:
- // NSLog(@"已经购买过商品");
- [self completeTransaction:tran];
- [[SKPaymentQueue defaultQueue] finishTransaction:tran];
- break;
- case SKPaymentTransactionStateDeferred:
- // NSLog(@"交易延迟");
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUD];
- [MBProgressHUD showActivityMessage:kLocalizedString(@"请稍等...")];
- });
- break;
- default:
- break;
- }
-
- }
- }
- #pragma mark 苹果支付完成
- - (void)completeTransaction:(SKPaymentTransaction *)transaction {
- //交易验证 本地验证方法
- /*NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
- NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
-
- if(!receipt){
-
- }
-
- NSError *error;
- NSDictionary *requestContents = @{
- @"receipt-data": [receipt base64EncodedStringWithOptions:0]
- };
- NSLog(@"requestContentstr:%@",[receipt base64EncodedStringWithOptions:0]);
- NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
- options:0
- error:&error];
-
-
- //In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
- //In the real environment, use https://buy.itunes.apple.com/verifyReceipt
- // Create a POST request with the receipt data.
- NSURL *storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
- NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
- [storeRequest setHTTPMethod:@"POST"];
- [storeRequest setHTTPBody:requestData];
-
- // Make a connection to the iTunes Store on a background queue.
- NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
- completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- if (connectionError) {
- } else {
- NSError *error;
- NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
- if (!jsonResponse) { }
- //Parse the Response
- NSLog(@"成功了:%@",jsonResponse);
- }
- }];*/
-
- //此时告诉后台交易成功,并把receipt传给后台验证
- // 验证凭据,获取到苹果返回的交易凭据 从沙盒中获取到购买凭据
- NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
- NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
- NSString *transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
-
- // 缓存苹果支付成功的数据
- NSDictionary *dict = @{@"orderId":self.orderId, @"transactionId":transaction.transactionIdentifier, @"receiptData":transactionReceiptString};
- [XYAppStorePayHelpler saveAppStoreCuccessData:dict];
-
-
- // 查询服务端支付状态
- [[XYPayAPIManager new] addPayOrderWithOrderId:self.orderId transactionId:transaction.transactionIdentifier receiptData:transactionReceiptString successHandler:^(ZYLResponseModel *responseModel) {
- [MBProgressHUD hideHUD];
- // 删除已经验证的支付信息
- [XYAppStorePayHelpler removeAppStoreCuccessData:self.orderId];
- !self.successHandler?:self.successHandler(self.currentPayType);
- } failureHandler:^(ZYLNetworkError *error) {
- [MBProgressHUD hideHUD];
- CustomActionAlertController *alert = [[CustomActionAlertController alloc] initWithTitle:@"提示" message:@"因为网络问题造成数据没有同步,是否刷新" sure:@"重新加载" cancel:@"取消" selctedBlock:^(NSInteger index, NSString * _Nonnull title) {
- if (index == 1) {
- // 查询服务端支付状态
- [[XYPayAPIManager new] addPayOrderWithOrderId:self.orderId transactionId:transaction.transactionIdentifier receiptData:transactionReceiptString successHandler:^(ZYLResponseModel *responseModel) {
- // 删除已经验证的支付信息
- [XYAppStorePayHelpler removeAppStoreCuccessData:self.orderId];
- !self.successHandler?:self.successHandler(self.currentPayType);
- } failureHandler:^(ZYLNetworkError *error) {
- dispatch_async(dispatch_get_main_queue(), ^{
- !self.failureHandler?:self.failureHandler(error.code, error.domain, self.currentPayType);
- });
- }];
- }else {
- dispatch_async(dispatch_get_main_queue(), ^{
- !self.failureHandler?:self.failureHandler(error.code, error.domain, self.currentPayType);
- });
- }
- }];
- [alert show];
- }];
- }
- - (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
- if (jsonString == nil) {
- return nil;
- }
-
- NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
- NSError *err;
- NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
- options:NSJSONReadingMutableContainers
- error:&err];
- if(err) {
- NSLog(@"json解析失败:%@",err);
- return nil;
- }
- return dic;
- }
- /**
- 根据指定位置索引获取指定的urlSchemes
- @param index plist里的索引
- @return urlSchemes
- */
- - (NSString *)getUrlSchemesWithUrltypesIndex:(NSInteger)index {
- NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
- NSArray *bundleUrltypes = [infoDic objectForKey:@"CFBundleURLTypes"];
- NSDictionary *bundleDict = [bundleUrltypes objectAtIndex:index];
- NSString *urlSchemes = [[bundleDict objectForKey:@"CFBundleURLSchemes"] firstObject];
- return urlSchemes;
- }
- #pragma mark — 缓存苹果支付成功的订单信息
- /// 缓存支付成功的订单信息
- + (void)saveAppStoreCuccessData:(NSDictionary *)dic {
- NSDictionary *orders = [UserDefaults objectForKey:APPSTORE_PAY_SUCCESS_INFO_USERDEFAULTS];
- BOOL isExist = NO;
- NSString *key = dic[@"orderId"];
- for (NSString *orderId in orders.allKeys) {
- if ([orderId isEqualToString:key]) {
- isExist = YES;
- break;
- }
- }
- if (!isExist) {
- NSMutableDictionary *allOrderInfo = [NSMutableDictionary dictionaryWithDictionary:orders];
- [allOrderInfo addEntriesFromDictionary:@{key:dic}];
- [UserDefaults setObject:allOrderInfo forKey:APPSTORE_PAY_SUCCESS_INFO_USERDEFAULTS];
- }
- }
- /// 删除已经验证过的订单信息
- + (void)removeAppStoreCuccessData:(NSString *)orderId {
- NSMutableDictionary *orders = [NSMutableDictionary dictionaryWithDictionary:[UserDefaults objectForKey:APPSTORE_PAY_SUCCESS_INFO_USERDEFAULTS]];
- [orders removeObjectForKey:orderId];
- [UserDefaults setObject:orders forKey:APPSTORE_PAY_SUCCESS_INFO_USERDEFAULTS];
- [UserDefaults synchronize];
- }
- /// 检查苹果支付成功没有校验的订单
- + (void)checkAppStorePaySuccessNoValidationOrders {
- NSDictionary *orders = [UserDefaults objectForKey:APPSTORE_PAY_SUCCESS_INFO_USERDEFAULTS];
- // 没有需要校验的订单
- if (orders.allKeys.count == 0) {
- return;
- }
- for (NSDictionary *dict in orders.allValues) {
- NSString *orderId = dict[@"orderId"];
- NSString *transactionId = dict[@"transactionId"];
- NSString *receiptData = dict[@"receiptData"];
- [[XYPayAPIManager new] addPayOrderWithOrderId:orderId transactionId:transactionId receiptData:receiptData successHandler:^(ZYLResponseModel *responseModel) {
- // 删除已经效验的订单信息
- [self removeAppStoreCuccessData:orderId];
- } failureHandler:^(ZYLNetworkError *error) {
- if ([error.codeStr isEqualToString:@"OPERATION_FAILED"]) {
- // 该订单已交易完成,请勿重复提交
- [self removeAppStoreCuccessData:orderId];
- }
- }];
- }
- }
- @end
|