Game > Gamebase > iOS SDK 사용 가이드 > 결제

여기에서는 앱에서 인앱 결제 기능을 사용하기 위해 필요한 설정 방법을 알아보겠습니다.

Gamebase는 하나의 통합된 결제 API를 제공해 게임에서 손쉽게 많은 스토어의 인앱 결제를 연동할 수 있도록 돕습니다.

Settings

Apple iTunes-Connect

  1. 테스트용 앱 빌드 업로드
  2. In-App Purchases 아이템 등록 및 승인
  3. Sandbox Tester 계정 등록
  4. Detail Guide for iTunes-Connect: Apple Guide

Gamebase Console 등록

다음은 Gamebase Console에서 설정해야 하는 내용입니다.

  1. Gamebase > Purchase(IAP) > 스토어에서 이용할 스토어를 등록합니다.
    • 스토어: App Store를 선택합니다.
  2. Gamebase > Purchase(IAP) > 상품에서 아이템을 등록합니다.
    • 상품 ID: 결제 요청 시 사용할 상품 ID를 입력합니다.
    • 상품 이름: 결제 시 표시할 상품 이름을 입력합니다.
    • 사용 여부: 아이템의 사용여부를 결정합니다.
    • 스토어: App Store를 선택합니다.
    • 스토어 아이템 ID: iTunes-Connect에 등록한 Product ID를 입력합니다.
  3. 아이템을 설정했다면, 저장을 누릅니다.

Xcode Project 설정

  1. Targets > Capabilities > In-App PurchaseON으로 설정합니다.
  2. Targets > General > Identity의 Bundle Identifier, Version, Build의 값을 알맞게 설정합니다.

Import Header File

구매 API를 구현하고자 하는 ViewController에 다음의 헤더 파일을 가져옵니다.

#import <Gamebase/Gamebase.h>

Purchase Flow

아이템 구매는 크게 결제 Flow 와 Consume Flow, 재처리 Flow 로 나누어 볼 수 있습니다. 결제 Flow는 다음과 같은 순서로 구현하시기 바랍니다.

purchase flow

  1. 이전 결제가 정상적으로 종료되지 못한 경우 재처리가 동작하지 않으면 결제가 실패합니다. 그러므로 결제 전에 requestItemListOfNotConsumedWithCompletion:를 호출하여 재처리를 동작시켜 미지급된 아이템이 있으면 Consume Flow 를 진행합니다.
  2. 게임 클라이언트에서는 Gamebase SDK의 requestPurchaseWithGamebaseProductId:viewController:completion:를 호출하여 결제를 시도합니다.
  3. 결제가 성공하였다면 requestItemListOfNotConsumedWithCompletion:를 호출하여 미소비 결제 내역을 확인한 후 지급할 아이템이 존재한다면 Consume Flow 를 진행합니다.

Consume Flow

미소비 결제 내역 목록에 값이 있으면 다음과 같은 순서로 Consume Flow 를 진행하시기 바랍니다.

purchase flow

  1. 게임 클라이언트가 게임 서버에 결제 아이템에 대한 consume(소비)을 요청합니다.
    • UserID, gamebaseProductId, paymentSeq, purchaseToken 을 전달합니다.
  2. 게임 서버는 게임 DB 에 이미 동일한 paymentSeq, purchaseToken 으로 아이템을 지급한 이력이 있는지 확인합니다.
    • 2-1. 아직 아이템을 지급하지 않았다면 UserID 에 gamebaseProductId 에 해당하는 아이템을 지급합니다.
    • 2-2. 아이템 지급 후 게임 DB 에 UserID, gamebaseProductId, paymentSeq, purchaseToken 을 저장하여 이후에 중복 지급 여부를 확인할 수 있도록 합니다.
  3. 게임 서버는 Gamebase 서버의 consume(소비) API를 호출하여 아이템 지급을 완료합니다.

