최근에 DeveloperPayload(개발자가 임의로 만든 payload값) 기능이 구글에서 없어졌습니다. 때문에 해당 부분을 삭제했습니다. (2021-1-8)

 

 

서버 검증을 위해, 구글에 계정 만들고, 개발자 페이지에서 p12 파일 만들고 그러는 거는 검색해 보시면 쉽게 보실 수 있어요.
아래 페이지에 잘 정리 돼 있더라구요.
http://theeye.pe.kr/archives/2570

여기서는 c#으로 서버를 개발 했을 경우, 서버 검증하는 코드를 넣었습니다.
서버 검증은 3가지 방법이 있는데,
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#oauth-2.0-protocol

여기서는 [ServiceAccountCredential]을 이용한 방법입니다.

 

1. 클라이언트에서 서버로 결과 보내기

 아래 클라이언트 부분의 코드는 유니티엔진의 인앱 라이브러리를 이용한 것 입니다.

// 유저 인앱 완료 시, 실행되는 이벤트
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
    //결과를 저장하기 위한 클래스 객체
    IapResultData result_data = new IapResultData();

    try
    {
        //인앱 구매 전, 게임 서버로부터 받은 payload값
        JObject json_object = JObject.Parse(e.purchasedProduct.receipt);            
        string payload = (string)json_object["Payload"];

        //결과값에 파싱에 문제되는 문자들이 섞여있습니다. 아래같이 직접 없애주세요.
        payload.Replace("\\", "");            

        JObject payload_object = JObject.Parse(payload);
        string payload_json = (string)payload_object["json"];


        JObject payload_json_object = JObject.Parse(payload_json);


        string payload_json_purchaseToken = (string)payload_json_object["purchaseToken"];
   
        
        result_data.m_data_id = m_curr_shop_data.m_id;
        result_data.m_pid = m_curr_shop_data.m_pid;
        result_data.m_token = payload_json_purchaseToken;

        //위 값들을 서버로 전송합니다~
        NetworkManager.Instance.SendBuyIapItemFinishReq(result_data);

    }
    catch (Exception ex)
    {
        return PurchaseProcessingResult.Complete;
    }
    return PurchaseProcessingResult.Complete;
}

 

 

2. 서버에서 받은 데이터로 검증하기

//클라이언트로 받은 결과를 저장하는 클래스 입니다.
public class IapResultData
{
    public int m_data_id;        //제 겜에서 사용하는 상품 데이터 id
    public string m_pid;        //구글 상품 id
    public string m_token;        //구글 인앱 결과에 있습니다.
}

//스레드로 처리하려다 보니 따로 request 객체를 만들어 사용했습니다. 몰라도 돼요
public class IapVerifyRequestData
{
    public IapResultData m_iap_result_data { get; set; }
    public jdUserToken m_user_token { get; set; }

    public IapVerifyRequestData()
    {
    }


    public IapVerifyRequestData(IapResultData data, jdUserToken user_token)
    {
        m_iap_result_data   = data;
        m_user_token        = user_token;
    }
}


//클라이언트로 받은 영수증 정보로 서버 검증을 합니다.
private void processRequest(IapVerifyRequestData iap_data)
{

    try
    {
    	//구글api 계정
        String serviceAccountEmail = "xxxxx@xxxxxxxxx.iam.gserviceaccount.com";

    	//위 계정에서 만든 key.p12 파일.
        var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

        ServiceAccountCredential credential = new ServiceAccountCredential(
           new ServiceAccountCredential.Initializer(serviceAccountEmail)
           {
               Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
           }.FromCertificate(certificate));


        AndroidPublisherService android_service = new AndroidPublisherService(
            new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
                ApplicationName = "com.jd.games.BattleGame",
            }
        );


    	//검증 요청
        var request = android_service.Purchases.Products.Get("com.xxx.앱패키지명",
                                                        iap_data.m_iap_result_data.m_pid,
                                                        iap_data.m_iap_result_data.m_token);
        var purchase_state = request.Execute();



        IapVerifyResultData result_data = new IapVerifyResultData();

      //결과 예시 입니다.
      //{
      //    "consumptionState" : 1,    // 0 아직 컨슘 안됨, 1 컨슘됨
      //  "developerPayload" : "",
      //  "kind" : "androidpublisher#productPurchase",
      //  "purchaseState" : 0,    // 0 구매완료, 1 취소
      //  "purchaseTimeMillis" : "1454502702978"
      //}

        //유니티에서 인앱 구매하는 경우 자동으로 컨슘까지 됩니다.
        // 페이로드 값이 제대로 왔는지 확인합니다.
        // 페이로드 체크 안하시면 안해도 됩니다.

        result_data.m_shop_data_id      = iap_data.m_iap_result_data.m_data_id;
        result_data.m_purchase_state    = (int)purchase_state.PurchaseState;
        result_data.m_consume_state     = (int)purchase_state.ConsumptionState;                
        result_data.m_fail_reason       = FailReason.FAIL_REASON_NONE;




        //인앱 결과를 처리...

    }
    catch (Exception exc)
    {
        //문제 발생 시 처리
    }
}
이세계 용병 온라인

댓글을 달아 주세요