마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

인앱결제 api3 타임아웃등의 예외처리

0 추천

안녕하세요. 새내기 개발자입니다.

매일 안드로이드 펍을 보면서 실력을 늘려가고 있습니다.

감사합니다. 

----------------------------------------------------------------

어플 ->  결제 -> 어플 -> 어플서버

이런식으로 인앱을 구현했습니다.

소스는 api3샘플을 그대로 가져다가 수정해서 사용했습니다.

어찌어찌해서 결제되어 넘어온값으로 서버에 등록까지 했습니다.

 

문제는

1.테스트중에 20초인가 넘어가니 타임아웃 글이 나오면서 종료 되더군요.

 (결제는 이루어졌는데 어플은 아무 반응이 없습니다. 물론어플서버에도 등록이 안되었구요)

  다시 결제 버튼누르니 아이템을 소유하고 있다고 안되더라구요

 

2. 4~5섯번결재하면 서버에 등록되는게2번정도....

(결제는4~5섯번 다이루어졌습니다.)

 

로그를 볼방법도 디버그를 할방법도 없고 너무 답답합니다.

샘플 소스코드 이해도 잘 안되고 orz

 

이틀동안 여기저기 안본것이 없을정도로 봤습니다.

도저히 제힘으로는 역부족이여서 도움을 청합니다.

혹시 경험이나 인앱만져본분계시면

가는방향이나 팁정도만 주셔도 대단히 감사합니다.

 

밑에는 제가 샘플을 조금수정한 소스입니다. 지저분해도 용서를 ;;;

구입개시
mHelper.launchPurchaseFlow(this, SKU_GAS, RC_REQUEST, mPurchaseFinishedListener, payload);

결제결과 받아오기
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.e(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);

// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data))
{
super.onActivityResult(requestCode, resultCode, data);
}
else
{
Log.e(TAG, "onActivityResult handled by IABUtil.");
}
}

