SSISO Community

시소당

구글 인앱결제 v3

 구글 인앱결제 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" />



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<p>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</p><p></p><string> 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;
 
        }
 
    };
 
}
</string>

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라든지 등등)  서비스하고 있는 서버에 저장하고 있다면 결제 취소시에도  변경된 정보를 관리 할 수 있을것 같습니다.
  

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

출처 : http://ondestroy.tistory.com/entry/%EA%B5%AC%EA%B8%80-%EC%9D%B8%EC%95%B1%EA%B2%B0%EC%A0%9C-v3

3963 view

4.0 stars