개발자들이여 T store를 정복해보자 - 4. cocos2d-x T Store In App Purchase Integration

 티스토어에 인앱 제품 추가까지 했다면 이제 실제로 코드 작업을 해야겠죠. 이번 포스팅은 cocos2d-x 기반 게임에 티스토어 인앱 결제 연동을 정리해보겠습니다.

 먼저 티스토어 개발자 센터로 가신 후 다운로드 -> 부분 유료화 API 메뉴에서 하단의 부분 유료화 API를 다운로드 합니다. 버전은 12.09.17 기준입니다.

 적절한 곳에 압축 해제 후 Java Build Path에서 Add External JARs를 눌러 추가시켜주고 Order and Export에 체크해줍니다. 이때 IAPLibD.jar와 IAPLibR.jar가 있는데 각각 디버그, 릴리즈용 입니다. 개발중에는 디버그용으로 하시고 최종 검증받으실 때는 릴리즈용으로 적용하시면 됩니다.

<activity android:label="@string/app_name" android:name="com.feelingk.iap.PwdActivity"/>

<!-- SMS receiver -->
<receiver android:name="com.feelingk.iap.SmsReceiver">
   <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
       </intent-filter>
   </receiver>

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- SMS receiver permission -->
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>

 개발중인 앱의 AndroidManifest.xml에 위와같이 액티비티와 리시버, 권한을 추가해줍니다.

 이제 코딩 작업을 들어가야하는데 문제가 있네요. SK에서 IAP 모듈을 Activity로 작업해놔서 Cocos2dxActivity를 기존에 extends Activity하던 것을 extends IAPActivity 해줘야 할 판이네요. 뭐 작업이야 하면 되는거지만, 최소한 cocos2d-x딴은 안 걸들고 싶었는데 이거 참 왜 이런식으로 해놨는지... 안드로이드 Service나 BroadCastReceiver 같은 좋은걸 놔두고 왜 이렇게 해놨는지 싶네요. 차라리 구글 플레이 인앱빌링 샘플이었던 Dungeons처럼 소스라도 공개되어 있으면 알아서 Activity부분 삭제하고 처리할텐데 말이죠.

 그리고 이렇게 되면 제가 작업중인 Java 딴 Framework에도 이슈가 생길 듯 합니다. 일단 작업 내용이야 간단해 소스가 공개되는거야 별 상관없다지만, 한번 수정해서 공유해서 쓸 수 있는 제 Framework딴을 벗어나 Cocos2dxActivity.java 라는 파일 수정본을 공유해야한다는게 좀 걸립니다. lib 공유가 아닌 코드베이스 공유가 되는것이죠. 아무튼 왜 Activity를 상속해서 해놨는지 아직도 모르겠네요.

 아무튼 위와 같이 Activity를 통합안하고 적용 했을 때에 대한 폐해를 알고 싶으시다면 구글 플레이 인앱빌링 샘플 최적화 전 연동 링크를 따라가서 스샷을 보시면 됩니다.

 이제 개발중인 프로젝트의 src/org.cocos2dx.lib에 있는 Cocos2dxActivity.java를 수정해보겠습니다.

///< 티스토어 관련 클래스 임포트

import com.feelingk.iap.IAPActivity;
import com.feelingk.iap.IAPLib;
import com.feelingk.iap.IAPLib.OnClientListener;
import com.feelingk.iap.IAPLibSetting;
import com.feelingk.iap.net.ItemAuth;
import com.feelingk.iap.net.ItemAuthInfo;
import com.feelingk.iap.net.ItemUse;


///< 기존 Activity extend하던 것을 티스토어 클래스인 IAPActivity로 수정
public class Cocos2dxActivity extends IAPActivity{
...

private final static int HANDLER_SHOW_DIALOG = 1;
///< 티스토어 핸들러 관련 상수값 추가
private final static int TSTORE_INIT = 2;
private final static int TSTORE_BUY = 3;



protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

...
...

        handler = new Handler(){
        public void handleMessage(Message msg){
        switch(msg.what){
...


         case TSTORE_INIT:
        {
               // 설정 객체를 생성
               IAPLibSetting setting   = new IAPLibSetting(); 
               setting.AppID           = msg.obj.toString();   // AID 설정
               setting.BP_IP           = null;             // BP 서버 IP
               setting.BP_Port         = 0;               // BP 서버 Port
               setting.ClientListener  = mClientListener;      // 각종 완료 및 에러 핸들러 등록
               
               // 라이브러리를 초기화.
               try {
                IAPLibInit(setting);
        } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
        }
        break;
       
        case TSTORE_BUY:
        popPurchaseDlg( msg.obj.toString(), null, null, null );
        break;
        }
        }
        };
}


///< c++에서 호출되어지는 티스토어 초기화 함수

