IOS 自动订阅以及恢复购买

news/2025/1/16 3:37:09/

<SKPaymentTransactionObserver,SKRequestDelegate,SKProductsRequestDelegate>

 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{    //添加一个交易队列观察者

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {

    NSLog(@"%@",error);

}

 

/// Called when all restorable transactions have been processed by the payment queue.

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {

    NSLog(@"%@",queue.transactions);

    if (queue.transactions.count==0)

    {

        [YJProgressHUD showMessage:@"您还没购买过会员!"];

    }

    else

    {

        for (SKPaymentTransaction *transaction in queue.transactions)

        {

            NSLog(@"%@",transaction.originalTransaction.transactionIdentifier);//不会改变的订单号

        }

通过这个订单号去向后台请求会员状态

    }

}

 

 

//监听购买结果

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions API_AVAILABLE(ios(3.0), macos(10.7), watchos(6.2))

{

    for (SKPaymentTransaction *tran in transactions) {

        [Singleton ShareDatabase].hgtran = tran;//一会儿需要删除的购买凭证

        // 如果小票状态是购买完成

        if (SKPaymentTransactionStatePurchased == tran.transactionState) {

            // 订阅特殊处理

            if (tran.originalTransaction) {

                // 如果是自动续费的订单,originalTransaction会有内容

                NSLog(@"自动续费的订单,originalTransaction = %@",tran.originalTransaction);

            } else {

                // 普通购买,以及第一次购买自动订阅

                NSLog(@"普通购买,以及第一次购买自动订阅");

            }

            [[SKPaymentQueue defaultQueue] finishTransaction:tran];

            [self verifyPruchase:tran isServerflag:NO];

        } else if (SKPaymentTransactionStatePurchasing == tran.transactionState) {

            NSLog(@"商品添加进列表");

        } else if (SKPaymentTransactionStateRestored == tran.transactionState) {

            NSLog(@"已经购买过商品");

            [YJProgressHUD hideHUD];

            [[SKPaymentQueue defaultQueue] finishTransaction:tran];

        } else if (SKPaymentTransactionStateFailed == tran.transactionState) {

            NSLog(@"交易失败");

            [YJProgressHUD hideHUD];

            [[SKPaymentQueue defaultQueue] finishTransaction:tran];

        }

    }

}

 

测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt

//正式验证地址:https://buy.itunes.apple.com/verifyReceipt

- (void)verifyPruchase:(SKPaymentTransaction *)tran isServerflag:(BOOL)flag

{// 发送给苹果服务器/自己服务器认证:

    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

    // 从沙盒中获取到购买凭据

    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];

    // 发送网络POST请求,对购买凭据进行验证

    NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";

    if (flag) {

        serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";

    }

    NSURL *storeURL = [NSURL URLWithString:serverString];

    NSMutableURLRequest *urlRequest =

    [NSMutableURLRequest requestWithURL:storeURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];

    urlRequest.HTTPMethod = @"POST";

    NSDictionary *requestContents = @{

                                      @"receipt-data":[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed],

                                      @"password":@""//自己的内购配置

                                      };

    NSData *payloadData = [NSJSONSerialization dataWithJSONObject:requestContents

                                                          options:0

                                                            error:nil];

    

    urlRequest.HTTPBody = payloadData;

    // 提交验证请求,并获得官方的验证JSON结果 iOS9后更改了另外的一个方法

    NSData *resultData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];

    // 官方验证结果为空

    if (resultData == nil) {

        NSLog(@"验证失败");

        return;

    }

    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:resultData options:NSJSONReadingAllowFragments error:nil];

    if (dict != nil) {

        NSLog(@"%@",dict);

        NSString *status = [NSString stringWithFormat:@"%@",dict[@"status"]];

        if (status && [status isEqualToString:@"21007"]) {

            [self verifyPruchase:[Singleton ShareDatabase].hgtran isServerflag:YES];

        }

        else if (status && [status isEqualToString:@"0"])

        {

            [Singleton ShareDatabase].TransactionID = StringFormat(@"%@",[[[dict valueForKey:@"latest_receipt_info"] objectAtIndex:0] valueForKey:@"original_transaction_id"]);

            [Singleton ShareDatabase].tokenStr = [Singleton ShareDatabase].TransactionID;

            [[NSUserDefaults standardUserDefaults]setValue:[Singleton ShareDatabase].tokenStr forKey:@"TokenStr"];

            [[NSUserDefaults standardUserDefaults]synchronize];

            [Singleton ShareDatabase].receipt = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

            NSString *typeStr = @"";

            if(flag == YES){

                typeStr = @"0";//沙盒

            }

            else{

                typeStr = @"1";//正式

            }

去请求后台,改变会员状态,成功后记得销毁凭证

                       [[SKPaymentQueue defaultQueue] finishTransaction:[Singleton ShareDatabase].hgtran];

        }

    }

}

 

 

 

 

购买方法

    NSString *PRODUCTID = @"";//自己内购配置

    //判断是否可进行支付

    if ([SKPaymentQueue canMakePayments]) {

        [YJProgressHUD showLoading:@"加载中..."];

        [self requestProductData:PRODUCTID];

    } else {

        NSLog(@"不允许程序内付费");

    }

 