Retry Transaction Flow

  • 스토어 결제에는 성공했으나 오류가 발생해 정상 종료되지 못하는 경우가 있습니다.
  • requestItemListOfNotConsumedWithCompletion:를 호출하여 재처리를 동작시켜 미지급된 아이템이 있으면 Consume Flow 를 진행하세요.
  • 재처리는 다음과 같은 시점에 호출할 것을 권장합니다.
    • 로그인 완료 후.
    • 결제 전.
    • 게임 내 상점(또는 로비) 진입시.
    • 유저 프로필 또는 우편함 확인시.

Purchase Item

구매하고자 하는 아이템의 gamebaseProductId를 이용해 다음의 API를 호출해 구매를 요청합니다.
gamebaseProductId는 일반적으로는 스토어에 등록한 아이템의 ID와 동일하지만, Gamebase 콘솔에서도 변경할 수도 있습니다. payload 필드에 입력한 추가 정보는 결제 성공 후 TCGBPurchasableReceipt.payload 필드에 유지되므로 여러가지 용도로 활용할 수 있습니다.
게임 유저가 구매를 취소하는 경우 TCGB_ERROR_PURCHASE_USER_CANCELED 오류가 반환됩니다. 취소 처리를 해 주시기 바랍니다.

API

+ (void)requestPurchaseWithGamebaseProductId:(NSString *)gamebaseProductId 
                              viewController:(UIViewController *)viewController
                                  completion:(void(^)(TCGBPurchasableReceipt *purchasableReceipt, TCGBError *error))completion;

+ (void)requestPurchaseWithGamebaseProductId:(NSString *)gamebaseProductId 
                                     payload:(NSString *)payload 
                              viewController:(UIViewController *)viewController 
                                  completion:(void(^)(TCGBPurchasableReceipt *purchasableReceipt, TCGBError *error))completion;

// Legacy API
+ (void)requestPurchaseWithItemSeq:(long)itemSeq 
                    viewController:(UIViewController *)viewController 
                        completion:(void(^)(TCGBPurchasableReceipt *purchasableReceipt, TCGBError *error))completion;

Example


- (void)purchasingItem:(NSString *)gamebaseProductId {
    NSString *userPayload = @"USER_PAYLOAD";

    [TCGBPurchase requestPurchaseWithGamebaseProductId:gamebaseProductId payload:userPayload viewController:self completion:^(TCGBPurchasableReceipt *purchasableReceipt, TCGBError *error) {
        NSString *receivedPayload = purchasableReceipt.payload;
        if ([TCGBGamebase isSuccessWithError:error] == YES) {
            // To Purchase Item Succeeded
        } else if (error.code == TCGB_ERROR_PURCHASE_USER_CANCELED) {
            // User Canceled Purchasing Item
        } else if (error) {
            // To Purchase Item Failed cause of the error
        }
    }];
}

List Purchasable Items

아이템 목록을 조회하려면 다음 API를 호출합니다. 콜백으로 반환되는 배열(array) 안에는 각 아이템들에 대한 정보가 담겨 있습니다.

- (void)viewDidLoad {
    [TCGBPurchase requestItemListPurchasableWithCompletion:^(NSArray *purchasableItemArray, TCGBError *error) {
        if (error != nil) {
            // To Request Item List Failed cause of the error
            return;
        }

        NSMutableArray *itemArrayMutable = [[NSMutableArray alloc] init];
        [purchasableItemArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            TCGBPurchasableItem *item = (TCGBPurchasableItem *)obj;

            [itemArrayMutable addObject:item];
        }];
    }];
}

List Non-Consumed Items

아이템을 구매했지만, 정상적으로 아이템이 소비(배송, 지급)되지 않은 미소비 결제 내역을 요청합니다.
미결제 내역이 있는 경우에는 게임 서버(아이템 서버)에 요청하여, 아이템을 배송(지급)하도록 처리해야 합니다..

  • 정상적으로 결제가 완료되지 못한 경우 재처리의 역할도 하므로 다음 상황에서 호출해 주세요.
    • 게임 유저에게 지급되지 못한 아이템이 남아 있는지 확인
      • 로그인 완료 후
      • 게임 내 상점(또는 로비) 진입 시
      • 유저 프로필 또는 우편함 확인 시
    • 재처리가 필요한 아이템이 있는지 확인
      • 결제 전
      • 결제 실패 후
