BLOG main image
분류 전체보기 (74)
Cocos2d (9)
낙서장 (4)
스토리지 (1)
안드로이드 (54)
유용한링크 (1)
모바일게임 (2)
추천앱 (1)
아이폰 (0)
맛집/여행 (1)
ナイトウェアメンズ
ナイトウェアメンズ
割烹着 オシャレ
割烹着 オシャレ
klicken Sie einfach auf die bi..
klicken Sie einfach auf die bi..
スポーツ
スポーツ
サンダル
サンダル
282,399 Visitors up to today!
Today 42 hit, Yesterday 39 hit
daisy rss
tistory 티스토리 가입하기!
2014.04.28 17:59
  

- 구글 인앱결제 v3 예제입니다. 


- http://westwoodforever.blogspot.kr/2013/10/unity3d-integration-google-in-app.html 

  http://theeye.pe.kr/archives/2130

  위 링크에서 퍼왔습니다(감사합니다!)


- 아이템등록법 취소방법등을 추가하였습니다.



1. 구글 인앱 빌링 라이브러리 설치 및 임포트는 아래링크를 참고하십시오.

  http://westwoodforever.blogspot.kr/2013/10/unity3d-integration-google-in-app.html 


2. Buy 버튼을 누르면 인앱 결제창이 뜨고 결제가 되는 예제입니다.


매니페스트에 추가해주세요!
<uses-permission android:name="com.android.vending.BILLING" />



import java.util.List; import org.json.JSONException; import org.json.JSONObject; import com.android.vending.billing.IInAppBillingService; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class InAppTestActivity extends Activity { IInAppBillingService mService; IabHelper mHelper; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main1); bindService(new Intent( "com.android.vending.billing.InAppBillingService.BIND"), mServiceConn, Context.BIND_AUTO_CREATE); String base64EncodiedPushedkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCphx6V1V9XXqe" + "XGgPMHgEtq64/199fDj0n46H2Gw7Qje+WXJKboCTvydomWUhpCxSknklv/7XhBC4/UI0VbWCVnWSz" + "+D2WYS+phunjtluImwAoT33/oV7Z4hempYKdPDaR24txT6GJgzT7ATJKffO6Wi4TgVILNcIQ1/LpXBALFvEFy" + "WiLEz5FB0hO4eemZtgnWTvUlsT7mdCo704l2PpfNtlpVwUixUVk21bHKiklVcR7AzI3yxFPa8SFSfNe4D7j5prBxSl" + "35wP5s5bRB0lsJ2DeaY8T9bdfZLqb8/ZObf68j8r7mVau9CIqDR/gpPjFUHam1RRPpiZPDxxxxxxx"; // developer console -> 서비스및 API -> 어플리케이션용 라이센스 키를 복사해서 넣으시면 됩니다. InAppInit_U(base64EncodiedPushedkey, true); Button innapp1 = (Button) findViewById(R.id.innapp1); innapp1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { InAppBuyItem_U("item01"); // 제품id를 써줍니다. 앱배포시에 인앱상품등록시 등록할 id입니다. } }); } public void InAppInit_U(String strPublicKey, boolean bDebug) { Log.d("myLog", "Creating IAB helper." + bDebug); mHelper = new IabHelper(this, strPublicKey); if (bDebug == true) { mHelper.enableDebugLogging(true, "IAB"); } mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { // TODO Auto-generated method stub boolean bInit = result.isSuccess(); Log.d("myLog", "IAB Init " + bInit + result.getMessage()); if (bInit == true) { Log.d("myLog", "Querying inventory."); mHelper.queryInventoryAsync(mGotInventoryListener); } Toast.makeText(InAppTestActivity.this, "InAppInit_U", Toast.LENGTH_SHORT).show(); } }); } IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { Log.d("myLog", "Failed to query inventory: " + result); SendConsumeResult(null, result); return; } /* * Check for items we own. Notice that for each purchase, we check * the developer payload to see if it's correct! See * verifyDeveloperPayload(). */ List

