2020年苹果虚拟产品购买流程
2020-06-20 本文已影响0人
贺兰山巅
1.申请开发者账号
2.填写相关的税务资料
3.填写内购产品信息
以上是为苹果虚拟支付做准备,网络资料众多,可以借鉴。下面记录相关的实现代码。
1.需要的头文件 #import <StoreKit/StoreKit.h>
2.遵循的代理 SKProductsRequestDelegate,SKPaymentTransactionObserver
3.通过后端获取自己平台的产品订单以及苹果的产品ID(自己定义的,类似于com.******.******)
4.正式和苹果服务器对接。
验证是否存在该件商品
-(void)requestProductID:(NSString *)productID{
// 1.拿到所有可卖商品的ID数组
NSArray *productIDArray = [[NSArray alloc]initWithObjects:productID, nil];
NSSet *sets = [[NSSet alloc]initWithArray:productIDArray];
// 2.向苹果发送请求,请求所有可买的商品
// 2.1.创建请求对象
SKProductsRequest *sKProductsRequest = [[SKProductsRequest alloc]initWithProductIdentifiers:sets];
// 2.2.设置代理(在代理方法里面获取所有的可卖的商品)
sKProductsRequest.delegate = self;
// 2.3.开始请求
[sKProductsRequest start];
}
苹果内购监听
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSLog(@"可卖商品的数量=%ld",response.products.count);
NSArray *product = response.products;
if([product count] == 0){
NSLog(@"没有商品");
return;
}
for (SKProduct *sKProduct in product) {
NSLog(@"pro info");
NSLog(@"SKProduct 描述信息:%@", sKProduct.description);
NSLog(@"localizedTitle 产品标题:%@", sKProduct.localizedTitle);
NSLog(@"localizedDescription 产品描述信息:%@",sKProduct.localizedDescription);
NSLog(@"price 价格:%@",sKProduct.price);
NSLog(@"productIdentifier Product id:%@",sKProduct.productIdentifier);
if([sKProduct.productIdentifier isEqualToString:self.selectProductID]){
[self buyProduct:sKProduct];
break;
}else{
//NSLog(@"不不不相同");
}
}
}
内购的代码调用
-(void)buyProduct:(SKProduct *)product{
// 1.创建票据
SKPayment *skpayment = [SKPayment paymentWithProduct:product];
// 2.将票据加入到交易队列
[[SKPaymentQueue defaultQueue] addPayment:skpayment];
}
实现观察者监听付钱的代理方法,只要交易发生变化就会走下面的方法
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
/*
SKPaymentTransactionStatePurchasing, 正在购买
SKPaymentTransactionStatePurchased, 已经购买
SKPaymentTransactionStateFailed, 购买失败
SKPaymentTransactionStateRestored, 回复购买中
SKPaymentTransactionStateDeferred 交易还在队列里面,但最终状态还没有决定
*/
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:{
[SVProgressHUD show];
NSLog(@"正在购买");
}break;
case SKPaymentTransactionStatePurchased:{
[SVProgressHUD dismiss];
NSLog(@"购买成功");
// 购买后告诉交易队列,把这个成功的交易移除掉
[queue finishTransaction:transaction];
[self buyAppleStoreProductSucceedWithPaymentTransactionp:transaction];
}break;
case SKPaymentTransactionStateFailed:{
[SVProgressHUD dismiss];
NSLog(@"购买失败");
// 购买失败也要把这个交易移除掉
[queue finishTransaction:transaction];
}break;
case SKPaymentTransactionStateRestored:{
NSLog(@"回复购买中,也叫做已经购买");
[SVProgressHUD dismiss];
// 回复购买中也要把这个交易移除掉
[queue finishTransaction:transaction];
}break;
case SKPaymentTransactionStateDeferred:{
[SVProgressHUD dismiss];
NSLog(@"交易还在队列里面,但最终状态还没有决定");
}break;
default:
break;
}
}
}
苹果内购支付成功
- (void)buyAppleStoreProductSucceedWithPaymentTransactionp:(SKPaymentTransaction *)paymentTransactionp {
NSString * productIdentifier = paymentTransactionp.payment.productIdentifier;
NSLog(@"productIdentifier Product id:%@", productIdentifier);
NSString *transactionReceiptString= nil;
//系统IOS7.0以上获取支付验证凭证的方式应该改变,切验证返回的数据结构也不一样了。
NSString *version = [UIDevice currentDevice].systemVersion;
if([version intValue] >= 7.0){
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURLRequest * appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle]appStoreReceiptURL]];
NSError *error = nil;
NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];
transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}else{
NSData * receiptData = paymentTransactionp.transactionReceipt;
// transactionReceiptString = [receiptData base64EncodedString];
transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}
// 去验证是否真正的支付成功了
[self checkAppStorePayResultWithBase64String:transactionReceiptString];
//[self verifyTransactionResult];
}
给后端传递苹果的票据已经订单号,后端进行验证以及发放商品
- (void)checkAppStorePayResultWithBase64String:(NSString *)base64String {
/* 生成订单参数,注意沙盒测试账号与线上正式苹果账号的验证途径不一样,要给后台标明 */
/*
注意:
自己测试的时候使用的是沙盒购买(测试环境)
App Store审核的时候也使用的是沙盒购买(测试环境)
上线以后就不是用的沙盒购买了(正式环境)
所以此时应该先验证正式环境,在验证测试环境
正式环境验证成功,说明是线上用户在使用
正式环境验证不成功返回21007,说明是自己测试或者审核人员在测试
*/
/*
苹果AppStore线上的购买凭证地址是: https://buy.itunes.apple.com/verifyReceipt
测试地址是:https://sandbox.itunes.apple.com/verifyReceipt
*/
// NSNumber *sandbox;
NSString *sandbox;
#if (defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))
//sandbox = @(0);
sandbox = @"0";
#else
//sandbox = @(1);
sandbox = @"1";
#endif
NSMutableDictionary *prgam = [[NSMutableDictionary alloc] init];;
[prgam setValue:base64String forKey:@"receiptData"];
[prgam setValue:self.orderID forKey:@"out_trade_no"];
[MRequestVideoDataTool requestApplepayNotifyWith:prgam andReturnData:^(id _Nonnull result) {
}];
/*
请求后台接口,服务器处验证是否支付成功,依据返回结果做相应逻辑处理
0 代表沙盒 1代表 正式的内购
最后最验证后的
*/
/*
内购验证凭据返回结果状态码说明
21000 App Store无法读取你提供的JSON数据
21002 收据数据不符合格式
21003 收据无法被验证
21004 你提供的共享密钥和账户的共享密钥不一致
21005 收据服务器当前不可用
21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
*/
NSLog(@"字典==%@",prgam);
}
注意事项:验证最好放在平台的后端做验证(保证交易的安全性)。如果查询不到商品请查看自己开发者账号关于税收模块的信息是否填写完整,是否通过了苹果的审核,2020年关于这一块的审核流程很快,大概一两个小时。正式通过这之后在做沙箱测试。否则查询不到商品,无法完成购买。苹果审核期间所需的还是沙箱测试,这个需要自己做好开关,提审的时候需要提供沙箱测试账号。