TA/Unity2013. 8. 29. 14:39

유니티게임 구글 인앱 결제 붙이기!!d Unity

2013/03/11 19:16

복사 http://blog.naver.com/psd0217/10162792878

전용뷰어 보기

1. 먼저 만들어진 유니티게임을 빌드 하여 APK파일을 만들어서 구글 플레이 개발자 콘솔 사이트 들어가서 어플을 등록해 주세요~!

물론 여기까지 들어오려면 개발자 등록을 해야 한다.

돈이 듭니다...ㅠㅠ

우선 매인은 이게 아니니까 패스 하고

새 애플리케이션 추가 클릭 클릭

 

이런화면이 뜨는데 1번 에 당연히 어플이름을 적어주시면 되고

APK업로드 누르시면 업로드가 됩니다.

 

여기서도 잠깐 업로드가 안된다고요??

그렇다면 유니티 빌드할때 키를 넣지 않았다는 뜻인데요

이것도 인터넷 쪼금만 찾아보면 나오는 것이니까 패스 할게요~!

 

자!! 여기서 궁금증?? 왜 인앱 시스템을 집어 넣지도 않았는데 어플을 업로드 했나요??

그건 밑에 설명해 드릴께요 차근차근 합니다

 

아 그리고 업로드 한다고 바로 어플 다운이 되고 구글 플레이에서 검색이 되고 이러는거 아니니까 걱정 마세요

어플 활성화 버튼을 누르지 않는 이상 어플은 완전히 등록 된것이 아니기 때문에 상관 없습니다.

 

자 다음은~유니티로 돌아가서~~

 

이부분은 다들 아시겠죠???

파일 -> 빌드 셋팅 -> 플레이어 셋팅

을 하시면~ 밑에처럼

이렇게 나오죠 ㅋㅋ

당연히 빌드를 했다면 저기 번들 이름을 지정하셧겟죠???

이거 복사 해 두세요~! ㅋ

 

자 다음은 이클립스에서 안드로이드 프로젝트를 생성해 볼까요?

자 프로젝트를 생성하다보면 패키지 이름을 지정하라고 나오죠???

방금 유니티에서 복사한 번들 이름 집어 넣어 주세요

자자 다음은 

생성된 프로젝트에서 오른쪽 마우스 클릭

그리고 properties를 눌러 주세요~!

이런화면이 나오는데 순서대로 눌러 주세요~!


자 그럼 저 파일을 찾아야 하는데 어딧을까요??ㅋ

경로는 Program File->Unity->Editor->Data->PlaybackEngines->androidplayer->bin

이경로에 있습니다 ㅋ

없다고요?? 그럴리가

유니티가 설치되어 있다면 당연히 있어야 정상입니다

없으면...구글링 혹은 유니티 재설치 ㄱㄱ
무튼 열기를 누르면

이번에도 순서대로 누르시기만 하면 됩니다.



위처럼 프로젝트 안에 classes.jar파일이 생성 되었다면 완료~!

이로써 이클립스에서 유니티 함수들을 불러다 쓸수 있게 되었습니다~~~짝짝짝~!

끝낫냐고요???

아직 멀었으니 따라 오세요


자 그러면 다음은 아래의 파일을 다운받아서 압축 풀고 임포트를 시켜 주세요

BillingTest.zip

위 그림처럼 src폴더에 복사해 주세요

그리고 다시 구글 플래이 개발자 콘솔로 돌아와서

여기서 왜 인앱결제 시스템을 붙이지 않고 어플을 등록 시켰는지 이해를 하게 될거에요

왜냐면 위의 그림처럼 인앱시스템을 구축하려면 구글에서 주는 키를 등록해 주어야 하는데

이 소스에서는 이부분을 소스 코드 안에서 처리를 해주기 때문이죠~! ㅋ

위 소스를 복사해서~

조기에 붙여넣어 주세요

잘 안보이시나???

babyaba.Test.billing 밑에 있는Security 클래스에 base64EncodedPublicKey부분에 붙여 넣어주시면 됩니다

 

