iOS开发-2017苹果内购最新教程

公司项目中有虚拟产品,所以要使用苹果内购.自此记录一下苹果内购的流程.前提是已有开发者账号

协议,税务和银行业务

  • 协议,税务和银行业务


    iOS开发-2017苹果内购最新教程_第1张图片
    协议,税务和银行业务

    iOS开发-2017苹果内购最新教程_第2张图片
    申请合同
  • 这里提示地址太长,按照要求重新填写一下就可以

iOS开发-2017苹果内购最新教程_第3张图片
添加联系人
  • 同意协议并提交
iOS开发-2017苹果内购最新教程_第4张图片
  • 设置相关信息


    iOS开发-2017苹果内购最新教程_第5张图片
    • 联系人信息

添加相关联系人信息之后,注意在role(角色)中,为联系人选择身份(高级管理人员 ,金融,技术,法律,营销),点击Done保存

iOS开发-2017苹果内购最新教程_第6张图片
联系人
  • 银行信息

    1. 添加银行信息
    iOS开发-2017苹果内购最新教程_第7张图片
    添加银行

    2.选择国家

    iOS开发-2017苹果内购最新教程_第8张图片
    选择国家

    3.填写CNAPS

    CNAPS 银行网点联行号.我们可以直接到银行客服电话查询 CNAPS, 快速便捷.还可以通过下图的Look up CNAPS Code 查询. 不过有的查询不到

    iOS开发-2017苹果内购最新教程_第9张图片
    CNAPS

    iOS开发-2017苹果内购最新教程_第10张图片
    Look up CNAPS Code

4.确认银行信息

iOS开发-2017苹果内购最新教程_第11张图片
银行信息

5.填写公司银行账号信息

iOS开发-2017苹果内购最新教程_第12张图片
公司银行信息
  • 税务信息

税务信息有三个选项:美国税务、澳大利亚税务、加拿大税务。我们在这里选择美国税务就可以

iOS开发-2017苹果内购最新教程_第13张图片
税务信息

这里有两个问题:如下图.我选择的都是NO

iOS开发-2017苹果内购最新教程_第14张图片

iOS开发-2017苹果内购最新教程_第15张图片

填写税务相关信息

9b.Foreign TIN 是填写公司税务识别码.公司营业执照上同意社会信用代码去掉前两位和最后一位就是公司税务识别码(15位)

iOS开发-2017苹果内购最新教程_第16张图片

点击提交之后会让你确认信息,确认无误后再次点击提交(提交后无法修改)

创建测试APP

新建APP在这里就不详细描述了

添加内购

  • 选择功能,我们添加一个app内购项目


    iOS开发-2017苹果内购最新教程_第17张图片
    添加内购
  • 根据项目需求,选择内购项目


    iOS开发-2017苹果内购最新教程_第18张图片
    消耗性项目
  • 填写内购项目的相关信息

  1. 商品名称根据你的消费道具的实际意义来说明
  2. 产品ID是比较重要的,只要唯一即可,在实际应用中,一定要认真填写。
  3. 选择价格
iOS开发-2017苹果内购最新教程_第19张图片
  • 本地化版本

将在 App Store 上可见的 App 内购买项目名称。可以参考App Store中其他应用的内购项目描述
描述不得少于10个字符.没有重新截图

iOS开发-2017苹果内购最新教程_第20张图片
本地化
  • 审核信息

1.只会在审核中使用屏幕快照,不会将其显示在 App Store 上。屏幕快照必须具有适合您 App 平台的有效尺寸。
2.能够有助于我们进行审核的关于您的 App 内购买项目的其他信息,如测试帐户(包括用户名、密码等)。审核备注不得超过 4000 个字符。

iOS开发-2017苹果内购最新教程_第21张图片
审核信息
  • 内购项目则添加完成

申请沙盒测试账号(用来测试购买项目)

我们不必用真实的人民币测试购买内购项目

  • 首先我们回到iTunes Connect中,在这里我们选择用户和职能。
  • 添加沙箱技术测试员


    iOS开发-2017苹果内购最新教程_第22张图片
    测试人员
  • 添加测试员详细信息

所有信息都可以随意填写,不用管是否真实。但是App Store地区必须对应
注意: 邮件地址不能填写与 Apple ID 关联的, 密码保护问题必须在 6 到 35 个字符之间。密码必须包含至少一个大写字母。

iOS开发-2017苹果内购最新教程_第23张图片
信息

所有准备工作都已完成.打开项目开始撸代码

在项目中实现购买

