[ios] IAP 기본 프로세스

IAP 기본 프로세스

인-앱 구매 상품들 나열하기

NSSet<NSString *> * productIdentifiers = [NSSet setWithArray: @[@"com.smart.product1", @"com.smart.product2", @"com.smart.product3"]];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers: productIdentifiers];
let productIdentifiers: Set<String> = []
let productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
//IAPHelper.h
@interface IAPHelper : NSObject <SKProductsRequestDelegate>

//IAPHelper.m
@implementation IAPHelper

- (void)requestFunctionExample 
{
    NSSet<NSString *> *productIdentifiers = [NSSet setWithArray: @[@"com.smart.product1", @"com.smart.product2", @"com.smart.product3"]];
    SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers: productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}
class IAPManager: SKProductsRequestDelegate {}

extension IAPManager {
	func requestFunctionExample() {
		let productIdentifiers: Set<String> = []
		let productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)								
		productsRequest.delegate = self
		protuctsRequest.start()
	}
}
//success
- (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response
{
    NSLog(@"Loaded list of products...");
    NSArray<SKProduct *> *products = [response products];
    
    for (SKProduct *product in products)
    {
        NSLog(@"Found Product: %@ %@ %f", [product productIdentifier], [product localizedTitle], [[product price] floatValue]);
    }
}

//fail
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"%@", [error localizedDescription]);
}
//success
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    print("Loaded list of products...")
    let products: [SKProduct] = response.products
    for product in products {
      print("Found product: \(product.productIdentifier) \(product.localizedTitle) \(product.price.floatValue)")
    }
}

//fail
public func request(_ request: SKRequest, didFailWithError error: Error) {
    print("Error: \(error.localizedDescription)")
}

인앱 구매 상품 구매 기능

// IAPHelper.h
@interface IAPHelper : NSObject <SKPaymentTransactionObserver>

// IAPHelper.m
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
    // ...
}
class IAPManager: SKPaymentTransactionObserver {
	paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])	{
		//...
	}
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        [[SKPaymentQueue defaultQueue] addTransactionObserver: self];
    }
    return self;
}
SKPaymentQueue.default().add(self)
SKPayment *payment = [SKPayment paymentWithProduct: product];
[[SKPaymentQueue defaultQueue] addPayment: payment];
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
    for (SKPaymentTransaction *paymentTransaction in transactions)
    {
        switch ([paymentTransaction transactionState]) {
            case SKPaymentTransactionStatePurchased:
                [self complete: paymentTransaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self fail: paymentTransaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restore: paymentTransaction];
                break;
            case SKPaymentTransactionStateDeferred:
                break;
            case SKPaymentTransactionStatePurchasing:
                break;;
        }
    }
}
- (void)complete:(nonnull SKPaymentTransaction *) transaction
{
    [self deliverPurchaseNotificationFor: [[transaction payment] productIdentifier]];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
//Just Example 
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
      switch (transaction.transactionState) {
      case .purchased:
        complete(transaction: transaction)
        break
      case .failed:
        fail(transaction: transaction)
        break
      case .restored:
        restore(transaction: transaction)
        break
      case .deferred:
        break
      case .purchasing:
        break
      }
    }
}
//Just Example 
private func complete(transaction: SKPaymentTransaction) {
    print("complete...")
    deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
    SKPaymentQueue.default().finishTransaction(transaction) 
    // finishTransaction을 호출해 트랜젝션을 완료시키고, 큐에서 transaction 객체를 제거시킨다. 
}

구매 기록 복원하기

복원 버튼을 누르면 아래 코드처럼 SKPaymentQueue 객체를 이용해 구매 기록들을 복원합니다. 그 이후에 IAPManager가 Observer로서 복원 상태(.restored)의 SKPaymentTransaction객체를 처리하면 됩니다.

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
SKPaymentQueue.default().restoreCompletedTransactions()

상품 구매 Permissions

특정 유저의 폰이나 계정은 구매가 허가되지 않습니다. 예를 들어, 부모가 아이의 폰이나 계정을 구매 불가하는 경우입니다. 애플은 이 상황을 매우 아름답게 구현시켰습니다. SKPaymentQueue.canMakePayments() 의 (Bool)값이 true이면 구매 가능한 앱/계정이고, false이면 구매 가능하지 않은 앱/계정입니다. 따라서 이 값에 따라 구매 상품의 구매 유무를 표시하십시오.

[SKPaymentQueue canMakePayments];
SKPaymentQueue.canMakePayments()