iOS内购你看我就够了(一)
程序员文章站
2024-01-14 22:47:34
...
内购坑多,
开始(建议先去看些入门的)
@import StoreKit;
#import "IAPManager.h"
@implementation IAPManager
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[IAPManager alloc] init];
});
return sharedInstance;
}
单利的入口,传进来一个后台得到的商品ID(在苹果网站注册的)
- (void)payBtnPressed:(NSString *)product_id {//这传进来个商品id,lzc
if ([SKPaymentQueue canMakePayments])//是否允许应用内付费
{
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:product_id]];
request.delegate = self;
[request start];
}else
DLog(@"用户不允许内购");//提示框
}
// 查询成功后的回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
//这里菊花消失
DLog(@"菊花消失");
NSArray *products = response.products;
if (products.count != 0) {
self.product = products[0];
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:self.product];//lzc 改
payment.applicationUsername = @(1000000).stringValue;//充值用户的id,也就是uid.
[[SKPaymentQueue defaultQueue] addPayment:payment];//发起购买
当然还有监听,这个东西写在程序入口比较好,至于为何下次讲
}
if (products.count == 0){
DLog(@"无法获取商品");
}
}
//查询失败后的回调
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
//菊花消失
DLog(@"请求苹果服务器失败%@",[error localizedDescription]);
}
下边就是监听结果了
//监听购买结果,每个状态下都要结束订单,否则就坑爹了
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {//当用户购买的操作有结果时,就会触发下面的回调函数,
//菊花消失
DLog(@"来监听购买结果吧");
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased://交易成功
[self completeTransaction:transaction];//验证
//如果用户在这中间退出,咋办??不知道的看下一篇,坑坑坑都是坑
DLog(@"结束订单了");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];//验证成功与否,咱们都注销交易,否则会出现虚假凭证信息一直验证不通过..每次进程序都得输入苹果账号的情况
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];//交易失败方法
break;
case SKPaymentTransactionStateRestored://已经购买过该商品
DLog(@"已经购买过");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];//消耗型不支持恢复,所以我就不写了
break;
case SKPaymentTransactionStatePurchasing:
DLog(@"已经在商品列表中");//菊花
break;
case SKPaymentTransactionStateDeferred:
DLog(@"最终状态未确定 ");
break;
default:
break;
}
}
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if(transaction.error.code != SKErrorPaymentCancelled) {
NSLog(@"购买失败");
} else {
NSLog(@"用户取消交易");
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
下边就是和服务器验证凭证了,重点坑在这里
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
if (self.cash != nil) { //self.cash这玩意我是点击商品后传进来的,所以通过它判断是不是漏单的,有他的话就走正常流程
DLog(@"购买成功验证订单");
NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
NSString *a = [data base64EncodedStringWithOptions:0];
NSLog(@"base64JSONString =---%@---",a);//得到凭证
NSDictionary * dic = @{@"uid":用户id,
@"receipt":a,
还有后台要的其他东西,起码凭证和用户id是必须的吧};
DLog(@"验证信息%@",dic);
//存起来
[self addDicToPayAry:dic];//先把这个信息存起到本地,这是你埋坑的第一步,有空再解释
[self testForServer:dic];//和后台去二次验证,这个很必要
}
else
{
DLog(@"漏单流程从本地取凭证去验证");
[self checkUnTestReceipt];//从本地取凭证验证去,下篇分解
}//不是点击cell 进来的,也就是说上次订单没结束,日狗去吧
}
服务器交互,只要服务器有反应咱就把本地的信息移除,因为验证成功删了正常,验证不成功说明凭证有假(当然也可能苹果出问题,这咱管不了了)删,咱这边服务器出毛病(我们后台说这个状态是后台验证过了但是没有发商品,用户找客服),删.
只有没和自己后台交互上的时候,我们就在本地找村过的凭证,有的话说明有没验证过的,咱继续验证.没的话(第一次也不会没,因为存过一次但是就没删过)说明都验证过了.总之这个过程不管怎么样都要结束订单.
- (void)testForServer:(NSDictionary *)dic
{
WEAKSELF;
[[NetWorkManager sharedInstance]postJsonData:dic url:url successBlock:^(id responseBody) {
DLog(@"支付成功%@",responseBody);
if ([responseBody[@"code"]isEqualToNumber:@(200)]) {
DLog(@"1验证成功完成交易OKOKOKOK");
if (weakSelf.paySuccessBlock){
weakSelf.paySuccessBlock();//告诉外边UI做处理
}
[weakSelf removeDicFromPayAry:dic];//从本地移除凭证等信息dic
}
if (验证receipt-data失败) {
DLog(@"1验证receipt-data失败");
[weakSelf removeDicFromPayAry:dic];//移除
}
if (我们服务器有毛病) {
[weakSelf removeDicFromPayAry:dic];
DLog(@"1你去找客服吧我们服务器有毛病");
}
// DLog(@"我结束订单了-----");
} failureBlock:^(NSString *error) {
DLog(@"%@和自己服务器交互失败11",error);
[weakSelf checkUnTestReceipt];//和自己后台没联系上,所以要检查本地有没有存过的凭证,有的话继续验证.下篇详聊
}];
}
篇幅问题,存凭证删凭证和再次验证凭证下次说.
还有订单没结束的坑(用户买成功了苹果服务器不给力,用户急脾气关应用了,订单还没结束)等等,下回分解.
8.25更,来埋坑了,点进来↓
iOS内购第二篇
感觉还是不太完美啊,先这样吧
上一篇: OC语言day04-09构造方法练习
下一篇: OC内存管理
推荐阅读