결과확인?
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
	{
		public void onIabPurchaseFinished(IabResult result, Purchase purchase)
		{
			Log.e(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
			if (result.isFailure())
			{
				complain("Error purchasing: " + result);
				return;
			}
			if (!verifyDeveloperPayload(purchase))
			{
				complain("Error purchasing. Authenticity verification failed.");
				return;
			}

			if (purchase.getSku().equals(SKU_GAS))
			{

				Log.e(TAG, "Consumption successful. Provisioning.");
				// bought 1/4 tank of gas. So consume it.
				Log.e(TAG, "Purchase is gas. Starting gas consumption.");
				mHelper.consumeAsync(purchase, mConsumeFinishedListener);
			}
		}
	};

서버에등록하는곳
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
	{
		public void onConsumeFinished(Purchase purchase, IabResult result)
		{
			Log.e(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);
			if (result.isSuccess())
			{
				Log.e(null, "getDeveloperPayload : " + purchase.getDeveloperPayload());

				CoinMyAsyncTask async = new CoinMyAsyncTask();
				if (SKU_GAS.equals(SKU_GAS200))
				{
					async.execute(str, SKU_COUNT1);
				}
				else if (SKU_GAS.equals(SKU_GAS500))
				{
					async.execute(str, SKU_COUNT3);
				}
				else if (SKU_GAS.equals(SKU_GAS800))
				{
					async.execute(str, SKU_COUNT5);
				}
			}
			else
			{
				complain("Error while consuming: " + result);
			}
			Log.e(TAG, "End consumption flow.");
		}
	};

 

 

 

 

(공지사항읽었습니다.)

  (11,920 포인트) 님이 2013년 5월 9일 질문
 님이 2013년 5월 9일 수정

2개의 답변

0 추천
걍 구글 문서 읽으시는게 더 좋으실 것 같네요.

그리고 이미 구매가 되었다고 나오면 구매 목록 받아와서 컨슈밍 하시면 될것입니다.

결제 모듈 만든 사람은 정상인데 셈플 코드 작성한 사람은 비정상인것 같네요..
Godwish (2,460 포인트) 님이 2013년 5월 9일 답변
답변감사합니다.
샘플소스말고 다른 소스를 검색해서 사용했습니다.
테스트중인데 현재까지 문제는 없습니다.


위의 1번문제가 아직 해결이 안되었습니다;;
결제버튼을 누르면  결제창이 떠서 마지막에 완료 창이 나오는데여

앱 -> 결재선택 -> 결재처리화면  -> 완료화면 -> 앱

결제처리화면(창)에서 원형프로그래스인가 나오잖아요
그부분에서 20~30초를 경과하니 타임아웃 에러가 나옵니다.
앱은 안죽습니다.

타임아웃 에러가 나면 엑티비트리졸트로 값이 안들어오는것같습니다.

결론은
결재버튼을 눌러 결재 도중 어떤이유(인터넷등)로 중간에 중지 되었을때
결제는 이루어 지지만 어플쪽은 값은 안돌아옵니다.

이럴때 어떤처리를 해주면 될까요
경험자님 들은 인앱3에 어떤 예외처리를 해주셨나요_??????
구글에서 제공한 travel샘플소스는 아주 잘 되어있습니다..
저도 구글문서 정독하고 그거 보고 만들었거든요..제공하는 IABHelper
잘 보시면 모든 에러로그를 볼수 있도록 설정이 가능합니다.
에러나는 부분은 로그 보고 하나하나 따라가시면 답이 나옵니다.

아이템을 소유하고 있다는 에러는 consume이 처리가 안된 것입니다.
타임아웃도 그쪽에서 나는것 같고요
답변감사합니다. 구글문서 정독하시다니 대단하십니다.
전까막눈이라 번역기돌려도 무슨말인지....
아이템소유는 해결했습니다.

저도 샘플소스가 잘만들어진건알겠는데 아직 익숙하지않아서
잘모르겠더군요.디버그해서 메소드 하나하나 다 살펴보았는데....

타임아웃이나면 어플쪽에 신호를 보내주나요?
샘플의 결제버튼 누르면 중간에 인터넷을 off하기전에
너무 빨리 신호가 돌아와서 테스트가 안됩니다.
테스트는 결제쪽을 확인할길이 없어서 말씀을 못드리겠습니다만
제가 만드는 어플쪽 디벨로퍼 콘솔보면 결제만이루어 지더군요

제가 걱정하고있는것은
결재만 이루어지고 어플에 아이템은 추가가 안되는것입니다.
위의소스를 보시면 아시겠지만 샘플소스 수정거의 안했고
서버등록하는것만 추가한지라....

혹시 결재만 이루어진 경우는 없으신가요?
startIntentSenderForResult 여기에 값이안돌아온다던지

에러로 결제가 중단되었을경우 구글 서버에 결재가 이루어졌는지
확인하는 메소드 같은게 있나요?
글쎄요.. 저는 타임아웃 관련 에러가 난 적이 없어서..구글에서도 못본거 같고요..결제만 진행된 경우는 consume쪽에서 문제가 생긴게 대부분 이었습니다.
아마 순서가 초기화 부분에서
startSetup -> queryInventoryAsync -> consumeAsync
후에 이상이 없으면 구매를 눌렀을 경우
launchPurchaseFlow->handleActivityResult->onIabPurchaseFinished->consumeAsync 이런 순서로 진행이 될텐데 어느쪽에서 문제가 생기는 것인지요??
결제가 완료된 후에 클라언트 바꿔주는것은 consume쪽에서만 해야 되고요.말하신대로 서버등록도 여기서 해야되는게 맞는데..
구글API에서 문제가 난다면 에러코드와 resultcode가 바로 넘어와서 확인이 가능합니다.
빠른답변 감사드립니다^^
샘플코드를 이용했을때 말씀하신대로 구현한거 같은데 제가 어딘가
잘못한거 같네요...아마도

구글API에서 문제가 난다면 에러코드와 resultcode가 바로 넘어와서 확인이 가능합니다.
위의말씀되로라면 에러 다이얼로그가떠야되는데,
전 아무것도 없이 그냥 구글 결제완료창에 타임아웃땜시 종료되었다고 나왔습니다.
그리고 어플쪽으로 돌아와지더군요
서버등록은 안되었고 다시 구매버튼누르니 소유하고있다고 <- 여기서 나온것입니다.
콘솔에서는 실결제가 이루어졌구요

지금 구현해놓은 소스를 말씀드리면
온크레이트안에서 스타트셋업
mHelper = new IabHelper(CoinShop.this, base64EncodedPublicKey);
    mHelper.enableDebugLogging(true);

    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
    {
        public void onIabSetupFinished(IabResult result)
        {
            if (!result.isSuccess())
            {
                // Oh noes, there was a problem.
                    complain("Problem setting up in-app billing: " + result);
                    return;
            }
        }
    });
               
