본문 바로가기

Development Note/JAVA

[안드로이드] onPurchaseFinished() 메서드가 호출되지 않는 경우



 인앱결제 v3(In-App Billing, v3)가 문제가 종종 발견되는군요, 이번에 포스팅할 내용은 문제라고 하기엔 좀 그렇지만 인앱결제 구현시 빼먹기 쉬운 내용입니다.


 처음 인앱결제를 구현하시는 분들은 인앱결제에 관련된 또다른 이슈를 해결하는 방법도 참고하시면 좋을 듯 합니다.

2014/07/02 - [Development Note/JAVA] - [안드로이드] 인앱결제 (In-App Billing, v3) IllegalArgumentException 해결방법


 In-App Billing v3를 구현하다 보면 IapHelper.OnIabPurchaseFinished() 메소드를 오버라이드하게 됩니다. 이 메소드는 인앱구매창에서 인앱구매가 성공(혹은 실패)한 경우에 호출되는 콜백베소드입니다. 인앱구매가 완료된 후 UI를 업데이트 해주는 작업 등을 수행할 수 있기 때문에 매우 중요합니다.




       mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {\
       //PurchaseFlow 종료 리스너 오버라이드
	
		@Override
	        public void onIabPurchaseFinished(IabResult result, Purchase info) {
		// TODO Auto-generated method stub

		if(result.isFailure()){ //구매가 실패한 경우(혹은 취소한 경우)
						
			//구매 실패시 수행할 이벤트 작성
						
			Log.d("In-App-Purchase", "Error purchasing: " +result); //로그출력
			Toast.makeText(mContext, "purchase failed", Toast.LENGTH_SHORT).show(); //구매실패 메시지 출력
			return; //리턴
						
		}else if(info.getSku().equals(SKU_PREMIUM)){ //SKU_PREMIUM 구매가 확인된 경우
						
			// SKU_PREMIUM (영구구매)아이템 구매 성공시 수행할 이벤트 코드 작성

			Log.d("In-App-Purchase", "Purchase SKU_PREMIUM: " +result); //로그출력
			isPremium = true; //구매상태 true로 변경, DB 및 UI 업데이트 처리
			showPremiumPopup(); //프리미엄 구매 성공 팝업창 호출
						
			}
		}
	};


 그리고 작성한 OnIabPurchaseFinishedListener 는 구매 이벤트 발생창을 호출하는 launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener)의 마지막 파라미터로 들어갑니다. 작성한 리스너를 파라미터로 전달하는 과정이 있기 때문에 launchPurchaseFlow()를 호출하면 끝나는 거라고 생각하기가 쉽습니다.

 그러나 실제로 적용해보면 launchPurchaseFlow()를 호출하고 인앱구매가 종료된 후에도 리스너 내부에 구현한 OnIabPurchaseFinished()가 호출되지 않습니다. 토스트를 띄워서 확인해보아도, 로그를 찍어보아도 마찬가지입니다. 아예 호출이 안됩니다.


		@Override
	        public void onClick(View v) {
			// TODO Auto-generated method stub

			if(v==btnPurchase) launchPurchaseFlow(this, SKU_PREMIUM, 10001, mPurchaseFinishedListener);

				// launchPurchaseFlow를 호출하면서 mPurchaseFinishedListener를 던져주면 끝나는 것만 같지만,
				// 정작 구매 테스트를 해 보면 OnIabPurchaseFinished()는 호출되지 않는다
		}


 하지만 구글 문서를 자세히 보면 답이 있습니다. launchPurchaseFlow()를 호출하고 인앱구매가 발생하면서 구매창이 닫히면 구매결과 데이터가 구매를 수행한 Activity로 다시 전달되게 되는데, 이 과정에서 구매결과 데이터는 onActivityResult()메소드로 전달됩니다. 안드로이드 개발을 하다 보면 다른 액티비티를 띄웠다가 다시 원래의 액티비티에서 정보를 전달받을 때 onActivityResult()를 오버라이드하게 되는데, 그와 같은 원리로 인앱구매창이 Activity 형태로 실행된 후에 종료하면서 데이터를 onActivityResult()로 전달하게 되는 것이죠.

 따라서, onActivityResult()를 오버라이드 해 주고 전달받은 데이터를 IabHelper 객체로 던져주면 비로소 onIabPurchaseFinished()가 호출되게 됩니다. 다음의 코드를 참고하시면 되겠네요.


	//purchase가 이루어지는 Activity에 onActivityResult() 메소드를 오버라이드
		
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		Log.d("ON_ACTIVITY_RESULT", "Called");
				
		if(iabHelper ==null) return; //iabHelper가 null값인경우 리턴

		if(!iabHelper.handleActivityResult(requestCode, resultCode, data)){ //iabHelper가 데이터를 핸들링하도록 데이터 전달
			super.onActivityResult(requestCode, resultCode, data);
			//구매와 관련된 데이터가 아닌 경우 onActivityResult가 처리하도록 함

		}else{
			Log.d("ON_ACTIVITY_RESULT", "onActivityResult handled by IABUtil");
		}
	}


 이제 비로소 onIabPurchaseFInishedListener()가 호출되는것을 볼 수 있습니다. 모두 인앱결제로 대박나시길 바라면서 글을 맺습니다.