iOS内购图文流程(2017)
什么是内购?
只要在iPhone App上购买的不是实物产品(也就是虚拟产品如qq币.虎牙币.电子书......) 都需要走内购流程,苹果在里面抽走三成。
使用内购需要走的流程。
1,填写协议,税务和银行业务;
2,填写用户和职能; 创建内购的项目
3,写代码,和后台配合
4,添加项目内购测试账号;检验成果
具体步骤:
接下来的步骤特别繁琐,请做好准备。
一.填写协议,税务和银行业务配置 https://itunesconnect.apple.com
1.请求合同
填写地址信息
阅读同意协议
2.填写联系方式
添加新的联系人
选中联系人
3.填写银行信息
添加银行卡
选择银行卡所在国家
填写银行CNAPS Code 货币类型 CN###银行账号如果是对公的账号,需要填写公司的英文名称,如果没有的话拼音
4.填写税务信息
U.S Tax Forms: 美国税务
Australia Tax Forms:澳大利亚税务
Canada Tax Forms: 加拿大税务
第一个问题如下:询问你是否是美国居民,有没有美国伙伴关系或者美国公司,如果没有直接选择No。
第二个问题如下:询问你有没有在美国的商业性活动,没有也直接选No
然后填写你的税务信息,包括以下几点:
Individual or Organization Name:个人或者组织名称
Country of incorporation: 所在国家
Type of Beneficial Owner:受益方式,独立开发者选个人
Permanent Residence:居住地址
Mailing address:邮寄地址
Name of Person Making this Declaration:声明人
Title:头衔
填写完这些信息后就可以提交了
5.等待审核,时间24小时左右。
二.创建内购项目
选中你要添加内购项目的APP然后点击功能,点击+创建内购项目。
根据自己APP的需求选择类型
填写项目名称id (ps:应用在首次添加内购买项目时需要与新的应用版本一起提交审核。)
添加沙盒技术测试员
用户职能>沙箱技术测试员
注意事项:
邮箱随便写但是格式要正确(test@163.com),但是不能用已经是AppleID的邮箱
App Store 地区不要乱选。虽然随便哪个地区都可以用来测试(还没上线之前app并没有地区之分),但是在沙盒测试的时候,弹出的购买提示框会根据当前AppleID(沙盒账号)的地区显示语言的。
使用沙盒测试一定要用真机 (越狱的不行)
沙盒账号不能直接登录AppleStore登录时会提示"不允许创建iTunes账户”
进行沙盒测试时需要退出AppleStore的账号
三.代码
#import <Foundation/Foundation.h>
#import "WXApi.h"
typedef NS_ENUM(NSInteger , Payment) {
IAP6 = 6,
IAP25 = 25,
IAP60 = 60
};
@interface PayCenter : NSObject
singleton_interface(PayCenter);
- (void)startInit;
- (void)payWithMoney:(NSInteger)money andType:(PayType)type dataDic:(NSDictionary *)dataDic;
@property (nonatomic, strong) MBProgressHUD * hud;
@property (nonatomic, copy) NSString * rechargeNumber;
@end
#define kProductID_IAP6 @"org.qqhl.nursning.6"//6
#import "PayCenter.h"
#import "PayHttpRequest.h"
//#import "Order.h"
//#import "DataSigner.h"
//#import <AlipaySDK/AlipaySDK.h>
#import <StoreKit/StoreKit.h>
@interface PayCenter()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
{
int buyType;
NSInteger _money;
}
@property (nonatomic, strong) NSMutableDictionary * dataDic;
@end
@implementation PayCenter
singleton_implementation(PayCenter);
- (void)startInit
{
[WXApi registerApp:kWeChatShareAppKey withDescription:appDefaultTilte];
}
- (void)payWithMoney:(NSInteger)money andType:(PayType)type dataDic:(NSDictionary *)dataDic
{
_money = money;
self.dataDic = [NSMutableDictionary dictionaryWithDictionary:dataDic];
switch (type) {
case PayTypeWX:
[self payTypeWXPay];
break;
case ApplePay:
// [self payTypeAliPay];
[[SKPaymentQueue defaultQueue]addTransactionObserver:self];
if ([SKPaymentQueue canMakePayments]) {
HULog(@"允许程序内付费购买");
[self payTypeApplePay];
}else {
HULog(@"不允许程序内付费购买");
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"您的手机没有打开程序内付费购买"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView show];
}
break;
default:
break;
}
}
- (void)payTypeApplePay{
NSLog(@"---------请求对应的产品信息------------");
NSArray *product = nil;
switch (_money) {
case IAP6:
{
product=[[NSArray alloc] initWithObjects:kProductID_IAP6,nil];
NSLog(@"---------IAP6------------");
}
break;
case IAP25:
{
NSLog(@"---------IAP25------------");
}
break;
case IAP60:
{
NSLog(@"---------IAP60------------");
}
break;
default:
break;
}
NSSet *nsSet = [NSSet setWithArray:product];
SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:nsSet];
request.delegate = self;
[request start];
}
#pragma mark - SKProductsRequestDelegate代理
//返回的在苹果服务器请求的产品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
HULog(@"收到产品信息");
NSArray *myProduct = response.products;
HULog(@"产品id %@",response.invalidProductIdentifiers);
NSLog(@"产品付费数量%d",(int)[myProduct count]);
//populate UI
for (SKProduct *product in myProduct) {
NSLog(@"product info");
NSLog(@"SKProduct 描述信息%@", [product description]);
NSLog(@"产品标题 %@" , product.localizedTitle);
NSLog(@"产品描述信息: %@" , product.localizedDescription);
NSLog(@"价格: %@" , product.price);
NSLog(@"Product id: %@" , product.productIdentifier);
}
SKPayment *payment = nil;
switch (_money) {
case IAP6:
{
payment = [SKPayment paymentWithProductIdentifier:kProductID_IAP6];
}
break;
case IAP25:{
}
default:
break;
}
NSLog(@"发起购买请求");
[[SKPaymentQueue defaultQueue]addPayment:payment];
}
//实现监听方法
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
NSLog(@"调用了几次这个方法?");
SKPaymentTransaction *transaction = transactions.lastObject;
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased: {
NSLog(@"购买完成,向自己的服务器验证 ---- %@", transaction.payment.applicationUsername);
NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
NSString *receipt = [data base64EncodedStringWithOptions:0];
// [self buySuccessWithReceipt:receipt transaction:transaction];
}
break;
case SKPaymentTransactionStateFailed: {
NSLog(@"交易失败");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
break;
case SKPaymentTransactionStateRestored: {
NSLog(@"已经购买过该商品");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
break;
case SKPaymentTransactionStatePurchasing: {
NSLog(@"商品添加进列表");
}
break;
default: {
NSLog(@"这是什么情况啊?");
}
break;
}
}
@end```
####购买成功后需要跟服务器交互验证交易是否成功
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURL receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// 从沙盒中获取到购买凭据
NSData receipt = [NSData dataWithContentsOfURL:receiptURL];
// 传输的是BASE64编码的字符串
/
BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性
BASE64是可以编码和解码的
*/
NSDictionary *requestContents = @{
@"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSError *error;
// 转换为 JSON 格式
NSData requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
// 不存在
if (!requestData) { / ... Handle error ... */ }
// 发送网络POST请求,对购买凭据进行验证
NSString *verifyUrlString;
测试环境 verifyUrlString = @"https://sandbox.itunes.apple.com/verifyReceipt";
生产环境 verifyUrlString = @"https://buy.itunes.apple.com/verifyReceipt";
// 国内访问苹果服务器比较慢,timeoutInterval 需要长一点
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:[[NSURL alloc] initWithString:verifyUrlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
// 在后台对列中提交验证请求,并获得官方的验证JSON结果
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(@"链接失败");
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) {
NSLog(@"验证失败");
}
// 比对 jsonResponse 中以下信息基本上可以保证数据安全
/*
bundle_id
application_version
product_id
transaction_id
*/
NSLog(@"验证成功");
}
}];
}
[苹果官方文档](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW4)
```刚接触内购如有不足之处请指教 ```