Unity3D GameNoll SDK Android Integration - 2. Init, Login, In-app Billing

 유니티3D 안드로이드에 중국 GameNoll SDK 연동 준비작업을 정리했었습니다. 이번에는 GameNoll SDK 초기화 및 로그인, 결제처리 클라이언트 부분을 정리해봅니다.


1. GameNoll Init
public class MainActivity extends UnityPlayerActivity {
 private final static String strNollGameNo = "xxxxxxxx";
 private static String strNollGameMemberId;
 private static String strSafeCode;
 private final String strGameVersion = "1.0";
 private final String strSpreadChannel = "91";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
 }
 
 public void NollGameInit_U()
 {
  NollGame.initSDK(
    UnityPlayer.currentActivity
    ///< 할당받은 유니크한 게임 번호
    , strNollGameNo
    ///<  게임 버전
    , strGameVersion
    ///< 홍보 대행사 번호. 중국에서 apk 언팩해서 직접 변경.
    , strSpreadChannel
    ///<  결과를 처리할 콜백 리스너
    , new CallbackNollGame()
    ///< 게임이 자동업데이트를 지원하는지?
    , false);
 }

 public static void NollGameInitOk()
 {
  UnityPlayer.UnitySendMessage("GameNollManager", "NollGameInitSuccess_J", "");
 }

 public static void NollGameSendErrorMsg(JSONObject jsonObj)
 {
  UnityPlayer.UnitySendMessage("GameNollManager", "NollGameError_J", jsonObj.toString());
 }
 GameNoll SDK Init 안드로이드 부분입니다. strNollGameNo 변수에 해당하는 부분을 개발하시는 어플용으로 대체하시면 됩니다.
public class CallbackNollGame extends CallbackListener {
 
 protected void SendErrMsg(int iErrorCode, String strErrorMessage) {
  JSONObject jsonObj = new JSONObject();
  try {
   jsonObj.put("ErrorCode", iErrorCode);
   jsonObj.put("ErrorMessage", strErrorMessage);
  } catch (JSONException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  MainActivity.NollGameSendErrorMsg(jsonObj);
 }

 @Override
 public void onInitSDKError(NollError arg0) {
  // TODO Auto-generated method stub
  String strError = "Init Error. Code : " + arg0.getErrorCode() + " Msg : " + arg0.getErrorMessage();
  Log.e("nollgame", strError);
  SendErrMsg(arg0.getErrorCode(), arg0.getErrorMessage());
 }

 @Override
 public void onInitSDKSuccess() {
  // TODO Auto-generated method stub
  Log.e("nollgame", "Init ok");
  MainActivity.NollGameInitOk();
 }
}
 GameNoll의 CallbackListener을 상속받는 자바 클래스를 위와 같이 하나 만듭니다. SDK 내부의 콜백을 처리하는 클래스입니다. 일단 간단히 초기화부분만 정리해봤습니다.

 public void NollGameInit()
 {
  curActivity.Call("NollGameInit_U");
 }

 void NollGameInitSuccess_J()
 {
  SetJavaLog("NollGameInitSuccess"); 
 }

 void NollGameError_J(string strError)
 {
  SetJavaLog(strError);
  /*
  jsonObj.put("ErrorCode", iErrorCode);
  jsonObj.put("ErrorMessage", strErrorMessage);
  */
  /*
  switch(json.["ErrorCode"])
  {
  case 100:
   //Login Faile
   break;
  case 101:
   //Login Cancel
   break;
  case 102
   //Order Error
   break;
  case 103
   //Payment Cancel
   break;
  case 104
   //Payment Faile
   break;
  case 105
   //SDK Init Faile
   break;
  case 106
   //Character Create Faile
   break;
  }
  */
 }
 이제 유니티부분입니다. GameNollManager 컴포넌트인데요, 간단히 로그만 처리하고 있는데 각 개발사에 맞게 작업을 진행하면 되겠습니다.

  float fYpos = 0;
  GUI.Label(new Rect(0, fYpos, 400, 100), GameNollManager.GetInstance().strLog);
  fYpos += 100;
  if (GUI.Button (new Rect(0, fYpos, 100, 100), "Init") == true)
  {
   GameNollManager.GetInstance().NollGameInit();
  }
 TestGUI 컴포넌트의 OnGUI 부분입니다.

 실행후 Init을 눌러본 스샷입니다. 다른 버튼까지 다 만들고 찍은 스샷이라 버튼들이 미리 있네요.


2. GameNoll Login
 /**
  * 자동 로그인 : memberLogin(true, false);
  * 일반 로그인 : memberLogin(false, true);
  * 계정 교체 : memberLogin(false, false);
  * @param bAutoJoin
  * true. 자동 회원가입. sdk가 계정과 비번생성. 과정이 노출되지 않음.
  * false. 유저가 수동으로 회원가입. SDK 내부에서 페이지 출력.  
  * @param bAutoLogin
  * autojoin == false일때만.
  * true. 계정이 있다면 자동 로그인. 과정이 노출되지 않음. 없다면 입력창 출력.
  * false. 수동 로그인.
  */
 public void NollGameLogin_U(final boolean bAutoJoin, final boolean bAutoLogin)
 {
  runOnUiThread(new Runnable()
  {
   @Override
   public void run() {
    // TODO Auto-generated method stub
    NollGame.memberLogin(bAutoJoin, bAutoLogin);
   }
  });
 }

