안녕하세요?


오늘은 게임내 인앱 결재를 구현하는 방법을 소개해드리겠습니다.


일단 첨부된 BillingTest.zip 파일을 받으셔서 설치하시기 바랍니다.


20121230_133555.png 


Import 시키시면 위 화면과 같은 프로젝트가 나타나는데요.


이미 만드신 게임이 있다면 위에서 붉은 사각형으로 표시된 패키지들을 자신의 프로젝트로 복사합니다.


20121230_133620.png 


매니페스트에도 위의 내용을 추가해줍니다.


끝으로 매니페스트에


<uses-permission android:name="com.android.vending.BILLING"/>


이 퍼미션을 반드시 추가해줘야 합니다.

간혹 이걸 빠트리셔서 제대로 결재가 안된다고 하시는 분들이 계십니다.

안드로이드 개발자 페이지에 위의 퍼미션이 적용된 APK가 업로드 되어 있어야만

결재 테스트가 가능하니 잊지 말고 적용하세요.


package bayaba.test.game;

import android.app.Activity;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Window;
import android.view.WindowManager;
import bayaba.test.billing.BillingService;
import bayaba.test.billing.BillingService.RequestPurchase;
import bayaba.test.billing.BillingService.RestoreTransactions;
import bayaba.test.billing.Consts;
import bayaba.test.billing.Consts.PurchaseState;
import bayaba.test.billing.Consts.ResponseCode;
import bayaba.test.billing.PurchaseObserver;
import bayaba.test.billing.ResponseHandler;

public class Test extends Activity
{
    private static final int DIALOG_CANNOT_CONNECT_ID = 1;
    private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;
    private GamePurchaseObserver mPurchaseObserver;
    private Handler mHandler;
    private BillingService mBillingService;

    private class GamePurchaseObserver extends PurchaseObserver
    {
        public GamePurchaseObserver(Handler handler) {
            super(Test.this, handler);
        }

@Override
public void onBillingSupported(boolean supported, String type){

if (type == null || type.equals(Consts.ITEM_TYPE_INAPP)) {

if (supported) {
mBillingService.restoreTransactions();
}
}
}

        @Override
        public void onPurchaseStateChange(PurchaseState purchaseState, String itemId, int quantity, long purchaseTime, String developerPayload)
        {
        	switch (purchaseState)
        	{
case PURCHASED:
// 현재 구매 확인
break;

case CANCELED:
// 취소 ..
break;

case REFUNDED:
// 환불 ..
break;

default:
break;
}
        }

        @Override
        public void onRequestPurchaseResponse(RequestPurchase request, ResponseCode responseCode)
        {
            if (responseCode == ResponseCode.RESULT_OK) {

            	// 사용자의 구매가 성공하면 이 루틴으로 리턴값이 들어옵니다.
        	 if ( request.mProductId.equals("coin01") ) // coin01 상품의 구매 성공 처리
        	 if ( request.mProductId.equals("coin02") ) // coin02 상품의 구매 성공 처리
        	 if ( request.mProductId.equals("coin03") ) // coin03 상품의 구매 성공 처리
if ( request.mProductId.equals("coin04") ) // coin04 상품의 구매 성공 처리
            	
            	if (Consts.DEBUG) {
                    //Log.i(TAG, "purchase was successfully sent to server");
                }
            } else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
                if (Consts.DEBUG) {
                    //Log.i(TAG, "user canceled purchase");
                }
            } else {
                if (Consts.DEBUG) {
                    //Log.i(TAG, "purchase failed");
                }
            }
        }

