Notice
Recent Posts
Archives
Today
Total
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Recent Comments
관리 메뉴

우당탕탕 개발일지

Google Developer API 사용하여 환불처리하기 본문

Server

Google Developer API 사용하여 환불처리하기

devchop 2023. 11. 9. 17:57

게임에 사정이생겨서, 결제건수를 모두 환불해야하는 일이 생겼다. 900건이 넘는 결제건수를 환불하기 위해서는 google api를 사용해 처리해야했다.

 

해야할 순서는 다음과 같다. 

1. 웹브라우저를 통해 인증 코드를 발급받는다.

2. api와 통신하여  인증코드를 이용해 엑세스 토큰을 발급받는다.

3. 발급받은 엑세스 토큰을 사용하여 환불처리한다.(api통신)

 

엑세스 토큰은 시간이 지나면 만료되기 때문에 refresh하는 작업도 필요하지만, 나는 너무 급했으므로 발급받아서 후딱 사용했다.

 

1. OAuth2.0 클라이언트 ID 생성하기

google cloud platform 에 들어가서 > 원하는 프로젝트 > API 및 서비스 > 사용자 인증정보 > OAuth2.0 클라이언트ID ( Web application) 을 생성해야한다. 보통 구글 출시를 할때 기본적으로 하나 만들어놓으므로, 있는걸 그대로 사용하기로 하자. 대신에, 리디렉션 URI 를 세팅해줘야한다. https://localhost:8080 를 입력해준다.

여기서 필요한값은

리디렉션 URI, 클라이언트 ID, 클라이언트 보안 비밀번호 3가지이다.(잘 적어두도록 하자.)

 

2. 생성한 클라이언트id로 code 발급받기

다음 주소를 인터넷 창에 넣으면, 구글로그인과 함께 엑세스허용이 뜬다.

redirect_uri = ... 부분에 아까 입력한 리디렉션URI를, client_id= ... 부분에 클라이언트ID를 입력해준뒤 엔터를 누르면 된다.

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=...&client_id=...

 

그러면 왠 페이지가 나오는데, 주소란이 다음과같다 여기서 우리가 사용해야할 코드는 code= 이후부터 &scope 이전까지이다. 형식은 4/eWdxD7b-YSQ5CNNb-c2iI83KQx19.wp6198ti5Zc7dJ3UXOl0T3aRLxQmbwI 

이런느낌이라는데, 자세히보면 / 가 %2F 로 변환되어서 출력될수도있다. 이는 나중에 스크립트에서 변환작업을 해줄거다.

https://localhost:8080/?code=4%2F0AfJohXk0H4iW-1w2omWHf5pONBS8ymr9s3xLYHdtIK0fAJOuF_FCtaFsghYLcUmcWDAtnQ&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fandroidpublisher

 

주의할점은, 이 코드는 주기적으로바뀐다. 코드를 미리 뽑아놨다가 나중에 사용하려고하면 Bad Request가 뜨니, 실제 사용하기 직전에 code를 추출하여 이용하도록하자.

 

 

3. api와 통신하여  인증코드를 이용해 엑세스 토큰을 발급받기

이제 Google Developer API 에 Post로 요청을 보낸다. 나는 유니티가 편해서 유니티 WepRequest를 사용했다.

  IEnumerator Access()
    {
        string accessURL = "https://accounts.google.com/o/oauth2/token";
        string client_id = "your client id";
        string client_serect = "your client secret key"

        WWWForm form = new WWWForm();
        form.AddField("grant_type", "authorization_code");
        form.AddField("code", browseCode.Replace("%2F", "/")); //%2F를 /로 변환하고있다.
        form.AddField("client_id", client_id);
        form.AddField("client_secret", client_serect);
        form.AddField("redirect_uri", "https://localhost:8080");


        UnityWebRequest www = UnityWebRequest.Post(accessURL, form);
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error +", ");
        }
        else
        {
            
            Debug.Log("Form upload complete!" + www.downloadHandler.text);
        }
    }

 

 

위 코루틴을 실행하면, 성공했을 경우 다음과같은 성공 메세지와 함께 엑세스 토큰이 주어진다.

Form upload complete!{
  "access_token": "....",
  "expires_in": 3599,
  "refresh_token": "....",
  "scope": "https://www.googleapis.com/auth/androidpublisher",
  "token_type": "Bearer"
}

 

Refresh토큰은 나중에 토큰갱신할때 사용하도록 하고, 우리가 사용해야할 것은 저 "access_token" 이다. 잘복사해주도록하자. 추출해서 쓰는것,,, 그런것까지 할 여유는없어..

 

 

4. 발급받은 AccessToken을 사용하여 환불처리하기 ( 만료되기전에 빨리하자~)

이 엑세스토큰은, 이제 환불처리 POST요청의 헤더에 넣어준다.

 

int startIndex = 0;
    IEnumerator IRefund()
    {
        
        for (int i = startIndex; i <gpas.Count ; i++)
        {
            string packageName = "your package Name ex)com.aa.company";
            string refundURL = string.Format("https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{0}/orders/{1}:refund", packageName, gpas[i]);

            WWWForm form = new WWWForm();

            UnityWebRequest www = UnityWebRequest.Post(refundURL, form);

            www.SetRequestHeader("Authorization", "Bearer " + accessToken);

            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogFormat("refund {0} fail. {1} : {2}", i, gpas[i], www.error );
                yield break;
            }
            else
            {
                Debug.LogFormat("refund {0} complete. {1} :{2}", i, gpas[i] , www.downloadHandler.text);
            }

            yield return new WaitForSeconds(.1f);
        }
        
    }

 

난 환불건수가 900건에 육박해서 루프를 이용해 모두 환불처리했다. 몇가지 없을 경우  아래 refundURL 에 {1} 값을 주문번호로 넣으면된다. 참고로 주문번호라 함은 "GPA.1234-1234-1234-12345" 이런형식이다.

 

string refundURL = string.Format("https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{0}/orders/{1}:refund", packageName, gpas[i]);

 

참고사이트 - 엑세스 토큰 발급받기

https://developers.google.com/android-publisher/authorization?hl=ko#using_the_access_token

 

승인  |  Google Play Developer API  |  Google for Developers

승인 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 섹션에는 Google Play Developer API와 관련된 안내가 포함되어 있습니다. 자세한 내용은 전체 OAuth2 문서를

developers.google.com

참고사이트- 환불처리하기

https://developers.google.com/android-publisher/api-ref/rest/v3/orders/refund?hl=ko

 

Method: orders.refund  |  Google Play Developer API  |  Google for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English Method: orders.refund 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 사용자의 정기 결제 또

developers.google.com

 

참고사이트 - 혹시나 통신중에 에러메시지가 발견될경우 참고하면 좋을사이트

https://cloud.google.com/apigee/docs/api-platform/reference/policies/oauth-http-status-code-reference?hl=ko

 

OAuth HTTP 오류 응답 참조  |  Apigee  |  Google Cloud

organizations.environments.sharedflows.deployments

cloud.google.com

 

후기))

 정말 다행스럽게도 인앱결제마다 로그를 남겨놓았기때문에 엑셀파일로 추출이 가능했다만,,, 구글콘솔에서는 한달이 지나지 않아서 보고서가 나오지 않았다. 인앱결제 로그는 필수라는 생각이들면서 등골이오싹..

 

이와중에도 아주열심히 환불처리하고있는 ... 일해라 컴퓨터야~