public static void TStoreInit( String strAppId )
{
Message msg = new Message();
msg.what = TSTORE_INIT;
msg.obj = strAppId;
handler.sendMessage(msg);
}



///< c++에서 호출되어지는 티스토어 아이템 구매 함수

public static void TStoreBuyItem( String strProductId )
{
Message msg = new Message();
msg.what = TSTORE_BUY;
msg.obj = strProductId;
handler.sendMessage(msg);
}


///< 아래는 티스토어 인앱 샘플의 Sample.java와 같다. c++로 결과를 알려주는 부분 빼고.

    // 각종 완료 및 에러 처리 핸들러  
    OnClientListener mClientListener = new OnClientListener() {
     
        // 아이템 구매 가능 이벤트 처리
        // 구매가 가능한 아이템에 한하여 자체 아이템 발급 혹은 BP 서버를 통한 아이템을 발급 한 후 결과를 Boolean으로 반환
        public Boolean onItemQueryComplete() {
       
        return true;
       
        }
     
        // 아이템 구매 완료 이벤트 처리
        // 해당 아이템의 구매가 완료 되면 호출 된다.
        public void onItemPurchaseComplete() {
        Toast toast = Toast.makeText(Cocos2dxActivity.this, "onItemPurchaseComplete!!!", Toast.LENGTH_LONG);
toast.show();
///< CPP에 알려준다. 각각 개발 환경에 따라 다르겠다.
JniMapper.callCppPurchaseResponse( "itemid" );
        }

        public void onWholeQuery(ItemAuth[] items) {
         
            // 전체 인증 아이템 목록이 수신되면 호출됨

            String strOut = "";
         
            int n = items.length;
         
            for(int i=0; i<n; ++i)
            {
                strOut += items[i].pId + " : " + items[i].pName + "\n";
            }
         
            ShowToast(getApplicationContext(), strOut);
        }


        public void onItemUseQuery(ItemUse item) {
            // 소멸성 아이템을 사용 시 호출됨
            String strOut = "";
            strOut += item.pId + " : " + item.pName + " : " + item.pCount;
            ShowToast(getApplicationContext(), strOut);
        }

        public void onItemAuthInfo(ItemAuthInfo itemAuth) {
            // 특정 아이템의 인증 호출됨
            String strOut = "";
            //strOut += PID + " : " + itemAuth.pCount + " : " + new String(itemAuth.pExpireDate);
            strOut += " : " + itemAuth.pCount + " : " + new String(itemAuth.pExpireDate);
            ShowToast(getApplicationContext(), strOut);
         
            // 아이템의 토큰 정보를 반환
            if(itemAuth.pToken != null)
                Log.i("Sample", new String(itemAuth.pToken));
         
        }
@Override      
public void onDlgError() {
Toast toast = Toast.makeText(Cocos2dxActivity.this, "onDlgError!!!", Toast.LENGTH_LONG);
toast.show();

}

@Override
public void onDlgPurchaseCancel() {
Toast toast = Toast.makeText(Cocos2dxActivity.this, "onDlgPurchaseCancel!!!", Toast.LENGTH_LONG);
toast.show();
}

@Override
public void onError(int arg0, int arg1) {
Toast toast = Toast.makeText(Cocos2dxActivity.this, "onError!!!", Toast.LENGTH_LONG);
toast.show();
 switch (arg0) {
           // 초기화 실패
           case IAPLib.HND_ERR_INIT:
               break;
         
           // 인증 처리 에러
           case IAPLib.HND_ERR_AUTH:
               break;

           // 아이템 구매 가능 처리 에러
           case IAPLib.HND_ERR_ITEMQUERY:
               break;

           // 아이템 정보 수신 에러
           case IAPLib.HND_ERR_ITEMINFO:
               break;

           // 아이템 과금 처리 에러
           case IAPLib.HND_ERR_ITEMPURCHASE:
             
               break;

           // 서버 데이터 처리 에러
           case IAPLib.HND_ERR_DATA:
               break;
           }
         
}

@Override
public void onDlgAutoPurchaseInfoCancel() {
// TODO Auto-generated method stub

}

@Override
public void onJoinDialogCancel() {
Toast toast = Toast.makeText(Cocos2dxActivity.this, "onJoinDialogCancel!!!", Toast.LENGTH_LONG);
toast.show();

}

@Override
public void onPurchaseDismiss() {
// TODO Auto-generated method stub

}
    };

    public static void ShowToast(Context context, String str) {
        // 데모용 토스트 팝업
        Toast toast = Toast.makeText(context, str, Toast.LENGTH_LONG);
        toast.show();
    }


 Bold 처리한 부분을 잘 보시면 됩니다. 기타 Toast같은 것은 불필요하다면 삭제하시면 되겠습니다. 또한 C++딴에서의 JNI 처리는 기존에 제가 정리했던 것을 참고하시기 바랍니다.

 자 이제 구매 테스트를 해보겠습니다. 참고로 구매 테스트중 나오는 이슈는 따로 정리했으니 링크를 확인하시기 바랍니다.

 초기화 후 아이템 구매를 요청하면 위와 같이 이용안내가 뜹니다. 동의합니다를 눌러 체크후 확인을 누릅니다.

 상품결제 팝업입니다. 티스토어 개발자 센터에 등록했던 정보가 보여집니다. 여기서 바로 구매를 클릭하면,

 위와 같이 주민번호 인증이 뜨면서 뭔가 실제로 결제가 이루어질 것 같은 포스가 느껴집니다. 취소를 한 후,

 스크롤을 내려보면 티스토어 개발자 센터에서 테스트용으로 기입했던 캐쉬가 있습니다. 사용하기를 눌른 후 구매를 눌러줍니다.

 마지막으로 인증번호를 기입하면 구매가 완료됩니다.

 이것은 구매완료 메세지가 왔을 때 자바에서 c++로 호출이 잘 되었는지 간단하게 CCMessageBox를 통해 체크해본 결과 화면입니다.

 
 또한 티스토어 개발자 센터 상품등록/관리 -> 부분유료화에서 위와같이 과금 로그 및 구매 내역을 조회할 수 있습니다.

 이렇게 티스토어까지 정복해봤습니다. 이제 올레 마켓과 U+마켓이 남았네요. 추후에 작업하게 되면 정리해보겠습니다.

