Game Development, 게임개발/개발

Unity IAP, In-App Purchase, 유니티 인앱결제

게임이 더 좋아 2022. 3. 13. 16:13
반응형
728x170

Unity 는 언제부턴가 Codeless한 툴을 제공하기 시작했다.

하지만 어차피 스크립트 구현부분을 만들어야 하기에 나는 그것을 버리고 했다.

나는 스크립트로 만들어진 공개된 코드를 찾고자 했으나.. 못찾음 알아보도록 하자

하지만 몇가지는 찾았고 내 식으로 설명하려고 했다.

 

** 주석을 읽으면 다 이해된다.

 


 

우선 IAP에 대해 안다고 치고.. 스크립트 작성에 대해서만 알아보자

using System;
using UnityEngine;
using UnityEngine.Purchasing;



//IStoreLinster는 구매와 관련된 이벤트를 관리함.
public class IAPManager : MonoBehaviour, IStoreListener
{

    public static IAPManager instance;


    private IStoreController controller;
    private IExtensionProvider extensions;

    


    //하나만 존재함.
    public void Awake()
    {
        if (instance == null) instance = this;
        else if (instance != this) Destroy(gameObject);
        DontDestroyOnLoad(gameObject);
        
    }

    void Start()
    {
        //초기화 되었으면 다시 실행하지 않음.(Reload)같은 경우
        if (IsInitialized()) return;
        InitializePurchasing();
    }


    #region Purchasing 초기화
    private bool IsInitialized()
    {
        //둘다 null이 아니라면 초기화 정상적으로 된 것임
        return controller != null && extensions != null;
    }

    public void InitializePurchasing()
    {
        //이 빌더는 제품 정의를 위한 필수
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

        //스태틱데이터 -> 스토어에 따른 정보를 가지고 있음.
        var data = 0; //사용자 정의

        //제품 정의 등록
        for (int i = 0; i < data.Length; i++)
        {
            //제품을 추가할 때 앱스토어 또는 구글스토어에 대한 id를 같이 넣어줌
            builder.AddProduct("상품이름", "상품타입"); // -> 스토어별 ID 넣어줘야함.
        }

        //진행
        UnityPurchasing.Initialize(this, builder);
    }
        

    //위의 초기화가 완료되었을 때 실행됨
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        this.controller = controller;
        this.extensions = extensions;
    }


    //위의 초기화가 실패되었을 때 실행됨
    public void OnInitializeFailed(InitializationFailureReason error)
    {
        Debug.Log("결제정보 초기화 실패");
    }

    #endregion


    #region 구매

    //구매가 완료되었을 때 실행됨 -> 초기화 이후에 실행되어야 함.
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
    {
        if (String.Equals(purchaseEvent.purchasedProduct.definition.id, "제품 ID", StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", purchaseEvent.purchasedProduct.definition.id));
            //해당 제품에 대한 지급
            //->
        }
        else if(String.Equals(purchaseEvent.purchasedProduct.definition.id, "다른 제품 ID", StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", purchaseEvent.purchasedProduct.definition.id));
            //.. 구입한 상품에 대한 효과 적용
        }
        //...

        //아이디가 존재하지 않으면 구매 효과 적용하지 않음
        else
        {
            Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", purchaseEvent.purchasedProduct.definition.id));
        }

        return PurchaseProcessingResult.Complete;
    }

    //구매가 실패했을 때 실행됨.
    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    {
        Debug.Log($"{product.definition.id} 구매과정에서 {failureReason} 발생");
    }


    //구매버튼을 클릭한다면 구매하는 함수 실행
    public void OnPurchaseClicked(string productId)
    {
        if (!IsInitialized())
        {
            Debug.Log("초기화 되지 않았음");
            return; //초기화되었을 때만 살 수 있음.
        }
        controller.InitiatePurchase(productId); //구매함수 실행
        //id가 아닌 Product 클래스로 실행할 수 있음.
    }

    //구매 되돌리기
    public void RestorePurchases()
    {
        //초기화 이후 가능.
        if (!IsInitialized()) return;


        // 앱스토어에 대한 작동.
        if (Application.platform == RuntimePlatform.IPhonePlayer ||
            Application.platform == RuntimePlatform.OSXPlayer)
        {
            
            Debug.Log("RestorePurchases started ...");

            // 스토어 서브 시스템에 접근.
            var apple = extensions.GetExtension<IAppleExtensions>();


            // 비동기작업으로 진행
            // result에 대해서 비동기 작업이 완료되면 실행될 콜백함수 (무명메서드로 동작해도 괜찮음) -> 여기서 구입한 항목 되돌리는데 쓰임.
            apple.RestoreTransactions((result) => {
                // The first phase of restoration.
                //If no more responses are received on ProcessPurchase then 
                // no purchases are available to be restored.
                Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
            });
        }
        //다른 플랫폼에서 진행한다면 Restore는 진행되지 않음.
        else
        {
            // We are not running on an Apple device. No work is necessary to restore purchases.
            Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
        }
    }

    #endregion


}

 

 

어차피 인앱결제에서 필요한 것을 굳이 따져보자면

 

1. 상품

2. 구매

끝이다.

 

상품의 하위에는

상품 등록. 스토어별 상품 등이 있는 것이고

 

구매 하위에는

상품 타입별 구매효과, 구매 적용, 구매 성공,실패 처리, Pending 처리 등이 있을 뿐이다.

 

조금 더 이해하고자 한다면 Interface의 항목을 살펴보거나 실제로 Product 클래스에서 내가 쓸 수 있는 것이 무엇인지 찾아보자.

 

반응형
그리드형