그림으로는 안나와 있지만 MainActivity 소스를 아래처럼 바꿔 줍니다

 

 

 

 

 

import bayaba.test.billing.BillingService;

import bayaba.test.billing.Consts;

import bayaba.test.billing.PurchaseObserver;

import bayaba.test.billing.ResponseHandler;

import bayaba.test.billing.BillingService.RequestPurchase;

import bayaba.test.billing.BillingService.RestoreTransactions;

import bayaba.test.billing.Consts.PurchaseState;

import bayaba.test.billing.Consts.ResponseCode;

import com.Bumblebee.CatsIsland.MainActivity;

 

import com.unity3d.player.UnityPlayer;

import com.unity3d.player.UnityPlayerActivity;

 

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.app.AlertDialog;

import android.content.DialogInterface;

 

public class MainActivity extends UnityPlayerActivity {

 

    private GamePurchaseObserver mPurchaseObserver;

    private Handler mHandler;

    private BillingService mBillingService;

  

    private class GamePurchaseObserver extends PurchaseObserver

    {

        public GamePurchaseObserver(Handler handler) {

            super(MainActivity.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:

UnityPlayer.UnitySendMessage("AndroidManager", "CharacterPurchaseState", itemId );

// 현재 구매 확인

break;

case CANCELED:

//UnityPlayer.UnitySendMessage("AndroidManager", "LabelLog", "CANCELED" + itemId );

// 취소 ..

break;

/*

case REFUNDED:

UnityPlayer.UnitySendMessage("AndroidManager", "LabelLog", "REFUNDED" + itemId );

// 환불 ..

break;

*/

default:

break;

}

        }

 

        @Override

        public void onRequestPurchaseResponse(RequestPurchase request, ResponseCode responseCode)

        {

            if (responseCode == ResponseCode.RESULT_OK) 

            {

            // 확인 메시지

            UnityPlayer.UnitySendMessage("AndroidManager", "PurchaseResult", "ok" );

            // 확인된 아이템 아이디

            UnityPlayer.UnitySendMessage("AndroidManager", "PurchaseOk", "" + request.mProductId );

           

            if (Consts.DEBUG) 

            {

                    //Log.i(TAG, "purchase was successfully sent to server");

                }

            }

            else if (responseCode == ResponseCode.RESULT_USER_CANCELED) 

            {

            // 취소 메시지

            UnityPlayer.UnitySendMessage("AndroidManager", "PurchaseResult", "cancle" );

            // 취소된 아이템 아이디

            UnityPlayer.UnitySendMessage("AndroidManager", "PurchaseCancle", "" + request.mProductId );

           

                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);

}

        }

    }

    

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

        

        InitBiling();

}

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") )

{

UnityPlayer.UnitySendMessage("AndroidManager", "LabelLog", "PurchaseError");

}

}

//public void initActivity(String tagFromUnity, String messageFromUnity)

    //{

    // UnityPlayer.UnitySendMessage("AndroidManager", "AndroidLog", "[" + tagFromUnity + "]" + messageFromUnity);

    //}

public void quitApplication()

    {

handler.sendEmptyMessage(0);

    }

public Handler handler = new Handler()

{

public void handleMessage(Message msg)

{

switch(msg.what)

{

case 0:

finishMessage();

}

}

};

public void finishMessage()

{

AlertDialog.Builder builder = new AlertDialog.Builder(this);

builder.setMessage("프로그램을 종료 하시겠습니까?");

builder.setCancelable(false);

builder.setPositiveButton("예", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which)

{

UnityPlayer.UnitySendMessage("AndroidManager", "ApplicationQuit","");

}

});

builder.setNegativeButton("아니요", new DialogInterface.OnClickListener(){

@Override

public void onClick(DialogInterface dialog, int which)

{

dialog.cancel();

}

});

builder.show();

}

@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);

}

 

}




이 클래스로 유니티와 함수 호출을 왔다갔다 해줍니다.


 


이대로 프로젝트를 익스포트 해주시구요

 

jar파일을 선택해서

1번 처럼 체크를 해주시고 

2번처럼 경로와 파일이름을 지정해 주시고

finish!!!

