apple Developer console 에 앱 등록이 되어 있다는 가정하에 설명한다.
우선 인앱상품등록 부터 준비한다. (앱 업로드는 하지 않아도 샌드박스 결제테스트가 가능하다.)
여기까지 인앱결제 개발을 위한 준비가 끝났다.
BillingManager.h
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BillingManager : NSObject<SKProductsRequestDelegate,SKPaymentTransactionObserver>
{
NSString *productID;
}
+ (instancetype)getInstance;
@property (nonatomic) NSArray *productList;
- (void)setupBilling:(NSArray*)arr;
- (void)purchase:(NSString*)pid;
- (BOOL)canMakePurchases;
- (float)getPrice:(NSString*)pid;
- (NSString*)getPriceCurrencyCode:(NSString*)pid;
- (SKProduct*)getSKProduct:(NSString*)pid;
@end
NS_ASSUME_NONNULL_END
BillingManager.m
#import "BillingManager.h"
@implementation BillingManager
+ (instancetype)getInstance {
static BillingManager *shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [[BillingManager alloc] init];
});
return shared;
}
- (void)setupBilling:(NSArray *)arr
{
_productList = arr;
NSMutableArray* tempArr = [NSMutableArray array];
for(RespAppInApp *item in _productList)
{
[tempArr addObject:item.ProductID];
}
NSSet *productIdentifiers = [NSSet setWithArray:tempArr];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (float)getPrice:(NSString *)pid
{
for(SKProduct *skProduct in _productList)
{
if ([skProduct.productIdentifier isEqualToString:pid])
{
return [skProduct.price floatValue];
}
}
return 0;
}
- (NSString*)getPriceCurrencyCode:(NSString *)pid
{
for(SKProduct *skProduct in _productList)
{
if ([skProduct.productIdentifier isEqualToString:pid])
{
return skProduct.priceLocale.currencyCode;
}
}
return @"";
}
- (SKProduct*)getSKProduct:(NSString *)pid
{
for(SKProduct *item in _productList)
{
if([item.productIdentifier isEqualToString:pid] == YES)
return item;
}
return nil;
}
- (BOOL)canMakePurchases {
return [SKPaymentQueue canMakePayments];
}
- (void)purchase:(NSString *)pid
{
productID = pid;
if (_productList != nil)
{
if ([self canMakePurchases])
{
SKProduct *skProduct = [self getSKProduct:pid];
if(skProduct != nil)
{
SKPayment *skPayment = [SKPayment paymentWithProduct:skProduct];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:skPayment];
}else{
NSLog(@"Product is null");
}
} else {
NSLog(@"No Purchases");
}
}
}
- (NSString *)getReceiptCode
{
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) {
NSLog(@"no receipt");
return nil;
} else {
// Get the receipt in encoded format
NSString *encodedReceipt = [receipt base64EncodedStringWithOptions:0];
return encodedReceipt;
}
}
#pragma mark - StoreKit Delegate
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(@"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
{
long long milliseconds = (long long)(transaction.transactionDate.timeIntervalSince1970 * 1000.0);
NSString *purchaseTime = [NSString stringWithFormat:@"%lld", milliseconds];
NSLog(@"%lld", milliseconds);
NSLog(@"purchaseTime : %@", purchaseTime);
NSLog(@"transactionIdentifier : %@", transaction.transactionIdentifier);
NSLog(@"productIdentifier : %@", transaction.payment.productIdentifier);
NSLog(@"quantity : %@", [@(transaction.payment.quantity) stringValue]);
NSLog(@"getReceiptCode : %@", [self getReceiptCode]);
NSLog(@"Purchase completed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Restored");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"Purchase failed %@", transaction.error);
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateDeferred:
{
break;
}
default:
break;
}
}
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSUInteger count = [response.products count];
if (count > 0) {
_productList = response.products;
for(SKProduct *skProduct in _productList)
{
NSLog(@"Found product: %@ – Product: %@ – Price: %0.2f", skProduct.productIdentifier, skProduct.localizedTitle, skProduct.price.floatValue);
}
} else {
NSLog(@"No product or complete contract and tax financial transaction items.");
}
}
@end
-(void)verifyReceipt
{
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) {
NSLog(@"no receipt info");
}
// Create the JSON object that describes the request
NSError *error;
NSDictionary *requestContents = @{
@"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
if (!requestData) {
NSLog(@"%@", error);
}
// Create a POST request with the receipt data.
// https://sandbox.itunes.apple.com/verifyReceipt , https://buy.itunes.apple.com/verifyReceipt
NSURL *storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
[[NSURLSession sharedSession] dataTaskWithRequest:storeRequest
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error)
{
if(error)
{
NSLog(@"%@", error);
}else{
NSError *error;
NSDictionary *respDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!respDict) {
NSLog(@"%@", error);
}
NSLog(@"%@", respDict);
}
}];
}