前提
这里默认,你已经有了 Apple 开发者账号,并且已经在 iTunes Connect
-> 我的 App
中,新建了 App。
添加内购
在 iTunes Connect
-> 我的 App
中,打开需要添加内购的 App,选择左上角的功能
-> App 内购买项目
,然后点击 App内购买项目
后面的 +
号,为 App 添加内购。
可以看到内购类型的选项,
这里的各种内购类型,官方解释的已经很清楚了。大部分 App 内购走的都是消耗型项目,这里就以第一个为例,选择第一个
消耗型项目
,点击创建
。- 参考名称:将用于 iTunes Connect 以及“销售和趋势”报告中。不会显示在 App Store 上。名称不得超过 64 个字符。
- 产品 ID:将用于报告的唯一字母数字 ID。
- 销售范围:选中此复选框,App 内购买项目在经批准之后便可在 App Store 上提供。
- 价格:可以查看
所有价格和货币
来选择合适自己 App 的。
- 显示名称:将会在 App Store 上显示的 App 内购买项目名称。
- 描述:根据您 App 内购买项目的配置而定,此描述也可能对客户可见。(不能少于十个字)
- App Store 推广:App Store 上推广此 App 内购买项目(可选)。
- 屏幕快照:只会在审核中使用屏幕快照,它不会在 App Store 上显示。至少 312x390 像素,至少 72 DPI。
- 审核备注:有助于审核您 App 内购买项目的其他信息。
点击存储
按钮,到这里为止,内购项目添加完成。接下来是测试阶段。
添加沙箱技术测试员
沙箱技术测试员可让你在向用户提供 Apple Pay 交易、App 内购买项目、Game Center 功能及本地化版本之前进行测试。
在 iTunes Connect
-> 用户和职能
中,点击沙箱技术测试员
然后点击测试员后的 +
添加测试员。
- 信息不一定需要真实的
- 此账号只能用来测试,不要在正式的 App Store 上使用
- App Store 地区选择,对应的是你创建的 App 的地区
准备工作都搞完了,下面开始上代码吧。
代码
- 工程导入
StoreKit.framework
- 需要的地方
#import <StoreKit/StoreKit.h>
- 代理
<SKProductsRequestDelegate, SKPaymentTransactionObserver>
开启内购:
//开启内购
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
//检测是否可以购买
if ([SKPaymentQueue canMakePayments]) {
//请求商品
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:@"diamond", nil]];
request.delegate = self;
[request start];
} else {
NSLog(@"不允许内购");
}
SKProductsRequestDelegate
代理:
/**
收到返回信息
*/
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
/**
SKProductsResponse
products:SKProduct 的数组,验证有效的商品,
invalidProductIdentifiers:无效的产品数组
*/
NSArray *products = response.products;
if (!products.count) return;
/**
SKProduct:包含了在 App Store 上注册的商品的本地化信息
*/
SKProduct *p = nil;
for (SKProduct *product in products) {
if ([product.productIdentifier isEqualToString:@"diamond"]) {
p = product;
}
}
if (!p) return;
SKPayment *payment = [SKPayment paymentWithProduct:p];
//购买请求
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
/**
请求失败
*/
- (void)requestDidFinish:(SKRequest *)request {
NSLog(@"请求结束");
}
/**
请求结束
*/
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
NSLog(@"请求失败");
}
SKPaymentTransactionObserver
监听:
/*
监听购买结果
*/
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
for (SKPaymentTransaction *tran in transactions) {
switch (tran.transactionState) {
//交易完成
case SKPaymentTransactionStatePurchased:{
//发送到苹果服务器验证凭证
[self verifyPurchaseWithPaymentTransaction];
//从支付队列中移除交易
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
//开始添加
case SKPaymentTransactionStatePurchasing:
break;
//已购买
case SKPaymentTransactionStateRestored:{
//从支付队列中移除交易
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
//失败
case SKPaymentTransactionStateFailed:{
//从支付队列中移除交易
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
default:
break;
}
}
}
购买验证:
/**
验证购买,避免越狱软件模拟苹果请求达到非法购买问题
*/
-(void)verifyPurchaseWithPaymentTransaction {
//从沙盒中获取交易凭证并且拼接成请求体数据
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
//转化为base64字符串
NSString *receiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//拼接请求数据
NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];
NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
//创建request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:verifyPurchaseUrl(0) cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
request.HTTPMethod = @"POST";
request.HTTPBody = bodyData;
//发送请求到苹果官方进行购买验证,也可以让服务器去验证结果,然后返回给客户端
//创建session对象
NSURLSession *session = [NSURLSession sharedSession];
//添加网络任务
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
if (error) {
NSLog(@"验证购买过程中发生错误");
} else {
if (httpResponse.statusCode == 200) {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (dic) return;
//在此处对购买记录进行存储,也可以上传自己的服务器
} else {
NSLog(@"验证购买失败");
}
}
}];
//开始任务
[task resume];
}
苹果官方进行购买验证 url:
/**
inline 内联函数
@param flag 0 测试 其他正式
@return url
*/
static inline NSURL * verifyPurchaseUrl(NSInteger flag) {
if (flag == 0) {
//测试
return [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
}
//正式
return [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
}
- 监听购买结果后,一定要调用
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
来从你的支付队列中移除交易。 - 请使用真机测试,真机测试的时候,需要注销原来的账号,然后用测试账号测试。
- Bundle Identifier 必须保持一致,不然无法请求到商品信息。