-
在接入微信支付和支付宝支付后被苹果拒绝了。审核条例 3.1.1 -In-App-Purchase。所以就研究了一波苹果内支付。
下面只是代码部分,iTunes上面的协议领导解决了。
第一步在工程中打开应用内支付,如下图:
image.png
然后在你的购买界面导入库:
#import <StoreKit/StoreKit.h>
购买界面添加2个代理:
<SKPaymentTransactionObserver,SKProductsRequestDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
// 苹果内购
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
在你点击购买的事件中:
if([SKPaymentQueue canMakePayments]){
// 这里需要时间比较长,所以加一个菊花
[WINDOW addSubview:self.hubView]; // 这个可以不管。
[self requestProductData:self.currentProId]; // self.currentProId 这个是你正在购买的商品的ID,在iTunes Connect上面。我这边是在工程中加了宏定义,不过是从上个界面传过来的。
}else{
NSLog(@"不允许程序内付费");
}
接下来就是对代理方法的处理:<SKPaymentTransactionObserver,SKProductsRequestDelegate>
当然这些代码网上都大同小异,我也是看了很多代码(英文文档看的头疼)
//去苹果服务器请求商品
- (void)requestProductData:(NSString *)type{
NSLog(@"请求对应的产品信息");
NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
[request start];
}
/// 苹果那边给的回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
// 收到苹果的回调之后菊花消失
// [self.hubView removeFromSuperview];
NSLog(@"收到产品反馈信息");
NSArray *myProduct = response.products;
NSLog(@"产品Pro ID:%@",response.invalidProductIdentifiers);
NSLog(@"产品数量: %d", (int)[myProduct count]); // 当然我这里的数组只有一个商品
SKProduct *pro = nil;
for(SKProduct *product in myProduct){
NSLog(@"Product id: %@" , product.productIdentifier);
if ([product.productIdentifier isEqualToString:self.currentProId]) {
pro = product;
}
}
// 找到你想要的商品,那么就将这个商品加入购买队列。
if (pro != nil) {
SKPayment *payment = [SKPayment paymentWithProduct:pro];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
/// 购买状态的回调
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:{//交易完成
[[SKPaymentQueue defaultQueue] finishTransaction: transaction]; // 购买完成之后一定要移除队列
// 验证是否购买成功
[self verifyPurchaseWithPaymentTransaction:transaction];
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@""
message:@"购买成功"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView show];
} break;
case SKPaymentTransactionStateFailed://交易失败
{ [self failedTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction]; // 购买完成之后一定要移除队列
UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"购买失败,请重新尝试购买"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView2 show];
}break;
case SKPaymentTransactionStateRestored://已经购买过该商品
NSLog(@"已经购买过该商品");
case SKPaymentTransactionStatePurchasing://商品添加进列表
NSLog(@"商品添加进列表");
break;
default:
break;
}
}
}
// 验证购买成功的方法
-(void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)paymentTransactionp{
// NSString * productIdentifier = paymentTransactionp.payment.productIdentifier; // 商品id
// 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 verifyInAppPurchaseWithReceipt:transactionReceiptString];
}
// 自己后台校验的方法实现
// 我们后台校验
- (void)verifyInAppPurchaseWithReceipt: (NSString *)receipt {
NSString * userId = [USERDEFAULTS objectForKey:@"account"];
NSString * isSandbox = nil;
#ifdef DEBUG
isSandbox = @"true";
#else
isSandbox = @"false";
#endif
// 下面就是你去调用后台的接口,根据返回成功或失败来处理相应的UI和逻辑。
// isSandbox 给后台判断是否是沙盒测试。当然这是后台的事情,你也不用管。
//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
}
// 一些失败的回调
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
[AlertView alertViewWithTitle:[NSString stringWithFormat:@"%@",[error localizedDescription]]]; // 一个弹窗
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
NSLog(@"交易失败");
if (transaction.error.code != SKErrorPaymentCancelled){
// code
}
// [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
// 最后移除监听*************************************这一步我要重点说一下我遇到的坑
-(void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//移除监听
}
在最后一步移除监听的时候,有个问题。就是在页面切换后这个dealloc不走。。
*************不走会导致你购买过的商品还会出现在商品列表中**************
反正这个很烦就是了。
那么问题来了,为啥他不走呢?
我的理解是:
****** 在block 中有self.语法导致循环引用。没有走dealloc。*****
然后我不管了。反正我这个商品只需要他购买一次。在切换页面的时候强行移除监听就完事了。
所以我将移除监听的方法写到了viewwilldisappear中。。不要骂我。当然需求决定你该怎么处理。
下面给大家一些链接吧。这些都是有iTunesConnect中的设置。
https://www.2cto.com/kf/201605/513647.html
http://www.jianshu.com/p/c252b2ccb078
当然也得谢谢上面2个文章的作者
-- 来自涛胖子的工作笔记
网友评论