課金怖くない。
v2からかなり改善されていて良い。BroadcastをReceiveするのでなくて、onActivityResultへ結果が降ってくるようになったので、サンプルから持って来てそのままActivityに取り込みやすい。
対応しました。Subscriptionには非対応とのこと。
v2, v3で迷う時は
1. SDKから持ってくる
IInAppBillingService.aidl
{sdk}/extras/google/play_billing/in-app-billing-v03/IInAppBillingService.aidl
をsrc.com.android.vending.billing
パッケージへコピー。
buildするとproject/gen
にIInAppBillingService.java
が生成される。
サンプルのUtility
extras/google/play_billing/in-app-billing-v03/samples/TrivialDrive/src/com/example/android/trivialdrivesample/util/*.java
を自分のプロジェクトで適当なパッケージを切ってコピー。よしなにpackage, importをエラーが出ないように抑制する。
2. サンプルのActivityを参考に課金処理をActivityに実装する
以下、実装例。
-
void requestBilling()
をActivity上で実行すれば非消費型アイテムの購入プロセスがスタートする -
void requestSubscriptionBilling()
を実行すれば定期購読アイテムの購入プロセスがスタートする -
boolean isPremiumUser()
,boolean isPremiumSubscriber()
で課金した状態かどうかを取得出来る
ような各アクティビティで継承する基底のクラスをイメージ。
あとはPlayから確実に課金状態が取得出来ない(v2ではちらほら起きていた)ことも考慮して本体に保存、定期的にチェックを入れるような実装をするのが良さそう。また、BillingがSupportedかどうかをちゃんとハンドリングするべき。あとサンプルのUtilityの中身も精査した方が良さそう。
public abstract class BaseActivity extends SherlockFragmentActivity {
private static final String SKU_PREMIUM = "Developer Consoleで設定した非消費型アイテムのproduct id";
private static final String SKU_PREMIUM_SUBSCRIPTION = "Developer Consoleで設定した定期購読アイテムのproduct id";
private static final int REQUEST_CODE_PURCHASE_PREMIUM = よしなにリクエストコードを;
private static final String BILLING_PUBLIC_KEY = "Developer Consoleで得られるBase64encodedな公開鍵(そのままコードに持たせず別の形からデコードなりして持ってくるのが推奨されている";
private IabHelper mBillingHelper;
private boolean mIsPremium = false;
private boolean mIsSubscriber = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
~~
setupBilling();
}
@Override
protected void onDestroy() {
super.onDestroy();
tearDownBilling();
}
private void setupBilling() {
mBillingHelper = new IabHelper(this, BILLING_PUBLIC_KEY);
mBillingHelper.enableDebugLogging(true); // Remove before release
mBillingHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d("billing", "Setup finished.");
if (result.isFailure()) return;
Log.d("billing", "Setup successful. Querying inventory.");
mBillingHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
private void tearDownBilling() {
if (mBillingHelper != null) mBillingHelper.dispose();
mBillingHelper = null;
}
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d("billing", "Query inventory finished.");
if (result.isFailure()) return;
Log.d("billing", "Query inventory was successful.");
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
Log.d("billing", "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
}
};
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d("billing", "Purchase finished: " + result + ", purchase: " + purchase);
if (result.isFailure()) return;
Log.d("billing", "Purchase successful.");
if (purchase.getSku().equals(SKU_PREMIUM)) {
Log.d("billing", "Purchase is premium upgrade. Congratulating user.");
mIsPremium = true;
}
if (purchase.getSku().equals(SKU_PREMIUM_SUBSCRIPTION)) {
Log.d("billing", "Purchase is new subscribing. Congratulating.");
mIsSubscriber = true;
}
}
};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!mBillingHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
protected boolean isPremiumUser() {
return this.mIsPremium;
}
protected boolean isSubscriber() {
return this.mIsSubscriber;
}
protected void requestBilling() {
mBillingHelper.launchPurchaseFlow(this, SKU_PREMIUM, REQUEST_CODE_PURCHASE_PREMIUM, mPurchaseFinishedListener);
}
protected void requestSubscriptionBilling() {
if (mBillingHelper.subscriptionsSupported()) {
mBillingHelper.launchSubscriptionPurchaseFlow(this, SKU_PREMIUM_SUBSCRIPTION, REQUEST_CODE_PURCHASE_PREMIUM, mPurchaseFinishedListener);
}
}
protected void cancelSubscription() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName())));
}
}
これだけ。v2で必死にListener作ったのは何だったんだ。