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..
スポーツ
スポーツ
サンダル
サンダル
285,524 Visitors up to today!
Today 4 hit, Yesterday 15 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