首先在项目工程中加入storekit.framework,加入头文件#import
遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate

 //添加一个交易队列观察者
  [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
            
 //self.productIds是在开发者平台填写的产品id
 self.productId = @"701";
 if ([SKPaymentQueue canMakePayments]) {
       [self requestProductData:self.productId];
  }else{
        DLog(@"不允许程序内付费");
  }
  • 去苹果服务器请求产品信息
// 去苹果服务器请求产品信息
- (void)requestProductData:(NSString *)productId {
    
    
    [SVProgressHUD show];
    
    NSArray *productArr = [[NSArray alloc]initWithObjects:productId, nil];
    
    NSSet *productSet = [NSSet setWithArray:productArr];
    
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:productSet];
    
    request.delegate = self;
    [request start];
    
}
  • SKProductsRequestDelegate
// 收到产品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    
    
    NSArray *productArr = response.products;
    
    if ([productArr count] == 0) {
        [SVProgressHUD dismiss];
        DLog(@"没有该商品");
        return;
    }
    
    DLog(@"productId = %@",response.invalidProductIdentifiers);
    DLog(@"产品付费数量 = %zd",productArr.count);
    
    SKProduct *p = nil;
    
    for (SKProduct *pro in productArr) {
        DLog(@"description:%@",[pro description]);
        DLog(@"localizedTitle:%@",[pro localizedTitle]);
        DLog(@"localizedDescription:%@",[pro localizedDescription]);
        DLog(@"price:%@",[pro price]);
        DLog(@"productIdentifier:%@",[pro productIdentifier]);
        if ([pro.productIdentifier isEqualToString:self.productId]) {
            p = pro;
        }
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    
    //发送内购请求
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}

  • SKRequestDelegate
- (void)requestDidFinish:(SKRequest *)request {
    [SVProgressHUD dismiss];
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    [SVProgressHUD showErrorWithStatus:@"支付失败"];
}

  • SKPaymentTransactionObserver监听购买结果
// 监听购买结果

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

    for (SKPaymentTransaction *tran in transactions) {
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased: //交易完成
                // 发送到苹果服务器验证凭证
                [self verifyPurchaseWithPaymentTrasaction];
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                break;
            case SKPaymentTransactionStatePurchasing: //商品添加进列表

                break;
            case SKPaymentTransactionStateRestored: //购买过
                // 发送到苹果服务器验证凭证
                
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                break;
            case SKPaymentTransactionStateFailed: //交易失败
                
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                [SVProgressHUD showErrorWithStatus:@"购买失败"];
                break;

            default:
                break;
        }
    }
}
  • 发送到苹果服务器验证凭证

//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
// 验证购买
- (void)verifyPurchaseWithPaymentTrasaction {
    
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    // 发送网络POST请求,对购买凭据进行验证
    //测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt
    //正式验证地址:https://buy.itunes.apple.com/verifyReceipt
    NSURL *url = [NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *urlRequest =
    [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
    urlRequest.HTTPMethod = @"POST";
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    urlRequest.HTTPBody = payloadData;
    // 提交验证请求,并获得官方的验证JSON结果 iOS9后更改了另外的一个方法
    NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
    // 官方验证结果为空
    if (result == nil) {
        NSLog(@"验证失败");
        return;
    }
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    if (dict != nil) {
        // 比对字典中以下信息基本上可以保证数据安全
        // bundle_id , application_version , product_id , transaction_id
        NSLog(@"验证成功!购买的商品是:%@", @"_productName");
    }

}
  • 移动观察者
- (void)dealloc {
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

测试内购

必须是没有越狱的真机
测试之前现在iPhone上的Apple id 注销

  • 使用现有Apple id

使用在沙箱测试员中添加的账号即可

iOS开发-2017苹果内购最新教程_第24张图片
账号
  • 购买


    iOS开发-2017苹果内购最新教程_第25张图片
    购买
  • 完成购买


    iOS开发-2017苹果内购最新教程_第26张图片
    完成

官方文档

  • 2017.03.15更新

APP Store首发以为会卡在内购上,但是顺利的审核过了,但是版本更新的时候,审核员如何做内购测试呢? 首先你要了解xcode运行的APP只能用沙盒测试账号进行购买,不能使用真实的Apple id. 而你在应用商店里下载的只能使用真实的Apple id.

解决方案:

进行二次验证:测试用沙盒验证,App Store审核的时候也使用的是沙盒购买,所以验证购买凭证的时候需要判断返回Status Code决定是否去沙盒进行二次验证,为了线上用户的使用,验证的顺序肯定是先验证正式环境,此时若返回值为21007,就需要去沙盒二次验证,因为此购买的是在沙盒进行的

注意:

验证操作让后台去验证

丢单处理详看下篇博客

iOS开发-内购丢单处理方式

你可能感兴趣的:(iOS开发-2017苹果内购最新教程)