- (void)viewDidLoad {
    [TCGBPurchase requestItemListOfNotConsumedWithCompletion:^(NSArray<TCGBPurchasableReceipt *> *purchasableReceiptArray, TCGBError *error) {
        if (error != nil) {
            // To Requesting Non-consumed Item List Failed cause of the error
            return;
        }

        // Should Deal With This Non-consumed Items.
        // Send this item list to the game(item) server for consuming item
    }];
}

List Activated Subscriptions

현재 사용자 ID 기준으로 활성화된 구독 목록을 조회합니다. 결제가 완료된 구독 상품(자동 갱신형 구독, 자동 갱신형 소비성 구독 상품)은 만료되기 전까지 계속 조회할 수 있습니다. 사용자 ID가 같다면 Android와 iOS에서 구매한 구독 상품이 모두 조회됩니다.

- (void)viewDidLoad {
    [TCGBPurchase requestActivatedPurchasesWithCompletion:^(NSArray<TCGBPurchasableReceipt *> *purchasableReceiptArray, TCGBError *error) {
        if (error != nil) {
            // To Requesting Activated Item List Failed cause of the error
            return;
        }

        // Should Deal With This Activated Items.
    }];
}

Restore Purchase

사용자의 App Store 계정으로 구매한 내역을 기준으로 구매 내역을 복원하여 콘솔에 반영합니다. 구매한 구독 상품이 조회되지 않거나 활성화되지 않을 경우 사용합니다. 만료된 결제 건을 포함해 복원된 결제 건이 결과로 반환됩니다. 자동 갱신형 소비성 구독 상품의 경우 반영되지 않은 구매 내역이 있다면 복원 후 미소비 구매 내역에서 조회할 수 있습니다.

- (void)viewDidLoad {
    [TCGBPurchase requestRestoreWithCompletion:^(NSArray<TCGBPurchasableReceipt *> *purchasableReceiptArray, TCGBError *error) {
        if (error != nil) {
            // To Requesting Restore Failed cause of the error
            return;
        }

        // Should Deal With This Restored Items.
    }];
}

Event by Promotion

주의 iOS 11 이상에서만 사용할 수 있습니다. Xcode 9.0 이상에서 빌드가 필요합니다. Gamebase 1.13.0 이상에서 지원합니다. (TOAST IAP SDK 1.6.0 이상적용)

주의 로그인 성공 이후에만 호출 할 수 있습니다. 로그인 성공 후, 다른 결제 API보다 먼저 실행되어야 합니다.

사용시 주의 사항

Facebook SDK, Google AdMob SDK 와 같이 SDK 내에 In App Purchase (AppStore 결제) 기능이 있는 경우에는 Gamebase Login 을 하기 전에 사전결제를 시작할 경우에는 정상적으로 결제창이 나타나지 않을 수 있습니다.

  • 해결 방법
  • Facebook
    • Facebook Console > 설정 > 기본 설정 > 앱 내 이벤트를 자동으로 로깅(권장) 기능을 비활성화
    • Facebook 인증 기능을 사용하지 않을 경우 : GamebaseAuthFacebookAdapter.framework 파일을 제외시킨 후 빌드

Overview

  • Apple Developer Overview : https://developer.apple.com/app-store/promoting-in-app-purchases/
  • Apple Developer Reference : https://help.apple.com/app-store-connect/#/deve3105860f

App Store 앱 내에서 아이템을 구매할 수 있는 기능을 제공합니다. 아이템 구매 성공 후, 아래의 등록해놓은 핸들러를 통하여, 아이템지급을 진행할 수 있습니다.

프로모션 IAP는 App Store Connect 에서 별도의 설정이 되어야 노출이 가능합니다.

