最近遇到App需要开发订阅功能,查了很多资料,参考了很多,结合自己了解的,还是记录下来。
原理如下
逻辑1
1.1,App启动的时候,做订阅过的监听(如下的代码)
-(void)addObserver
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
1.2,收到订阅的记录后,同步数据至服务器,服务器处理后,修改用户时间等其它数据
1.3,刷新UI,显示订阅成功后的UI
逻辑2
2.1 未订阅状态,点击UI区域,订阅
// 1.创建票据
SKPayment *payment = [SKPayment paymentWithProduct:self.buyProduct];
// 2.将票据加入到交易队列中
[[SKPaymentQueue defaultQueue] addPayment:payment];
2.2 订阅成功后,同步至服务器(同理1.2)
2.3 刷新UI,显示订阅成功后的UI(同理1.3)
订阅成功,校验地址
正式验证api地址
https://buy.itunes.apple.com/verifyReceipt
沙箱验证api地址
https://sandbox.itunes.apple.com/verifyReceipt
下面上一下简单代码
IAPManager.h
@interface IAPManager : NSObject
+ (instancetype)manager;
//添加监听
-(void)addObserver;
//直接购买
-(void)buyServers:(void(^)(BOOL succ))block;
// 恢复购买
- (void)restore;
@end
IAPManager.m
#import "IAPManager.h"
#import <StoreKit/StoreKit.h>
#import "UserRequest.h"
@interface IAPManager ()<SKPaymentTransactionObserver, SKProductsRequestDelegate>
@property (nonatomic, strong) SKProductsRequest *request;
@property (nonatomic, strong) SKProduct *buyProduct;
@property (nonatomic, copy) void(^buyBlock)(BOOL succ);
@property (nonatomic, strong) UserRequest *userRequest;
@property (nonatomic, retain) dispatch_group_t group;
@property (nonatomic, retain) dispatch_queue_t groupQueue;
@end
static IAPManager *manager = nil;
@implementation IAPManager
+ (instancetype)manager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [self new];
});
return manager;
}
-(id)init
{
if (self = [super init]) {
}
return self;
}
-(void)addObserver
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
// 请求可卖的商品
- (void)requestProducts
{
if (![SKPaymentQueue canMakePayments]) {
// 您的手机没有打开程序内付费购买
return;
}
[HUD show];
// 3.获取productid的set(集合中)
NSSet *set = [NSSet setWithArray:@[@"SmartStickOneMonth"]];
// 4.向苹果发送请求,请求可卖商品
_request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
_request.delegate = self;
[_request start];
}
-(void)buyServers:(void (^)(BOOL))block
{
if (![SKPaymentQueue canMakePayments]) {
//您的手机没有打开程序内付费购买
if (block) {
block(NO);
}
return;
}
self.buyBlock = block;
if (self.buyProduct != nil) {
[self addPayment];
return;
}
// 3.获取productid的set(集合中)
NSSet *set = [NSSet setWithArray:@[@"SmartStickOneMonth"]];
// 4.向苹果发送请求,请求可卖商品
_request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
_request.delegate = self;
[_request start];
}
/**
* 当请求到可卖商品的结果会执行该方法
*
* @param response response中存储了可卖商品的结果
*/
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
for (SKProduct *product in response.products) {
// 用来保存价格
NSMutableDictionary *priceDic = [NSMutableDictionary dictionary];
// 货币单位
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
// 带有货币单位的价格
NSString *formattedPrice = [numberFormatter stringFromNumber:product.price];
[priceDic setObject:formattedPrice forKey:product.productIdentifier];
NSLog(@"价格:%@", product.price);
NSLog(@"标题:%@", product.localizedTitle);
NSLog(@"秒速:%@", product.localizedDescription);
NSLog(@"productid:%@", product.productIdentifier);
}
self.buyProduct = [response.products firstObject];
}
/// 请求商品结束
/// @param request 请求对象
-(void)requestDidFinish:(SKRequest *)request
{
[self addPayment];
}
/// 请求商品失败
/// @param request 请求对象
/// @param error 错误信息
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
//购买失败
if (self.buyBlock) {
self.buyBlock(NO);
}
}
#pragma mark - 购买商品
-(void)addPayment
{
// 1.创建票据
SKPayment *payment = [SKPayment paymentWithProduct:self.buyProduct];
// 2.将票据加入到交易队列中
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark - 实现观察者回调的方法
/**
* 当交易队列中的交易状态发生改变的时候会执行该方法
*
* @param transactions 数组中存放了所有的交易
*/
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
SKPaymentTransaction *lastTransaction = nil;
/*
SKPaymentTransactionStatePurchasing, 正在购买
SKPaymentTransactionStatePurchased, 购买完成(销毁交易)
SKPaymentTransactionStateFailed, 购买失败(销毁交易)
SKPaymentTransactionStateRestored, 恢复购买(销毁交易)
SKPaymentTransactionStateDeferred 最终状态未确定
*/
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(@"用户正在购买");
break;
case SKPaymentTransactionStatePurchased:
{
NSLog(@"购买完成----->id:%@==oriID:%@", transaction.transactionIdentifier, transaction.originalTransaction.transactionIdentifier);
lastTransaction = transaction;
//处理可以一个一个处理(我选择了直接校验最后一个了)
//[self buySuccessWithTransaction:lastTransaction];
}
break;
case SKPaymentTransactionStateFailed:
//购买失败
if (self.buyBlock) {
self.buyBlock(NO);
}
NSLog(@"购买失败");
[queue finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"恢复购买");
//TODO:向服务器请求补货,服务器补货完成后,客户端再完成交易单子
[queue finishTransaction:transaction];
break;
case SKPaymentTransactionStateDeferred:
NSLog(@"最终状态未确定");
//购买失败
if (self.buyBlock) {
self.buyBlock(NO);
}
break;
default:
break;
}
}
//直接传最后一个交易凭证至服务器就行
if (lastTransaction != nil) {
[self buySuccessWithTransaction:lastTransaction];
}
}
/// 购买成功
/// @param transaction 订阅凭证对象
-(void)buySuccessWithTransaction:(SKPaymentTransaction *)transaction
{
NSString *origID = transaction.originalTransaction.transactionIdentifier;
NSString *tranID = transaction.transactionIdentifier;
//第一次购买,origID=null (单独处理一样)
if (!origID && tranID) {
origID = tranID;
}
if (!origID && !tranID) {
return;
}
NSURL * receiveUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData * receiveData = [NSData dataWithContentsOfURL:receiveUrl];
NSString *receiveString = [receiveData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
dispatch_group_enter(self.group);
dispatch_group_async(self.group, self.groupQueue, ^{
[self.userRequest subscribeWithOriginalID:origID transactionID:tranID receiveString:receiveString block:^(BOOL succ, NSString *msg, id data) {
dispatch_group_leave(self.group);
if (self.buyBlock) {
self.buyBlock(YES);
}
}];
});
}
/// 观察购买
-(void)addObserverBuyStatePurchased
{
dispatch_group_notify(self.group, self.groupQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"这里写请求完成之后的处理");
});
});
}
// 恢复购买
- (void)restore
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
// 恢复失败
NSLog(@"恢复失败");
}
-(UserRequest *)userRequest
{
if (_userRequest == nil) {
_userRequest = [[UserRequest alloc] init];
}
return _userRequest;
}
// 取消请求商品信息
- (void)dealloc {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[_request cancel];
}
@end