댓글

  1. 안녕하세요. cocos2d-x로 ios와 android를 동시에 개발하고 있는 사람입니다. 간혹 이슈사항이 생길 때에 웨우영원님의 블로그가 참고가 많이 되었습니다. 다름이 아니라 이번에 2013년 2월 15일에 SKT 부분유료화 API가 버전업이 되었습니다. 버전업이 되면서 libdodo.so 파일과 libUSToolkit.so 파일을 안드로이드 프로젝트 내에 libs\armeabi 와 libs\armeabi-v7a 에 추가하게 되었는데...
    문제는 여기에 파일들을 넣어놓았을 시 NDK 빌드를 하게되면 위에 폴더에 있던 so 파일들이 제거가 되버리면서 기타 so파일들은 새로 생성이 되는데 libdodo.so, libUSToolkit.so 파일은 없어지는 문제가 있습니다. 그래서 일단 없어진 상태에서 다시 수동으로 libdodo.so, libUSToolkit.so 파일들을 각 폴더에 집어넣은뒤 이클립스에서 빌드를 하여 단말기에 넣으면 바로 어플이 중지가 되버리더군요. 그래서 현재 난관에 부딪혀 있는 상태인데 혹시 이런 이슈사항 없으셨는지요? 해결방안이 있다면 여쭙고 싶습니다. ㅎㅎ

    답글삭제
    답글
    1. 찾아주셔서 감사합니다~ 오랜만에 칼퇴하고 집에서 답글을 남기네요.
      일단 저도 cocos2d-x관련 개발은 작년 12월 말 정도를 기점으로 관련 개발을 거의 안하고 있는 상태입니다. 지금은 서버쪽을 해야하는 사항이라. 위와 같은 이슈는 제가 할때는 없던건데.. sk에서 버전업하면서 뭔가 방식을 바꿨나보군요.
      음.. 그 lib어쩌구 so 파일들 말고 제가 정리한거와 같이 jar lib로는 없나요? 보아하니 ndk용 c++ lib인듯한데, java용 jar lib도 아예 없애진 않았을 듯한데... 아니면 둘다 사용해야하는건가;;;
      에고 답변이 안되겠네요...;

      삭제
    2. java용 jar lib도 있구요. so 파일도 생겼습니다. 둘다 사용을 하는식으로 변경이 되었네요...방법을 찾다보면 뭐 어떻게든 해결이 되겠죠 ㅋ 답변해주셔서 감사합니다 ^^
      그나저나 저도 이번 프로젝트를 완료하게 되면 서버를 맡아야 할듯한데 참 상황이 비슷하네요 ㅎㅎ

      삭제
    3. 흠..cocos2d-x 개발자를 위한 배려인건가? ndk용이 생겼군요...
      서버.. 처음하는지라 당황스럽네요 ㅎ... db도 처음이고...
      수고하세요~

      삭제

댓글 쓰기

이 블로그의 인기 게시물

'xxx.exe' 프로그램을 시작할 수 없습니다. 지정된 파일을 찾을 수 없습니다.

goorm IDE에서 node.js 프로젝트로 Hello World Simple Server 만들어 띄워보기

애드센스 수익을 웨스턴 유니온으로 수표대신 현금으로 지급 받아보자.