zoukankan      html  css  js  c++  java
  • iOS App 内购 Demo

    /*注意事项:

    1.沙盒环境测试appStore内购流程的时候,请使用没越狱的设备。

    2.请务必使用真机来测试,一切以真机为准。

    3.项目的Bundle identifier需要与您申请AppID时填写的bundleID一致,不然会无法请求到商品信息。

    4.如果是你自己的设备上已经绑定了自己的AppleID账号请先注销掉,否则你哭爹喊娘都不知道是怎么回事。

    5.订单校验 苹果审核app时,仍然在沙盒环境下测试,所以需要先进行正式环境验证,如果发现是沙盒环境则转到沙盒验证。

    识别沙盒环境订单方法:

    1.根据字段 environment = sandbox。

    2.根据验证接口返回的状态码,如果status=21007,则表示当前为沙盒环境。

    苹果反馈的状态码:

    21000App Store无法读取你提供的JSON数据

    21002 订单数据不符合格式

    21003 订单无法被验证

    21004 你提供的共享密钥和账户的共享密钥不一致

    21005 订单服务器当前不可用

    21006 订单是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中

    21007 订单信息是测试用(sandbox),但却被发送到产品环境中验证

    21008 订单信息是产品环境中使用,但却被发送到测试环境中验证

    */

    开发内购功能,首先需要一个开发者账号,在 App store connect -> 我的App -> 功能 中申请 如图:

    有四种类型,主要看项目的需求而决定(自动续期订阅这个最为麻烦,要签署协议,而已在App 启动是请求苹果服务器,是否存在自动续期订单)

    这个图是新增一项内购产品 

    参考名称:介绍这个内购产品 

    产品ID(主要用到的):支付的时候用到 

    其他的都是在app store 中看到的介绍

    首先引用 #import <StoreKit/StoreKit.h>

    封装一个内购功能,这个在app 中可能多个地方用到

    + (instancetype)shareIAPManager;
    
    //添加内购产品
    - (void)addPurchWithProductID:(NSString *)product_id completeHandle:(IAPCompletionHandleBlock)handle;
    复制代码

    SKProductsRequestDelegate代理方法
    交易结束后用到

    - (void)completeTransaction:(SKPaymentTransaction *)transaction {
    
        NSString * productIdentifier = transaction.payment.productIdentifier;
        NSData *data = [productIdentifier dataUsingEncoding:NSUTF8StringEncoding];
        NSString *receipt = [data base64EncodedStringWithOptions:0];
    
        YMLog(@"%@",receipt);
        if ([productIdentifier length] > 0) {
            // 向自己的服务器验证购买凭证
            NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
            if (![[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]]) {
                // 取 receipt 的时候要判空,如果文件不存在,就要从苹果服务器重新刷新下载 receipt 了
                // SKReceiptRefreshRequest 刷新的时候,需要用户输入 Apple ID,同时需要网络状态良好
                SKReceiptRefreshRequest *receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
                receiptRefreshRequest.delegate = self;
                [receiptRefreshRequest start];
                return;
            }
            NSData *data = [NSData dataWithContentsOfURL:receiptURL];
            /** 交易凭证*/
            NSString *receipt_data = [data base64EncodedStringWithOptions:0];
            /** 事务标识符(交易编号)  交易编号(必传:防止越狱下内购被破解,校验 in_app 参数)*/
            NSString *transaction_id = transaction.transactionIdentifier;
            NSString *goodID = transaction.payment.productIdentifier;
    
            //这里缓存receipt_data,transaction_id 因为后端做校验的时候需要用到这两个字段
            YMLog(@"%@",receipt_data);
            YMLog(@"%@",transaction_id);
    
            [self retquestApplePay:receipt_data transaction_id:transaction_id goodsID:goodID];
        }
        [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
    }
    复制代码
    • (void)completeTransaction:(SKPaymentTransaction *)transaction ;

    中 获取

    NSString * productIdentifier = transaction.payment.productIdentifier;

    NSData *data = [productIdentifier
    dataUsingEncoding:NSUTF8StringEncoding];

    NSString *receipt = [data base64EncodedStringWithOptions:0];

    NSString *receipt_data = [data base64EncodedStringWithOptions:0];

    /** 事务标识符(交易编号) 交易编号(必传:防止越狱下内购被破解,校验 in_app 参数)*/

    NSString *transaction_id = transaction.transactionIdentifier;

    NSString *goodID = transaction.payment.productIdentifier;

    得到的 transaction_id receipt_data goodID需要上传到app 服务器校验(具体看后端的需求)

    //private 提交订单数据到app 服务器校验

    - (void)retquestApplePay:(NSString *)receipt_data transaction_id:(NSString *)transaction_id goodsID:(NSString *)goodsId;
    复制代码

    // 交易失败

    - (void)failedTransaction:(SKPaymentTransaction *)transaction{
        if (transaction.error.code != SKErrorPaymentCancelled) {
            [self handleActionWithType:IAPPurchFailed data:nil];
        }else{
            [self handleActionWithType:IAPPurchCancel data:nil];
        }
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
    
    #pragma mark -- 结束上次未完成的交易 防止串单
    -(void)removeAllUncompleteTransactionBeforeStartNewTransaction{
        NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
        if (transactions.count > 0) {
            //检测是否有未完成的交易
            SKPaymentTransaction* transaction = [transactions firstObject];
            if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                return;
            }
        }
    }复制代码

    IAPDemo链接:Demo

    我的掘金:https://juejin.im/post/5dca8b526fb9a04a8e3be109

  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/ljj-Andrew-519/p/11847045.html
Copyright © 2011-2022 走看看