이로서 플러그인 완전 완성~!!!!!

안된다구요??

끝~!!!! 이었으면 좋았으나 아직 좀 남았습니다~!

다시 유니티로 돌아와서

빌드를 해주시는데~

이미 빌드했다면 안해 줘도 됨 ㅋ

프로젝트 경로로 쭉쭉 들어가서 Temp폴더를 살펴 보시면 위 폴더가 보일거에요~!

다 필요 없고

그안에 있는 매니 패스트만 복사 해서 다른 폴더에 넣어주세요

아까 생성한 jar파일 있는곳에 같이 넣어주면 좋구요

자 다시 유니티에서 Plugins 폴더와 Android폴더를 만들어서 그 밑에

두파일을 집어 넣어 주세요

위 경로는 무조건 저렇게

한글자라도 틀리면 못읽어 오니까 주의 하시구요~!!!

 

그리고~! 매니페스트 파일을 열어 보시면

밑에 처럼 뭐라뭐라 솰랴 솰랴 하는데

다 필요 없고요

1번 젤위 의 페키지 명을 플러그인으로 가져온(이클립스에서 가져온) jar파일에있는 패키지명..com.어쩌고.어쩌고 했던 그거 적어 주세요~!

2번 부분에는 3번에 있는 MAIN이랑 LANCHER 이부분이 있을탠대요 싹 지워 주세요

이유는 뭐랄까 저부분은 다른 패키지 명으로 열어줘야 해서?? 라고 답해드리죠  매인이 두번 올순 없으니까요

3번은 그냥 그대로 적어주세요

대략 내용은 위에서 지운 매인부분 넣어주고 결제 시스템 클래스들을 같이 써주기 위함이죠

아 그리고 깜빡하고 위의 그림에서 그리지 않은 부분이 있는데요

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

그림 밑에 쪽에 보시면 이 소스 보이시죠

꼭 써줘야 결제가 됩니다~!!!

 

다시 유니티로 돌아와서~!!!

 

 

위 처럼 안드로이드매니져 클래스를 만들어 주세요

당연 클래스 이름 저거랑 같아야 됩니다. 왜냐면 아까 이클립스에서 호출하는 클래스 이름을 저걸로 해뒀거든요 쭉 살펴 보시면 아실거에요

이 클래스에는

 

 

using UnityEngine;

using System.Collections;

 

public class AndroidManager : MonoBehaviour

{

    private static AndroidManager _instance;

 

    public string androidLog = "No Log";

public string fps = "No fps";

public string purchaseOkItemID = "";

public string purchaseCancleItemID = "";

public bool character2State = false;

public bool character3State = false;

public bool character4State = false;

public bool character5State = false;

public bool purchaseOk = false;

public bool purchaseCancle = false;

 

//#if UNITY_ANDROID && !UNITY_EDITOR

 

    public AndroidJavaObject activity;

 

    void Awake()