 /**
  * SDK로부터 로그인 성공후 콜백으로 넘어온 memberid와 safecode를 서버딴에서 유저 인증을
  * 체크해야한다. gamenoll에 get/post로 전달하고 주소는 sdk문서에 있다.
  * @param strMemberId
  * @param strSafeCode
  */
 public static void NollGameLoginOk(String strMemberId, String strSafeCode)
 {
  MainActivity.strNollGameMemberId = strMemberId;
  MainActivity.strSafeCode = strSafeCode;

  JSONObject jsonObj = new JSONObject();
  try {
   jsonObj.put("MemberID", strMemberId);
   jsonObj.put("SafeCode", strSafeCode);
  } catch (JSONException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  UnityPlayer.UnitySendMessage("GameNollManager", "NollGameLoginSuccess_J", jsonObj.toString());
 }
 로그인 처리부분입니다.
 @Override
 public void onLoginCancelled() {
  // TODO Auto-generated method stub
  String strError = "Login Cancelled";
  Log.e("nollgame", strError);
  SendErrMsg(101, strError);
 }

 @Override
 public void onLoginError(NollError arg0) {
  // TODO Auto-generated method stub
  String strError = "Login Error. Code : " + arg0.getErrorCode() + " Msg : " + arg0.getErrorMessage();
  Log.e("nollgame", strError);
  SendErrMsg(arg0.getErrorCode(), arg0.getErrorMessage());
 }

 @Override
 public void onLoginSuccess(String arg0, String arg1) {
  // TODO Auto-generated method stub
  String strError = "Login ok. " + arg0 + " " + arg1;  
  Log.e("nollgame", strError);
  MainActivity.NollGameLoginOk(arg0, arg1);
 }
 로그인 콜백 처리 부분입니다. 만들었던 콜백 클래스에 정의해야합니다.
 public void NollGameLogin(bool bAutoJoin = false, bool bAutoLogin = true)
 {
  curActivity.Call("NollGameLogin_U", bAutoJoin, bAutoLogin);
 }

 void NollGameLoginSuccess_J(string strJson)
 {
  /*
  jsonObj.put("MemberID", strMemberId);
  jsonObj.put("SafeCode", strSafeCode);
  */
  SetJavaLog("NollGameLoginSuccess");
 }
 GameNollManager 컴포넌트의 로그인 부분입니다.
  fYpos += 100;
  if (GUI.Button (new Rect(0, fYpos, 100, 100), "Login") == true)
  {
   GameNollManager.GetInstance().NollGameLogin(false, false);
  }
 마지막으로 TestGUI 컴포넌트에 로그인을 만들었습니다.
 로그인 버튼을 클릭하면 GameNoll 자체 로그인 창이 뜹니다. 계정을 로그인합니다.

 콜백으로 넘어와 GUI.Lavel로 출력됩니다.


3. GameNoll In-app Billing
 /**
  * 결제 페이지를 출력한다.
  * 완료 후 CallbackListener의 onPaymentSuccess, onPaymentError 호출
  * OrderInfo를 인자없이 단순 showPaymentView()를 호출하면 구매 페이지가 SDK에 포함된다. 이때는 운영사와 협의 필요.
  * 게임 서버에도 결과가 전달된다.
  * 클라이언트딴은 결제 내역 확인 용도로만 사용.
  * @param strProductId
  * @param strProductName
  * @param iProductNum
  * @param strProductDesc
  * @param strCost
  */
 public void NollGameShowPayment_U(final String strProductId, final String strProductName, final int iProductNum, final String strProductDesc, final String strCost)
 {
  runOnUiThread(new Runnable()
  {
   @Override
   public void run() {
    // TODO Auto-generated method stub
    OrderInfo orderInfo = new OrderInfo();
    ///<  구매 요청 번호. 중복 불가
    orderInfo.setGameOrderId(Long.toString(System.currentTimeMillis()));
    ///< 유저 멤버 ID, 로그인 성공시 획득
    orderInfo.setMemberId(strNollGameMemberId);
    ///< 게임 번호
    orderInfo.setGameNo(strNollGameNo);
    ///< 게임 서버 번호. 개발사에서 지정. 단독서버는 1
    orderInfo.setServerNo("1");
    ///< 상품 ID. 결제 처리 후 다시 리턴됨.
    orderInfo.setProductId(strProductId);
    ///< 상품 이름.
    orderInfo.setProductName(strProductName);
    ///< 상품 수량.
    orderInfo.setProductNum(iProductNum);
    ///< 상품 설명. 선택사항.
    orderInfo.setProductDesc(strProductDesc);
    ///< 상품 가격. 소수점 아래 2자리까지 표기. 10원은 10.00
    orderInfo.setAmount(new BigDecimal(strCost));
    ///< 화폐 단위
    orderInfo.setCurrency("CNY");
    ///< 구매 관련 기타 정보. 선택사항.
    //orderInfo.setExtInfo("extinfo");
    NollGame.showPaymentView(orderInfo);
   }
  });
 }

 public static void NollGamePaymentOk(JSONObject jsonObj)
 {
  UnityPlayer.UnitySendMessage("GameNollManager", "NollGamePaymentSuccess_J", jsonObj.toString());
 }
 마지막으로 GameNoll 결제창 처리 안드로이드 부분입니다.
 @Override
 public void onPaymentCancelled() {
  // TODO Auto-generated method stub
  String strError = "Payment Cancelled";
  Log.e("nollgame", strError);
  SendErrMsg(103, strError); 
 }

 @Override
 public void onPaymentError(NollError arg0) {
  // TODO Auto-generated method stub
  String strError = "Payment Error. Code : " + arg0.getErrorCode() + " Msg : " + arg0.getErrorMessage();
  Log.e("nollgame", strError);
  SendErrMsg(arg0.getErrorCode(), arg0.getErrorMessage());
 }

 @Override
 public void onPaymentSuccess(Transaction arg0) {
  // TODO Auto-generated method stub
  JSONObject jsonObj = new JSONObject();
  try {
   ///< SDK 결제 시스템에서 생성한 구매 명령 번호.
   jsonObj.put("OrderId", arg0.getOrderId());
   ///< 결제 대행사에서 생성한 결제 거래 번호.
   jsonObj.put("TransactionId", arg0.getTransactionId());
   ///< 게임 클라이언트에서 생성한 구매 명령 번호.
   jsonObj.put("GameOrderId", arg0.getGameOrderId());
   ///< 유저 ID.
   jsonObj.put("MemberId", arg0.getMemberId());
   ///< 게임 ID.
   jsonObj.put("GameNo", arg0.getGameNo());
   ///< 서버 번호. 개발사 지정.
   jsonObj.put("ServerNo", arg0.getServerNo());
   ///< 결제 대행사.
   jsonObj.put("Channel", arg0.getChannel());
   ///< 결제 수단.
   jsonObj.put("Method", arg0.getMethod());
   ///< 결제 금액.
   jsonObj.put("Amount", arg0.getAmount());
   ///< 결제 상태.SUCCESS이면 ok
   jsonObj.put("Status", arg0.getStatus());
   ///< 상품 ID.
   jsonObj.put("ProductId", arg0.getProductId());
   ///< 화폐 단위.
   jsonObj.put("Currency", arg0.getCurrency());
   ///< 기타 정보.
   jsonObj.put("ExtInfo", arg0.getExtInfo());
   ///< 암호화 문자열. 암호화 인증에 필요.
   jsonObj.put("Sig", arg0.getSig());
  } catch (JSONException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  String strError = "Payment ok. " + jsonObj.toString();
  Log.e("nollgame", strError);
  
  MainActivity.NollGamePaymentOk(jsonObj);
 }
 결제 콜백 처리입니다.
 public void NollGameShowPayment(string strProductId, string strProductName, int iProductNum, string strProductDesc, string strCost)
 {
  curActivity.Call("NollGameShowPayment_U", strProductId, strProductName, iProductNum, strProductDesc, strCost);
 }

 void NollGamePaymentSuccess_J(string strJson)
 {
  SetJavaLog("NollGamePaymentSuccess");
 }
 GameNollManager 컴포넌트에 결제창 처리부분입니다. 중국 마켓들은 애플이나 구글과 같이 앱에서 아이템을 설정하는게 아니고 이런식으로 함수 호출을 하면서 인자를 넘겨줘서 구매할 아이템을 설정하네요.
  fYpos += 100;
  if (GUI.Button (new Rect(0, fYpos, 100, 100), "Payment") == true)
  {
   GameNollManager.GetInstance().NollGameShowPayment("testProduct1", "testName", 1, "testDesc", "1.00");
  }
 마지막으로 TestGUI에서 호출하는 부분입니다. 각 게임에 맞게 구매 아이템 값을 설정해주면 되겠죠.

 결제 요청화면입니다.

 이건 취소화면이구요.

 이것으로 유니티3D 안드로이드에 중국 GameNoll SDK 연동하는 것을 마무리해봅니다. 처음에 언급했듯이 서버 부분은 없습니다. 결제 Callback의 경우 SDK에서 onPaymentSuccess를 호출합니다만 GameNoll에서 개발사의 게임서버도 post 방식으로 전달합니다. 넘어온 sig값을 가지고 암호화 인증을 한 후 GameNoll 결제서버에 결과를 보내야합니다. 실제 운영 매출 정산에서는 GameNoll 결제서버가 리턴 받은 인증성공 로그를 사용한다고하니 정확한 리턴값을 보장해 줘야겠습니다.

 다음에는 또 다른 중국 마켓인 91 마켓의 플랫폼 SDK를 적용하는 것을 정리해보겠습니다.

댓글

이 블로그의 인기 게시물

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

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

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