Skip to content

Instantly share code, notes, and snippets.

@niusounds
Created January 15, 2014 06:27
Show Gist options
  • Save niusounds/8431722 to your computer and use it in GitHub Desktop.
Save niusounds/8431722 to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import com.android.vending.billing.IInAppBillingService;
import com.googlecode.androidannotations.annotations.AfterInject;
import com.googlecode.androidannotations.annotations.Background;
import com.googlecode.androidannotations.annotations.EBean;
import com.googlecode.androidannotations.annotations.RootContext;
@EBean
public class InAppBillingUtils {
public static final String TEST_PURCHASED = "android.test.purchased";
public static final String TEST_CANCELED = "android.test.canceled";
public static final String TEST_REFUNDED = "android.test.refunded";
public static final String TEST_ITEM_UNAVAILABLE = "android.test.item_unavailable";
private static final int API_VER = 3;
private static final String TYPE = "inapp";
private static final String IN_APP_BILLING_SERVICE_ACTION = "com.android.vending.billing.InAppBillingService.BIND";
@RootContext
Activity activity;
private IInAppBillingService inAppBillingService;
private ServiceConnection serviceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
inAppBillingService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
inAppBillingService = IInAppBillingService.Stub.asInterface(service);
}
};
@AfterInject
void init() {
activity.bindService(new Intent(IN_APP_BILLING_SERVICE_ACTION), serviceConn, Context.BIND_AUTO_CREATE);
}
/**
* You must call this method in caller's onDestroy.
*/
public void release() {
if (serviceConn != null) {
activity.unbindService(serviceConn);
}
}
/**
* InAppBillingサービスが利用可能になるまで待機する。
* @return
*/
public boolean waitForConnection() {
try {
while (isConnected() == false) {
Thread.sleep(100);
}
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
/**
* 接続されているかどうかを返す。
* @return
*/
public boolean isConnected() {
return inAppBillingService != null;
}
/**
* InAppBilling v3がサポートされているかを返す。
* @return
* @throws RemoteException
*/
public boolean isBillingSupported() throws RemoteException {
int response = inAppBillingService.isBillingSupported(API_VER, activity.getPackageName(), TYPE);
return response == 0;
}
/**
* 商品の詳細情報を取得する。
* @param productIds
* @return
* @throws RemoteException
* @throws JSONException
*/
public SkuDetails getSkuDetails(String... productIds) throws RemoteException, JSONException {
ArrayList<String> skuList = new ArrayList<String>();
Collections.addAll(skuList, productIds);
return getSkuDetails(skuList);
}
/**
* 商品の詳細情報を取得する。
* @param skuList
* @return
* @throws RemoteException
* @throws JSONException
*/
public SkuDetails getSkuDetails(ArrayList<String> skuList) throws RemoteException, JSONException {
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle result = inAppBillingService.getSkuDetails(API_VER, activity.getPackageName(), TYPE, querySkus);
SkuDetails details = new SkuDetails();
details.success = result.getInt("RESPONSE_CODE") == 0;
List<SkuDetail> list = new ArrayList<SkuDetail>();
for (String json : result.getStringArrayList("DETAILS_LIST")) {
list.add(parseSkuDetail(json));
}
details.detailsList = list;
return details;
}
/**
* 購入リクエストを送るためのIntentを取得する。
* @param productId
* @param developerPayload
* @return
* @throws RemoteException
*/
public PendingIntent getBuyIntent(String productId, String developerPayload) throws RemoteException {
Bundle result = inAppBillingService.getBuyIntent(API_VER, activity.getPackageName(), productId, TYPE, developerPayload);
if (result.getInt("BILLING_RESPONSE_RESULT_OK") == 0) {
return result.getParcelable("BUY_INTENT");
} else {
return null;
}
}
/**
* 購入リクエストを実行する。
* @param requestCode
* @param intent
* @throws SendIntentException
*/
public void buy(int requestCode, PendingIntent intent) throws SendIntentException {
activity.startIntentSenderForResult(intent.getIntentSender(), requestCode, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
}
/**
* 指定した商品を購入するリクエストを実行する。結果は呼び出し元のActivityのonActivityResultに渡される。<br>
* 結果はActivity.RESULT_OK (1) または Activity.RESULT_CANCELED (0)
* @param requestCode
* @param productId
* @param developerPayload
* @throws RemoteException
* @throws SendIntentException
*/
public void buy(int requestCode, String productId, String developerPayload) throws RemoteException, SendIntentException {
PendingIntent intent = getBuyIntent(productId, developerPayload);
buy(requestCode, intent);
}
/**
* ランダムに生成したペイロードを使用して購入リクエストを実行する。
* @param requestCode
* @param productId
* @return developerPayload
* @throws RemoteException
* @throws SendIntentException
*/
public String buy(int requestCode, String productId) throws RemoteException, SendIntentException {
String developerPayload = "payload" + new Random().nextLong();
PendingIntent intent = getBuyIntent(productId, developerPayload);
buy(requestCode, intent);
return developerPayload;
}
/**
* 購入リクエストを非同期で実行する。
* @param requestCode
* @param productId
* @param developerPayload
*/
@Background
public void buyAsync(int requestCode, String productId, String developerPayload) {
try {
buy(requestCode, productId, developerPayload);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 購入リクエストを非同期で実行する。
* @param requestCode
* @param productId
*/
@Background
public void buyAsync(int requestCode, String productId) {
try {
buy(requestCode, productId);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 購入済み商品のデータを取得する。
* @return
* @throws RemoteException
* @throws JSONException
*/
public Purchases getPurchases() throws RemoteException, JSONException {
Bundle ownedItems = inAppBillingService.getPurchases(API_VER, activity.getPackageName(), TYPE, null);
int response = ownedItems.getInt("RESPONSE_CODE");
if (response == 0) {
Purchases purchases = new Purchases();
purchases.continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
purchases.list = new ArrayList<Purchase>();
ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
for (int i = 0; i < purchaseDataList.size(); ++i) {
Purchase purchase = new Purchase();
purchase.data = purchaseDataList != null ? parsePurchaseData(purchaseDataList.get(i)) : null;
purchase.signature = signatureList != null ? signatureList.get(i) : null;
purchase.sku = ownedSkus != null ? ownedSkus.get(i) : null;
purchases.list.add(purchase);
}
// TODO if continuationToken != null
return purchases;
}
return null;
}
/**
* 消費する。
* @param purchaseToken
* @return
* @throws RemoteException
*/
public boolean consumePurchase(String purchaseToken) throws RemoteException {
int response = inAppBillingService.consumePurchase(API_VER, activity.getPackageName(), purchaseToken);
return response == 0;
}
public void consumePurchaseFromId(String productId) throws RemoteException, JSONException {
for (Purchase purchase : getPurchases().list) {
if (purchase.data.productId.equals(productId)) {
consumePurchase(purchase.data.purchaseToken);
return;
}
}
}
/**
* isPurchasedProduct
* @param productId
* @return
* @throws RemoteException
* @throws JSONException
*/
public boolean isOwned(String productId) throws RemoteException, JSONException {
return getPurchase(productId) != null;
}
/**
* getPurchase
* @param productId
* @return
* @throws RemoteException
* @throws JSONException
*/
public Purchase getPurchase(String productId) throws RemoteException, JSONException {
for (Purchase purchase : getPurchases().list) {
if (productId.equals(purchase.data.productId)) {
return purchase;
}
}
return null;
}
/**
* Use carefully!
*/
@Background
public void consumeAll() {
try {
for (Purchase purchase : getPurchases().list) {
consumePurchase(purchase.data.purchaseToken);
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
public static class SkuDetails {
public boolean success;
public List<SkuDetail> detailsList;
@Override
public String toString() {
return "SkuDetails [success=" + success + ", detailsList=" + detailsList + "]";
}
}
public static class SkuDetail {
public String title;
public String price;
public String type;
public String description;
public String productId;
@Override
public String toString() {
return "SkuDetail [title=" + title + ", price=" + price + ", type=" + type + ", description=" + description + ", productId=" + productId + "]";
}
}
public static class Purchases {
public String continuationToken;
public List<Purchase> list;
@Override
public String toString() {
return "Purchases [continuationToken=" + continuationToken + ", list=" + list + "]";
}
}
public static class Purchase {
public PurchaseData data;
public String signature;
public String sku;
@Override
public String toString() {
return "Purchase [data=" + data + ", signature=" + signature + ", sku=" + sku + "]";
}
}
public static class PurchaseData {
public String packageName;
public String orderId;
public String productId;
public String developerPayload;
public int purchaseTime;
public int purchaseState;
public String purchaseToken;
@Override
public String toString() {
return "PurchaseData [packageName=" + packageName + ", orderId=" + orderId + ", productId=" + productId + ", developerPayload=" + developerPayload + ", purchaseTime=" + purchaseTime
+ ", purchaseState=" + purchaseState + ", purchaseToken=" + purchaseToken + "]";
}
}
public static PurchaseData parsePurchaseData(Intent intent) throws JSONException {
if (intent.hasExtra("INAPP_PURCHASE_DATA")) {
return parsePurchaseData(intent.getStringExtra("INAPP_PURCHASE_DATA"));
} else {
return null;
}
}
public static PurchaseData parsePurchaseData(String jsonStr) throws JSONException {
PurchaseData res = new PurchaseData();
JSONObject json = new JSONObject(jsonStr);
res.packageName = json.getString("packageName");
res.orderId = json.getString("orderId");
res.productId = json.getString("productId");
res.developerPayload = json.getString("developerPayload");
res.purchaseTime = json.getInt("purchaseTime");
res.purchaseState = json.getInt("purchaseState");
res.purchaseToken = json.getString("purchaseToken");
return res;
}
public static SkuDetail parseSkuDetail(String jsonStr) throws JSONException {
SkuDetail res = new SkuDetail();
JSONObject json = new JSONObject(jsonStr);
res.title = json.getString("title");
res.price = json.getString("price");
res.type = json.getString("type");
res.description = json.getString("description");
res.productId = json.getString("productId");
return res;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment