2013/11/28

In-app billing v3のTrivialDriveをAndroid 2.1で動かすとエラーが発生する

Androidアプリでアプリ内課金(in-app billing v3) を実装するために、TrivialDriveを参考にしていると思います。

TrivialDriveでは、Android 2.2(android:minSdkVersion="8")のため問題なかったのですが、もし、Android 2.1(android:minSdkVersion="7")までを対象にしているアプリを作成していた場合、バックボタンやホームボタンでActivityを終了すると、下記のExceptionが発生します。

11-28 19:53:49.412: E/AndroidRuntime(3697): Uncaught handler: thread main exiting due to uncaught exception
11-28 19:53:49.422: E/AndroidRuntime(3697): java.lang.RuntimeException: Unable to destroy activity {jp.example.android.t
rivialdrivesample/jp.example.android.trivialdrivesample.MainActivity}: java.lang.IllegalArgumentException: Service not r
egistered: jp.example.android.trivialdrivesample.util.IabHelper$1@457a5280
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java
:3476)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:
3494)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.access$2800(ActivityThread.java:123)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1903)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.os.Looper.loop(Looper.java:123)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.main(ActivityThread.java:4370)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at java.lang.reflect.Method.invokeNative(Native Method)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at java.lang.reflect.Method.invoke(Method.java:521)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit
.java:850)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at dalvik.system.NativeStart.main(Native Method)
11-28 19:53:49.422: E/AndroidRuntime(3697): Caused by: java.lang.IllegalArgumentException: Service not registered: jp.ex
ample.android.trivialdrivesample.util.IabHelper$1@457a5280
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread$PackageInfo.forgetServiceDispatcher(Activi
tyThread.java:934)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ApplicationContext.unbindService(ApplicationContext.java:
819)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.content.ContextWrapper.unbindService(ContextWrapper.java:342)

11-28 19:53:49.422: E/AndroidRuntime(3697):     at jp.example.android.trivialdrivesample.util.IabHelper.dispose(IabHelpe
r.java:284)

11-28 19:53:49.422: E/AndroidRuntime(3697):     at jp.example.android.trivialdrivesample.MainActivity.onDestroy(MainActi
vity.java:432)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java
:3463)
11-28 19:53:49.422: E/AndroidRuntime(3697):     ... 11 more


エラーが発生したソースコードの部分は、

IabHelper.java
public void dispose() {
    logDebug("Disposing.");
    mSetupDone = false;
    if (mServiceConn != null) {
        logDebug("Unbinding from service.");
        if (mContext != null) mContext.unbindService(mServiceConn);
        mServiceConn = null;
        mService = null;
        mPurchaseListener = null;
    }
}

です。Android 2.1 は、in-app-billing v3に対応しておらず、Serviceが立ち上がっていなかったのでunbindしようとしたときにエラーが発生しました。
そこで、下記のように修正します。

IabHelper.java
 public void startSetup(final OnIabSetupFinishedListener listener) {
    // If already set up, can't do it again.
    if (mSetupDone) throw new IllegalStateException("IAB helper is already set up.");

    // Connection to IAB service
    logDebug("Starting in-app billing setup.");
    mServiceConn = new ServiceConnection() {
        // 省略
    };

    Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
    if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {
        // service available to handle that Intent
        mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
    }
    else {
        // no service available to handle that Intent
        if (listener != null) {
            listener.onIabSetupFinished(
                    new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
                    "Billing service unavailable on device."));
        }

        mServiceConn = null;// 追加
    }
}

一行追加することで、unbindService(mServiceConn)する直前のmServiceConnの null チェックにより、unbindServiceが呼ばれなくなるのでエラーが発生しなくなります。


ちなみに、最近サンプルコードがrev.5 になっていろいろと修正が加わっていますので、もし以前のサンプルコードを利用している場合は差分を確認することをおすすめします。

0 件のコメント:

コメントを投稿