inappList = inventory .getAllOwnedSkus(IabHelper.ITEM_TYPE_INAPP); // inappList.add("item01"); for (String inappSku : inappList) { Purchase purchase = inventory.getPurchase(inappSku); Log.d("myLog", "Consumeing ... " + inappSku); mHelper.consumeAsync(purchase, mConsumeFinishedListener); } Log.d("myLog", "Query inventory was successful."); } }; public void InAppBuyItem_U(final String strItemId) { runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub /* * TODO: for security, generate your payload here for * verification. See the comments on verifyDeveloperPayload() * for more info. Since this is a SAMPLE, we just use an empty * string, but on a production app you should carefully generate * this. */ String payload = "user_id"; mHelper.launchPurchaseFlow(InAppTestActivity.this, strItemId, 1001, mPurchaseFinishedListener, payload); Log.d("myLog", "InAppBuyItem_U " + strItemId); } }); } IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { Log.d("myLog", "Purchase finished: " + result + ", purchase: " + purchase); //결제 완료 되었을때 각종 결제 정보들을 볼 수 있습니다. 이정보들을 서버에 저장해 놓아야 결제 취소시 변경된 정보를 관리 할 수 있을것 같습니다~ if (purchase != null) { if (!verifyDeveloperPayload(purchase)) { Log.d("myLog", "Error purchasing. Authenticity verification failed."); } mHelper.consumeAsync(purchase, mConsumeFinishedListener); } else { Toast.makeText(InAppTestActivity.this, String.valueOf(result.getResponse()), Toast.LENGTH_SHORT).show(); } } }; boolean verifyDeveloperPayload(Purchase p) { String payload = p.getDeveloperPayload(); /* * TODO: verify that the developer payload of the purchase is correct. * It will be the same one that you sent when initiating the purchase. * * WARNING: Locally generating a random string when starting a purchase * and verifying it here might seem like a good approach, but this will * fail in the case where the user purchases an item on one device and * then uses your app on a different device, because on the other device * you will not have access to the random string you originally * generated. * * So a good developer payload has these characteristics: * * 1. If two different users purchase an item, the payload is different * between them, so that one user's purchase can't be replayed to * another user. * * 2. The payload must be such that you can verify it even when the app * wasn't the one who initiated the purchase flow (so that items * purchased by the user on one device work on other devices owned by * the user). * * Using your own server to store and verify developer payloads across * app installations is recommended. */ return true; } // Called when consumption is complete IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() { public void onConsumeFinished(Purchase purchase, IabResult result) { Log.d("myLog", "Consumption finished. Purchase: " + purchase + ", result: " + result); SendConsumeResult(purchase, result); } }; protected void SendConsumeResult(Purchase purchase, IabResult result) { JSONObject jsonObj = new JSONObject(); try { jsonObj.put("Result", result.getResponse()); if (purchase != null) { jsonObj.put("OrderId", purchase.getOrderId()); jsonObj.put("Sku", purchase.getSku()); jsonObj.put("purchaseData", purchase.getOriginalJson()); jsonObj.put("signature", purchase.getSignature()); Log.d("myLog", "OrderId" + purchase.getOrderId()); Log.d("myLog", "Sku" + purchase.getSku()); Log.d("myLog", "purchaseData" + purchase.getOriginalJson()); Log.d("myLog", "signature" + purchase.getSignature()); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("myLog", "onActivityResult(" + requestCode + "," + resultCode + "," + data); if (requestCode == 1001) { // Pass on the activity result to the helper for handling if (!mHelper.handleActivityResult(requestCode, resultCode, data)) { // not handled, so handle it ourselves (here's where you'd // perform any handling of activity results not related to // in-app // billing... super.onActivityResult(requestCode, resultCode, data); } else { Log.d("myLog", "onActivityResult handled by IABUtil."); } } } @Override protected void onDestroy() { super.onDestroy(); if (mServiceConn != null) { unbindService(mServiceConn); } } ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = IInAppBillingService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; } }; }

3. 위에 예제를 돌려보면 결제하기를 하면 제품이 없다고 나옵니다. 당연히 제품을 등록안했으니 안나오겠죠^^; 


 4. 인앱결제로 팔 아이템을 등록( http://theeye.pe.kr/archives/2130 에 잘 설명되어 있습니다) 
 1) 위에 예제를 빌드하셔서 배포용 apk로 만든 후 https://play.google.com/apps/publish 가서 스토어 등록 정    보들을 입력하고 apk를 등록합니다.
 2) 스토어 등록 정보에서 인앱상품을 클릭합니다. 
 3) 세 제품 추가를 클릭합니다. 
 4) 관리되는제품/관리되지않는제품/구독 중 하나를 선택하고 제품ID를 입력 후 계속을 클릭합니다. (위에 예제     에 제품ID는 item01로 하였습니다)
 5) 제목/설명/기본가격을 입력 후 상단의 비활성화 버튼을 활성화로 바꿔줍니다. 
 6) 모두 완료 되었으면 앱을 출시합니다!

 5. 주문 취소하기
  1) 인앱상품은 환불의 의무가 없다고 하는데요 . 그래도 취소해달라는 사람이 있을수도 있겠죠?
  2) https://wallet.google.com/merchant 로 이동합니다. 위에 등록한 앱과 같은 계정으로 로그인합니다
  3) 로그인 하면 결제 정보들이 보이는데 리스트를 클릭해서 상세 정보를 봅니다.
  4) 오른쪽 상단에 보면 취소/환불 버튼이 있습니다. 취소버튼만 활성화 되어있습니다
  5) 취소를 누르고 취소 사유를 입력하면 결제취소가 됩니다. 
  6) 인앱결제가 완료되었을때 각종 결제 정보들을(주문id라든지 등등)  서비스하고 있는 서버에 저장하고 있다면 결제 취소시에도  변경된 정보를 관리 할 수 있을것 같습니다.
  

다들 성공하시길 빕니다!!








개발자 | 2014.10.09 20:23 신고 | PERMALINK | EDIT/DEL | REPLY
감사합니다. 덕분에 쉽게 v2에서 v3로 갈아탈 수 있게 되었습니다.
Name
Password
Homepage
Secret