    {

 

        AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");

        activity = jc.GetStatic<AndroidJavaObject>("currentActivity");

    }

 

//#endif

 

void OnGUI()

{

GUI.Label( new Rect( 10, 10, 200, 20 ), "fps : " + fps );

GUI.Label( new Rect( 10, 30, 600, 20 ), "" + androidLog );

GUI.Label( new Rect( 10, 50, 600, 20 ), "character2State : " + character2State );

GUI.Label( new Rect( 10, 70, 600, 20 ), "character3State : " + character3State );

GUI.Label( new Rect( 10, 90, 600, 20 ), "character4State : " + character4State );

GUI.Label( new Rect( 10, 110, 600, 20 ), "character5State : " + character5State );

GUI.Label( new Rect( 10, 130, 600, 20 ), "purchaseOk : " + purchaseOk );

GUI.Label( new Rect( 10, 150, 600, 20 ), "purchaseCancle : " + purchaseCancle );

}

public void Buy( string ItemID )

{// 이클립스에서 작성한 클래스에서 BuyItem함수를 호출하는겁니다. 물론 뒤에는 인자값임

activity.Call("BuyItem", "" + ItemID );

}

public void Exit()

{// 위와 같이 함수를 호출하는거입니다

activity.Call("quitApplication");

}

// 이 밑에 부분은 신경 안쓰셔도 되고 쓰셔도 되고

// 대강 설명하자면 이클립스에서 만든 클래스에서 불려 쓰이는 함수들입니다.

 

void PurchaseOk( string ItemID )

{// 현재 무슨 아이템이 구매가 되었는지를 알아오는함수

purchaseOkItemID = ItemID;

}

void PurchaseCancle( string ItemID )

{// 현재 무슨 아이탬이 취소가 되었는지 알아오는 함수

purchaseCancleItemID = ItemID;

}

void PurchaseResult( string result )

{// 현재 아이템을 결재 했는지 취소했는지 알아오는함수

if( "ok" == result )

{

purchaseOk = true;

}

else if( "cancle" == result )

{

purchaseCancle = true;

}

}

void CharacterPurchaseState(string itemID)

{// 현재까지 결재된 아이템이 무었인지 알려주는 함수 (당연히 수정해서 쓰시겟죠?)

if( "character2" == itemID )

{

character2State = true;

}

if( "character3" == itemID )

{

character3State = true;

}

if( "character4" == itemID )

{

character4State = true;

}

if( "character5" == itemID )

{

character5State = true;

}

}

void ApplicationQuit(string message)

{// 이함수가 불리는순간 게임 종료

Application.Quit();

}

void LabelLog(string message)

{// 에러 매시지 같은 로그를 받아옵니다. 

// 인앱부분은 핸드폰 기기에서만 사용할수 있기 때문에 애러같은것을 라벨로 로그를 남겨줌

androidLog = "Log : " + message;

}

// 당연 어떤 클래스에서 불릴수 있는 싱글톤의 매력~!!!

    public static AndroidManager Instance

    {

        get

        {

            if (_instance == null)

            {

                _instance = FindObjectOfType(typeof(AndroidManager)) as AndroidManager;

                if (_instance == null)

                {

                    _instance = new GameObject("AndroidManager").AddComponent<AndroidManager>();

                }

            }

 

            return _instance;

        }

    }

}

 

대략 요딴식으로 적어주시면 되는대요

설명은 주석으로 달려있으니까 확인해 보세요

결재 되는 부분(클래스 or 함수)에서

AndroidManager.Instance.Buy( _itemID );

이런식으로만 써주면 바로 결재 들어갑니다.ㅋㅋ

 

자 다음은 다시 구글 플래이 게발자 콘솔로 돌아와서

인앱제품 부분으로 들어가서

새 제품 추가를 하시면~~~


 

위 그림처럼 나오는데요

관리되는 제품 관리되지 않은 제품으로 나뉘게 됩니다.

뭐 인터넷 조금만 확인해 보시면 되실꺼지만

관리되는 제품은 구글 서버에서 이아이템을 가지고 있는지 아닌지를 알아서

단 한번만 제품을 구매하게끔 만들어 줍니다.

관리되지 않는 제품은 

예를 들면 게임에서 게임머니같은 건대요

여러번 구매 할수 있습니다.

제품ID는 자신이 짠 소스 itemID와 일치 시켜야 합니다

뭐 간단한 설명과 아이템 이름을 적어주고

활성화를 시켜줍니다.

 

이렇게 모든게 끝이 났습니다.

그러면 다시 유니티 빌드를 해주시고

구글 콘솔에 APK파일을 다시 업로드 해주시고(당연히 전버전과는 버전코드와 번호가 달라야 올라가겠죠??)

테스트 아이디도 입력해 주시고~!!!(이 아이디는 테스트 대상자 폰의 구글 계정과 일치 해야 합니다.)

테스트 아이디는 개발자 콘솔 왼쪽에 설정 누르면 나옵니다~!!!!

두세시간후에 구매를 해보시면~!!

짜잔 결제가 됩니다~!!!!

물론 진짜로 결제 되 버림 ㅠㅠㅠ

이거 환불 받으세요 이부분은 인터넷 참조해 주쌔요~!ㅋㅋㅋㅋ

 

 

Posted by 프리랜서 디자이너