        @Override
        public void onRestoreTransactionsResponse(RestoreTransactions request, ResponseCode responseCode)
        {
        	if (responseCode == ResponseCode.RESULT_OK)
        	{
//	 Log.d(TAG, "completed RestoreTransactions request : " + request.getStartId());
} else {
//	 Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
        }
    }
    
private void InitBiling()
{
    	mHandler = new Handler();

    	mPurchaseObserver = new GamePurchaseObserver(mHandler);
        mBillingService = new BillingService();
        mBillingService.setContext(this);
        
        ResponseHandler.register(mPurchaseObserver);
        if ( !mBillingService.checkBillingSupported() ) showDialog(DIALOG_CANNOT_CONNECT_ID);
}

public void BuyItem( String item_name )
{
if ( !mBillingService.requestPurchase(item_name, Consts.ITEM_TYPE_INAPP, "REQUEST_PURCHASE") )
{
showDialog( DIALOG_BILLING_NOT_SUPPORTED_ID );
}
}

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getWindow().addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON );
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setVolumeControlStream( AudioManager.STREAM_MUSIC );
        
        setContentView( R.layout.main );
        InitBiling();
    }

    @Override
    public void onDestroy()
    {
    	super.onDestroy();
    	mBillingService.unbind();
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        ResponseHandler.register(mPurchaseObserver);
    }

    @Override
    protected void onStop() {
        super.onStop();
        ResponseHandler.unregister(mPurchaseObserver);
    }
}


이건 결재를 위한 소스 코드 샘플인데요.

사실상 본인의 프로젝트에 위의 내용들이 전부 추가되어 있어야 합니다.

이 소스는 개발자 페이지에서 관리되지 않는 항목으로 추가된 인앱 아이템 결재를 보여줍니다. 

관리되지 않는 항목이란 쉽게 설명해서 중복 구매가 가능하다고 생각하시면 됩니다.

"사용자 계정당 관리됨"으로 설정된 아이템은 1회만 구매가 됩니다.

20121230_134854.png 


인앱 아이템 설정시 위의 화면처럼 관리되지 않는 항목으로 설정하세요.

제가 올린 소스에서는 인앱 제품 ID를 coin01, coin02, coin03, coin04로 설정했다고 가정하고 구현했습니다.

인앱 제품 ID는 여러분들이 설정하시기 나름이니 취향대로 네이밍하시면 됩니다.



위의 소스를 기준으로 설명드리면

구매 버튼을 눌렀을때 BuyItem( "인앱 제품 ID" );를 호출하면 결재창이 뜹니다.

가령 제가 설정한 인앱 제품 ID를 기준으로 하면 BuyItem( "coin01" ); 정도가 되겠네요.

사용자가 구매를 정상적으로 완료했다면

onRequestPurchaseResponse 이 부분으로 리턴값이 들어옵니다.

RESULT_OK가 들어오면 구매가 완료된 것이고, request.mProductId로 구매한 인앱 제품 ID가 들어옵니다.

그러니까 request.mProductId가 어떤 인앱 아이템 ID를 가지고 있는지 비교해서

아이템 구매 성공 여부를 처리해주면 됩니다.



마지막으로 주의하실 부분은

게임을 런칭하기 전에 테스트하려면 개발자 페이지의 세부 항목에서 라이선스키를 가져와야 합니다.

라이선스키.jpg


각 앱의 세부 항목에 들어가면 이와 같은 라이선스키를 얻을 수 있는데요.

이 키를 일단 복사하셔서

20121230_140500.png 

billing 소스 코드 내에 있는 Security.java을 열고

20121230_140521.png 

위의 변수에 넣어주시면 됩니다.

테스트 결재를 하시려면 반드시 이 과정을 거쳐야 하니 주의하세요.

그리고 테스트폰의 이메일 계정은 프로필 수정 메뉴에서 추가해줘야 합니다.

테스트폰으로 등록된 폰에서만 결재 테스트가 가능합니다.

이메일 계정 설정은 여러개 할 수 있으나 보통 1~2시간 정도 있어야 갱신이 됩니다.

등록후 바로는 결재가 안될 수 있으니 유의하세요.


그럼 인앱 결재를 통해 다들 부자 되시기 바랍니다.


이 내용은 바야바 엔진 사이트(www.bayabalib.com)에 제가 올린 내용을 그대로 퍼왔습니다.

혹시라도 다운로드가 안된다거나 하시면 사이트에서 받아주세요.