결제창 불러오는 인텐트   
Bundle buyIntentBundle = mHelper.mService.getBuyIntent(3, getPackageName(), SKU_GAS, "inapp", "fjkdajfkldjakfldjaklfjdast");
PendingIntent penIntent = buyIntentBundle.getParcelable("BUY_INTENT");
startIntentSenderForResult(penIntent.getIntentSender(), RC_REQUEST, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
           
구글api에서 넘어오는 부분       
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (requestCode == RC_REQUEST)
    {
        int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
        String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
        String dataSignature = ata.getStringExtra("INAPP_DATA_SIGNATURE");
               
                if (resultCode == RESULT_OK)
        {
            try {  
                          JSONObject jo = new JSONObject(purchaseData);  
                          String sku = jo.getString("productId");  
                          String token = jo.getString("purchaseToken");
                          String purchaseState = jo.getString("purchaseState");
                    
                    //아이템 소비
                    int response = mHelper.mService.consumePurchase(3, getPackageName(), token);
                   
                    //서버등록
                    CoinMyAsyncTask async = new CoinMyAsyncTask();
                   
                    if (sku.equals(SKU_GAS200))
                    {
                        async.execute(str, SKU_COUNT1);   
                    }
                    else if(sku.equals(SKU_GAS500))
                    {
                        async.execute(str, SKU_COUNT3);   
                    }
                    else if(sku.equals(SKU_GAS800))
                    {
                        async.execute(str, SKU_COUNT5);
                    }
                  }  
                  catch (JSONException e) {  
                     alert("Failed to parse purchase data.");  
                     e.printStackTrace();  
                  }  
                  catch (RemoteException e)
                   {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                      alert("onActivityResult RemoteException");
                  }
            }
            else
            {
                alert("err");
                    // handle items here
            }

현재 위의 소스로 3대의 단말기에서 10회정도 테스트 했는데 문제없이
실결제가 이루어지고 서버등록도 되었습니다.

샘플소스를 이용하는게 훨씬 낳은가요?
먼가찜찜한 구석이 ........;;

구글 스토어에 개시하고 나서
 결제만이루어지고 아이템추가 안되었다고
크레임올까봐 걱정입니다.

자꾸질문해서 죄송합니다만 부탁합니다.
startup할 때 query해서 comsume 시키는 것 까지 넣어놓으시면 좋습니다.  이렇게 하면 오류나 났을 때 다시 들어오면 검색해서 소모를 시키면서 다시 결제가 가능 해 집니다. 나머지 코드는 맞는 것 같습니다.
답변감사드립니다.

그렇군요!!!
일단 말씀하신대로 셋업부분에 추가하겠습니다.

검색해보니
버전2에서는 실제로 결제만 이루어지는 경우가 많은가보더라구여
그래서 일일이 환불해줬다니......어쩌구 저쩌구

개발자는 그렇다 치고 주문한쪽에서는 시스템쪽을 모르니
결재만 이루어지면 이게머냐고 따지고 들꺼에요 아마도,,,,,

예외패턴이 너무 많아서 일일이 대응하기가 힘이 드네요....혼자서 할려니 orz
개발자 화이팅!
원래 처음 startsetup 부분에서  mHelper.queryInventoryAsync(mGotInventoryListener);
이 리스너로 비소모성아이템이 결제완료되었는지 체크하는 부분이 들어있는걸로 알고있는데요
자동으로 consume 까지 시켜주게끔 셈플소스에 들어있습니다
답변 감사드려요!!

mHelper.queryInventoryAsync(mGotInventoryListener);

mGotInventoryListener

OnConsumeFinishedListener
요렇게 되어있는걸 저도 보았지요.
흠흠....
그러나 샘플소스 그대로 했는데(아마도 ㅎ) 단말기나 네트워크 상태에 따라
결재완료 신호가 어플에 전달이 안되었거든요 (실결재만 이루어짐)

쩨~일위에 소스롤 보시면 아시겠지만
OnConsumeFinishedListener 에다가
서버등록하는 스레드 하나집어넣었을뿐인데.
참고로 전 인터넷이 빠른 한국이 아니라  인터넷 느리고 가끔 안터지는곳도 있는어떤나라에서 개발중입니다. ㅠ.ㅠ
추가로 말씀드리면  
아이템소유에 대해선 해결이 되었습니당^^

2번문제 타임아웃이나 밧데리없어서 결재중 꺼진다거나 머 여러가지
경우로 인해서 구글쪽신호를 못받거나 안왔을때의
예외처리가 궁금하네요

이런 예외가 발생하면 구글 콘솔쪽(실결제)만 이루어지고
어플쪽에는 아이템 추가가 안되잖아요.....(서버에 코인증가)
그럴때 말이죠 ...
다시 구입화면에 들어왔을때
조금전 구입할려고 한 아이템이 실결제가 이루어 졌는지 안졌는지
알아오는 메소드가 있을까요?
없다면 여러분들은 어떻게 대처를 해놓으셨는지궁금합니다.
0 추천
최근에 안드로이드쪽 포팅하다 유사한 문제가 발생을 했는데, 제경우에는 아래 내용을 통해 수정을 하였습니다.

제 생각엔 동일한 이슈 같은데요. 그런데 게시글의 날짜가 6개월도 더 된것이라 이미 해결은 하셨을것 같네요^^....

 

http://stackoverflow.com/questions/14800286/oniabpurchasefinished-never-called
익명사용자 님이 2014년 1월 23일 답변
...