Created
January 15, 2014 06:27
-
-
Save niusounds/8431722 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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