iOS之开发配置iOS证书、更新iOS学习

2017iOS内购最详细流程(手把手教你内购)

2017-05-27  本文已影响1284人  夜空丶

最近公司需要开发内购,特记录过程如下:

在写代码之前还要做在itunes里做几步操作:

先登录itunes(https://itunesconnect.apple.com)填写相关协议,税务和银行业务

itunes协议税务

首先,先填好公司地址

填写公司地址

然后填写合同信息

要勾选同意才进行下一步


1、之后进入填写详细信息界面,分别有三个:联系人信息,银行信息,税务信息

1-1

首先选择Add New Contact填写联系人信息(姓,名,email,职位,电话,后一个可以不写)

然后这些选择都选刚刚添加的联系人,如此联系人信息就填写完成了


2、填写银行信息(图1-1)

    添加银行信息

选择国家

CNAPS 银行网点联行号.我们可以直接到银行客服电话查询 CNAPS, 快速便捷.还可以通过下图的Look up CNAPS Code 查询. 不过有的查询不到。如果知道银行卡的分行地址也可以这样找:http://www.tui78.com/bank/选择银行,然后选择分行地址就可以找到CNAPS code

确认银行信息

填写公司银行账号信息

至此,银行信息填写完毕,接下来就是税务信息了:

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

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

填写税务相关信息

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

点击提交之后会让你确认信息,确认无误后再次点击提交(提交后无法修改,所以请认真填写)

到这里相关协议,税务和银行业务已经填写完毕,接下来是创建内购项目

选择王牌的APP->功能-APP内购买项目

消耗性项目

填写内购项目的相关信息

商品名称根据你的消费道具的实际意义来说明

产品ID是比较重要的,只要唯一即可,在实际应用中,一定要认真填写。

选择价格

本地化版本

将在 App Store 上可见的 App 内购买项目名称。可以参考App Store中其他应用的内购项目描述

描述不得少于10个字符.没有重新截图

审核信息

1.只会在审核中使用屏幕快照,不会将其显示在 App Store 上。屏幕快照必须具有适合您 App 平台的有效尺寸。

2.能够有助于我们进行审核的关于您的 App 内购买项目的其他信息,如测试帐户(包括用户名、密码等)。审核备注不得超过 4000 个字符。

如此内购项目就完成了


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

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

首先我们回到iTunes Connect中,在这里我们选择用户和职能。

添加沙箱技术测试员

添加测试员详细信息

所有信息都可以随意填写,不用管是否真实。但是App Store地区必须对应

注意: 邮件地址不能填写与 Apple ID 关联的, 密码保护问题必须在 6 到 35 个字符之间。密码必须包含至少一个大写字母。

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


在项目中实现购买

首先在项目工程中加入storekit.framework,加入头文件#import

遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate

//调起支付代码

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

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

//self.productIds是在开发者平台填写的产品id

self.productId=@"701";

if ([SKPaymentQueue canMakePayments]) {

[self requestProductData:self.productId];

}else{

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

}

// 去苹果服务器请求产品信息

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

[MBProgressHUD showHUDAddedTo:self.view animated:YES];

NSArray *productArr = [[NSArray alloc]initWithObjects:productId, nil];

NSSet *productSet = [NSSet setWithArray:productArr];

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

request.delegate = self;

[request start];

}

// 收到产品返回信息

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

NSArray *productArr = response.products;

if ([productArr count] == 0) {

[MBProgressHUD hideHUDForView:self.view animated:YES];

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

return;

}

NSLog(@"productId = %@",response.invalidProductIdentifiers);

NSLog(@"产品付费数量 = %zd",productArr.count);

SKProduct *p = nil;

for (SKProduct *pro in productArr) {

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

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

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

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

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

if ([pro.productIdentifier isEqualToString:self.productId]) {

p = pro;

}

}

SKPayment *payment = [SKPayment paymentWithProduct:p];

//发送内购请求

[[SKPaymentQueue defaultQueue] addPayment:payment];

}

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

[MBProgressHUD hideHUDForView:self.view animated:YES];

}

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

[MBProgressHUD showHUDAddedTo:self.view animated:YES].label.text = @"支付失败";

sleep(0.5);

[MBProgressHUD hideHUDForView:self.view animated:YES];

}

// 监听购买结果

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

for (SKPaymentTransaction *tran in transactions) {

switch (tran.transactionState) {

case SKPaymentTransactionStatePurchased: //交易完成

// 发送到苹果服务器验证凭证

NSLog(@"1");

[self verifyPurchaseWithPaymentTrasaction];

NSLog(@"成功=====%li",tran.error.code);

//允许你从支付队列中移除交易。

[[SKPaymentQueue defaultQueue]finishTransaction:tran];

break;

case SKPaymentTransactionStatePurchasing: //商品添加进列表

NSLog(@"2");

[MBProgressHUD showHUDAddedTo:self.view animated:YES];

break;

case SKPaymentTransactionStateRestored: //购买过

// 发送到苹果服务器验证凭证

NSLog(@"3");

[[SKPaymentQueue defaultQueue]finishTransaction:tran];

[MBProgressHUD hideHUDForView:self.view animated:YES];

break;

case SKPaymentTransactionStateFailed: //交易失败

NSLog(@"交易失败===%li",(long)SKPaymentTransactionStateFailed);

NSLog(@"失败=====%li",tran.error.code);

[[SKPaymentQueue defaultQueue]finishTransaction:tran];

[MBProgressHUD hideHUDForView:self.view animated:YES];

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

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

账号 购买 完成

再说一下真实项目中的一些注意事项:

1.在沙盒测试中,开始测试前一定要在手机的设置中退出当前的Apple ID账号,然后再测,不然会支付失败。

2. 在监听购买结果后,一定要调用[[SKPaymentQueue defaultQueue] finishTransaction:tran];来允许你从支付队列中移除交易。

3.验证过程一般写在服务器,前端把接收到的payload提交给后台,后台验证通过之后再告诉前端。

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

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

6.二次验证   正式服务和沙盒服务切换的问题,苹果测试人员测试的时候都是用的沙盒测试,那么我们审核通过以后要怎么切换到正式服务器呢,苹果对这种情况是有处理的:

处理过程就在验证的步骤,首先我们先用正式服务器验证一下,如果该应用还没通过审核,只能用沙盒测试的话dict会返回一个状态码,Status=21007,这是再用沙盒服务再验证一次就OK了。

附:苹果支付错误目录

Status CodeDescription

21000   The App Store could not read the JSON object you provided.

21002   The data in the receipt-data property was malformed or missing.

21003   The receipt could not be authenticated.

21004   The shared secret you provided does not match the shared secret on file for your account.Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21005   The receipt server is not currently available.

21006   This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21007   This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.

21008   This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.

OK,苹果内购开发完毕。

技术交流请加群:147881723

上一篇下一篇

猜你喜欢

热点阅读