開発のヒホ

iOSとかAndroidとかのアプリを開発するのに四苦八苦するブログ

Androidの課金処理でonActivityResultが呼ばれない

課金の処理についてはここを参考にさせてもらいました。
【Android】GooglePlayによるアプリ内課金実装方法

自分専用のクラス化をしつつ実装してたけど、なぜかonActivityResultが呼ばれないようになってしまった。

iOSの方の課金処理と違い、Androidの課金処理は『専用のダイアログを表示して後は丸投げ』で良いみたい。
ダイアログ上でアドオンを買ったかどうかを判断するためにonActivityResultが呼ばれるはずなんだけど・・・

実際のコードはこんな感じにしてました。

       try {
            String developerPayload = makeDeveloperPayload(productID) ;
            
            // 購入リクエストを送信する(APIVersion,パッケージ名,productID,購入タイプ,任意の文字列)
            Bundle buy_intent_bundle = billingService.getBuyIntent(3, activityNow.getPackageName(),
                    productID, "inapp", developerPayload);

            // レスポンスコードを取得する
            int responseCode = buy_intent_bundle.getInt( "RESPONSE_CODE" );

            // 成功(購入可能)
            if( responseCode == BILLING_RESPONSE_RESULT_OK ){
                
                // 購入対象候補に追加
                productsWaitingPurchase.add( new ProductWaitingPurchase(productID, developerPayload, onPurchaseOrRestoreResult) ) ;

                // 購入フローを開始する
                PendingIntent pending_intent = buy_intent_bundle.getParcelable("BUY_INTENT"); 

                // 購入フローを完了する
                activityNow.startIntentSenderForResult(pending_intent.getIntentSender(),
                        productID.hashCode(), new Intent(), Integer.valueOf(0), Integer.valueOf(0),
                        Integer.valueOf(0)) ;
                
                return ;
            }
            
            // リストア
            else if( responseCode == BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED )  {
                
                onPurchaseOrRestoreResult.onPurchasedOrRestored() ;
                return ;
                
            }
            
            else {
                HILog.v( HILog.getClassAndMethodName() + " : なんかここ来た : responseCode=" + responseCode ) ;
            }
            
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SendIntentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        onPurchaseOrRestoreResult.onCanceled() ;
    }
  1. クラス内でactivityNowを保持しておく
  2. productsWaitingPurchaseに商品と処理を貯めこむ
  3. startIntentrequestCodeに、商品名のハッシュ値を入れる

などの工夫をしています。
そのせいでonActivityResultが呼ばれない。なんでだ。

調べたところ、AndroidManifest.xmlのActivityをsingleInstanceにしてたりすると似たような症状になるらしい。
In-App Billing Version 3で少しはまった所

しかしこれが原因ではなく、requestCodeは0以上にしないといけないようだ。

今回の場合、requestCodeに、商品名のハッシュ値を入れてたから、商品名によっては負の値になってた。
なーるほどね。

こんな感じにするとうまくいきました。

               // 購入フローを完了する
                activityNow.startIntentSenderForResult(pending_intent.getIntentSender(),
                        Math.abs(productID.hashCode()), new Intent(), Integer.valueOf(0), Integer.valueOf(0),
                        Integer.valueOf(0)) ;

staticな変数に保存するのがいけないのか?」とか、「なんかしらんけどpidが-1だからダメなのか?」とか「クラス化するとダメなのか?」とか考えてたけど、もっと納得できる、理不尽じゃないバグだった。