首先介紹實現(xiàn)蘋果內(nèi)購的流程
購買
1.向蘋果服務(wù)器 請求商品列表
2.蘋果服務(wù)器 在回調(diào)中返回商品列表
3.向蘋果服務(wù)器 請求購買商品列表的第一個
4.蘋果服務(wù)器 在回調(diào)中返回購買結(jié)果
5.根據(jù)回調(diào)的結(jié)果 進行處理
恢復購買
1.向蘋果服務(wù)器 請求恢復購買
2.蘋果服務(wù)器 在回調(diào)中返回恢復購買結(jié)果
5.根據(jù)回調(diào)的結(jié)果 進行處理
下面是代碼實現(xiàn)
下面是.h文件的實現(xiàn)
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PQIAPManager : NSObject
+ (PQIAPManager *)sharedManager;
/**請求購買商品*/
- (void)requestProductWithId:(NSString *)productId;
/**請求恢復購買*/
- (void)restore;
@end
NS_ASSUME_NONNULL_END
下面是.m文件的實現(xiàn)
#import "PQIAPManager.h"
#import <StoreKit/StoreKit.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <AdSupport/AdSupport.h>
/**共享密鑰*/
#define KSecretKey @""
/**憑證校驗地址*/
#define KReceiptCheckUrl @""
/**訂閱狀態(tài)檢驗地址*/
#define KStateCheckUrl @""
@interface PQIAPManager()<SKPaymentTransactionObserver,SKProductsRequestDelegate,SKRequestDelegate>
// 交易是否結(jié)束
@property (nonatomic, assign) BOOL isRequestFinished;
// 判斷是購買還是恢復
@property (nonatomic, assign) BOOL isRestore;
@end
@implementation PQIAPManager
// 單例
+ (instancetype)sharedManager{
static dispatch_once_t pred;
static PQIAPManager *manager = nil;
dispatch_once(&pred, ^{
manager = [[self alloc] init];
});
return manager;
}
// 創(chuàng)建時就開始監(jiān)聽購買事件
- (instancetype)init{
if (self = [super init]) {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
self.isRequestFinished = YES;
}
return self;
}
// 銷毀時就移除監(jiān)聽事件
- (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
繼續(xù)在.m文件中添加方法
/**請求商品列表*/
- (void)requestProductWithId:(NSString *)productId {
self.isRestore = NO;
if (self.isRequestFinished) {
if ([SKPaymentQueue canMakePayments]) { //用戶允許app內(nèi)購
if (productId.length) {
self.isRequestFinished = NO; //正在請求
NSLog(@"%@商品正在請求中...",productId);
NSArray *product = [[NSArray alloc] initWithObjects:productId, nil];
NSSet *set = [NSSet setWithArray:product];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
productsRequest.delegate = self;
[productsRequest start];
}
} else { //沒有權(quán)限
self.isRequestFinished = YES; //完成請求
NSLog(@"沒有購買權(quán)限");
}
} else {
NSLog(@"上次請求購買未完成营勤,請稍后重試唯咬!");
}
}
// 請求購買商品列表的第一個
#pragma mark SKProductsRequestDelegate 請求商品列表后的回調(diào)
- (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response {
NSArray *product = response.products;
if (product.count == 0){
return;
} else {
if (response.invalidProductIdentifiers.count) {
NSLog(@"商品請求錯誤,error:%@", response.invalidProductIdentifiers);
}
NSLog(@"商品詳情:%@",[product[0] description]);
NSLog(@"商品價格:%@",[product[0] price]);
NSLog(@"商品名字:%@",[product[0] productIdentifier]);
// 請求購買
SKPayment *payment = [SKPayment paymentWithProduct:product[0]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
// 處理請求購買后的回調(diào)
#pragma mark - SKProductsRequestDelegate 請求購買后的回調(diào)
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
if (!self.isRestore) {
for (SKPaymentTransaction *tran in transactions) {
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchasing: // 正在交易
break;
case SKPaymentTransactionStatePurchased: // 交易完成
[self completeTransaction:tran];
if (tran.originalTransaction) {
// 如果是自動續(xù)費的訂單,originalTransaction會有內(nèi)容
if (tran.originalTransaction.transactionIdentifier) {
NSLog(@"自動續(xù)費的訂單ID = %@",tran.originalTransaction.transactionIdentifier);
[self saveOrderId:tran.originalTransaction.transactionIdentifier];
}
} else {
// 普通購買籽腕,以及第一次購買自動訂閱
if (tran.transactionIdentifier) {
NSLog(@"普通購買昵观,以及第一次購買自動訂閱ID = %@",tran.transactionIdentifier);
[self saveOrderId:tran.transactionIdentifier];
}
}
NSLog(@"購買完成,正在校驗購買憑證...");
[self vertifyReceipt]; // 校驗購買憑證
break;
case SKPaymentTransactionStateFailed: // 交易失敗
[self completeTransaction:tran];
NSLog(@"購買失敗!");
break;
case SKPaymentTransactionStateRestored: // 已經(jīng)購買過該商品
[self completeTransaction:tran];
NSLog(@"已經(jīng)購買過該商品血柳!");
break;
default:
break;
}
}
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
self.isRequestFinished = YES; // 請求完成
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
// 根據(jù)公司需求校驗憑證
- (void)vertifyReceipt{
NSURL * receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]]){
[self vertifyReceiptSuccess:^{
NSLog(@"校驗成功!");
} failure:^{
NSLog(@"校驗失斏住难捌!");
}];
} else {
// 如果憑證為空,則再發(fā)一次憑證請求
SKReceiptRefreshRequest *refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}];
refreshReceiptRequest.delegate = self;
[refreshReceiptRequest start];
}
}
// 如果憑證為空鸦难,需要再發(fā)一次憑證請求根吁,處理請求成功后的回調(diào)
#pragma mark - 成功請求憑證后的回調(diào)
- (void)requestDidFinish:(SKRequest *)request{
if ([request isKindOfClass:[SKReceiptRefreshRequest class]]) {
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) {
[self vertifyReceiptSuccess:^{
NSLog(@"再次請求憑證后,校驗成功合蔽!");
} failure:^{
NSLog(@"再次請求憑證后击敌,校驗失敗拴事!");
}];
}
}
}
// 校驗憑證
- (void)vertifyReceiptSuccess:(void(^)(void))success failure:(void(^)(void))failure {
NSString *receipt = [self getReceipt];
// 校驗憑證步驟需要按照你公司的需求來寫
}
// 檢驗訂單是否還在訂閱期內(nèi)
- (void)checkOrderStateSuccess:(void(^)(void))success failure:(void(^)(void))failure {
NSString *receipt = [self getOrderId];
// 檢驗訂單步驟需要按照你公司的需求來寫
}
// 獲取憑證
- (NSString *)getReceipt {
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
NSString *encodeReceiptStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
return encodeReceiptStr;
}
// 保存訂單ID
- (void)saveOrderId:(NSString *)orderId{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:orderId forKey:@"orderId"];
[defaults synchronize];
}
// 獲取訂單ID
- (NSString *)getOrderId{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults valueForKey:@"orderId"];
}
恢復購買
// 恢復購買
- (void)restore {
self.isRestore = YES;
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
// 恢復成功后的回調(diào)
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue{
if (queue.transactions.count) {
for (SKPaymentTransaction *tran in queue.transactions) {
if (tran.originalTransaction.transactionIdentifier) {
[self saveOrderId:tran.originalTransaction.transactionIdentifier];
break;
}
}
// 檢驗訂單是否還在訂閱期內(nèi)
[self checkOrderStateSuccess:^{
NSLog(@"訂單還在訂閱期沃斤,校驗成功圣蝎!");
} failure:^{
NSLog(@"訂單已過期,校驗失敽馄俊捅彻!");
}];
} else {
// 沒有可恢復的購買項
}
}
// 恢復失敗后的回調(diào)
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
// 沒有可恢復的購買項
}
最后
本篇主要講述了一個詳細的內(nèi)購流程及代碼實現(xiàn),感興趣的給個贊或者關(guān)注~~~
你們的支持就是我更新的動力0霸伞2窖汀!