- (void)requestProductData:(NSString *)type {

    //根据商品ID查找商品信息

    NSArray *product = [[NSArray alloc] initWithObjects:type, nil];

    NSSet *nsset = [NSSet setWithArray:product];

    //创建SKProductsRequest对象,用想要出售的商品的标识来初始化, 然后附加上对应的委托对象。

    //该请求的响应包含了可用商品的本地化信息。

    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];

    request.delegate = self;

    [request start];

}

 

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response API_AVAILABLE(ios(3.0), macos(10.7), watchos(6.2))

{

    //接收商品信息

    NSArray *product = response.products;

    if ([product count] == 0) {

        NSLog(@"--------------没有商品------------------");

        return;

    }

    NSLog(@"productID:%@", response.invalidProductIdentifiers);

    NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);

    // SKProduct对象包含了在App Store上注册的商品的本地化信息。

    SKProduct *storeProduct = nil;

    for (SKProduct *pro in product) {

        NSLog(@"%@", [pro description]);

        NSLog(@"%@", [pro localizedTitle]);

        NSLog(@"%@", [pro localizedDescription]);

        NSLog(@"%@", [pro price]);

        NSLog(@"%@", [pro productIdentifier]);

        storeProduct = pro;

    }

    SKPayment *payment = [SKPayment paymentWithProduct:storeProduct];

    //发送内购请求

    [[SKPaymentQueue defaultQueue] addPayment:payment];

}

 

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {

    NSLog(@"------------------购买失败-----------------:%@", error);

}

 

- (void)requestDidFinish:(SKRequest *)request {

    NSLog(@"------------购买完成-----------------");

}

 

 

 

恢复购买方法

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

 

 


http://www.ppmy.cn/news/748574.html

相关文章

ios自动订阅服务器,iOS IAP - 自动续期订阅

自动续期订阅是苹果推出的一项苹果内购服务,当用户在App Store订阅了某项服务后,App Store会在订阅时间快到期之前,自动扣费并帮用户续订该服务。 自动续期订阅的优势 创建自动续期订阅 1. 从“我的 App”中,选择您的 App。 2. 在侧边栏的“App 内购买项目”下方,点按“管…

Spring Boot 中的 @ComponentScan 注解是什么,原理,如何使用

Spring Boot 中的 ComponentScan 注解是什么&#xff0c;原理&#xff0c;如何使用 在 Spring Boot 中&#xff0c;ComponentScan 是一种注解&#xff0c;它可以让 Spring 自动扫描指定的包及其子包中的组件&#xff0c;并将这些组件自动装配到 Spring 容器中。本文将介绍 Com…

【C++学习笔记】1.6 引用

目录 &#x1f36f;1.6 引用 &#x1f95d;1. 引用的概念 &#x1f95d;2. 引用的特性 1、引用在定义时必须初始化 2、一个变量可以有多个引用 3、引用一旦引用一个实体&#xff0c;再不能引用其他实体 &#x1f95d;3. 常引用 1、取别名的原则&#xff1a;对原引用的…

游泳耳机排行榜前十名,分享几款值得推荐的游泳耳机

转眼间就要进入三伏天中的初伏阶段&#xff0c;在这段时间中很多人都忙忙碌碌的入手运动装备&#xff0c;以此来迎接一年一度的瘦身最佳日子&#xff0c;其中入手最多的基本都是游泳装备&#xff0c;因为游泳能够帮助我们塑性的同时还能够提高身体的各个机能&#xff0c;是夏天…

CMake 笔记

CMake 笔记 CMake 笔记 基础项目多个目录创建项目 链接库 用到的指令实验 使用自定义库 用到的指令实验 指定 C 标准CMake常见变量名 基础项目 实现一个CMakeLists.txt最简单是以下三步&#xff1a; # 最低 CMake 版本要求&#xff1a;指定项目所需的最低 CMake 版本 cma…

初来驾到。

Hello&#xff0c;各位大佬们。 今天我来谈谈我对于编程的一些小目标。 对于编程萌新来说&#xff0c;我编程主要的路线主要是跟着学校走&#xff0c;有不懂的话就上网看看一些课程来补漏&#xff0c;我的路线可能会变&#xff0c;但也以后再谈叭。 在学校课程没那么多的情况…

《冷宫太子妃》

因为一个特殊的原因&#xff0c;她远嫁别国&#xff0c;成了太子妃 嫁给了一个内心早有别人的太子 新婚之夜&#xff0c;他说他不想圆房 她把自己的手腕割破&#xff0c;滴血充作落红 他说&#xff0c;事情要做就做个彻底 于是她用小刀剜去了手臂上的守宫砂 他为了把她气…

《穿越迷雾》

一 清晨&#xff0c;早起&#xff0c;一个蛋&#xff0c;一瓶牛奶&#xff0c;俩小蛋糕&#xff0c;摆桌上 夜晚&#xff0c;回家&#xff0c;两个人&#xff0c;出门散步&#xff0c;超市购物&#xff0c;握手上 睡前&#xff0c;取三个盅 放米、杂粮、汤料&#xff0c;添净水…