- (void)didSuccessLogin {
    [TCGBPurchase setPromotionIAPHandler:^(TCGBPurchasableReceipt *purchasableReceipt, TCGBError *error) {
        if ([TCGBGamebase isSuccessWithError:error] == YES) {
            // To Purchase Item Succeeded
        } else if (error.code == TCGB_ERROR_PURCHASE_USER_CANCELED) {
            // User Canceled Purchasing Item
        } else if (error) {
            // To Purchase Item Failed cause of the error
        }
    }];
}

How to Test App Store Promotion IAP

주의 App Store Connect에 앱을 업로드한 다음 TestFlight를 통하여 앱을 설치 후, 테스트를 진행할 수 있습니다.

  1. TestFlight로 App을 설치합니다.
  2. 아래와 같은 URL Scheme을 호출하여, 테스트를 진행합니다.
URL Components keyname value
scheme itms-services 고정값
host & path 없음 없음
queries action purchaseIntent
bundleId 앱의 bundeld identifier
productIdentifier 구매 아이템의 product identifier

예제) itms-services://?action=purchaseIntent&bundleId=com.bundleid.testest&productIdentifier=productid.001

Process Promotion Event with GamebaseEventHandler

프로모션 결제 이벤트는 GamebaseEventHandler 를 통해서도 처리할 수 있습니다. GamebaseEventHandler 로 프로모션 결제 이벤트를 처리하는 방법은 아래 가이드를 확인하세요. Game > Gamebase > iOS SDK 사용 가이드 > ETC > Gamebase Event Handler

Error Handling

Error Error Code Description
TCGB_ERROR_NOT_SUPPORTED 10 GamebaseAdapter가 포함되지 않았습니다.
Error 객체의 도메인이 "TCGB.Gamebase.TCGBPurchase" 인 경우, PurchaseAdapter의 존재 유무를 확인해주시길 바랍니다.
TCGB_ERROR_PURCHASE_NOT_INITIALIZED 4001 Gamebase PurchaseAdapter가 초기화되지 않았습니다.
TCGB_ERROR_PURCHASE_USER_CANCELED 4002 구매가 취소되었습니다.
TCGB_ERROR_PURCHASE_NOT_FINISHED_PREVIOUS_PURCHASING 4003 이전 구매가 완료되지 않았습니다.
TCGB_ERROR_PURCHASE_NOT_ENOUGH_CASH 4004 해당 스토어의 캐쉬가 부족하여 결제할 수 없습니다.
TCGB_ERROR_PURCHASE_INACTIVE_PRODUCT_ID 4005 해당 상품이 활성화 상태가 아닙니다.
TCGB_ERROR_PURCHASE_NOT_EXIST_PRODUCT_ID 4006 존재하지 않은 GamebaseProductID로 결제를 요청하였습니다.
TCGB_ERROR_PURCHASE_NOT_SUPPORTED_MARKET 4010 지원하지 않는 스토어입니다. iOS의 지원가능한 스토어는 "AS" 입니다.
TCGB_ERROR_PURCHASE_EXTERNAL_LIBRARY_ERROR 4201 IAP 라이브러리 에러입니다.
error.message 를 확인하세요.
TCGB_ERROR_PURCHASE_UNKNOWN_ERROR 4999 정의되지 않은 구매 에러입니다.
전체 로그를 고객 센터에 올려 주시면 가능한 한 빠르게 답변 드리겠습니다.
  • 전체 오류 코드는 다음 문서를 참고하시기 바랍니다.

TCGB_ERROR_PURCHASE_EXTERNAL_LIBRARY_ERROR

  • 이 오류는 IAP 모듈에서 발생한 오류입니다.
  • 오류 코드는 다음과 같이 확인하실 수 있습니다.
TCGBError *tcgbError = error; // TCGBError object via callback
NSError *moduleError = [tcgbError.userInfo objectForKey:NSUnderlyingErrorKey]; // NSError object from external module
NSInteger moduleErrorCode = moduleError.code;
NSString *moduleErrorMessage = moduleError.message;

// If you use **description** method, you can get entire information of this object by JSON Format
NSLog(@"TCGBError: %@", [tcgbError description]);
TOP