1. ホーム
  2. java

AndroidアプリケーションにIn-App Billingを実装するには?

2023-12-05 19:36:29

質問

Android アプリに In-App Billing を実装するのは、かなり複雑なようです。どうすればよいのでしょうか。SDK のサンプル アプリにはアクティビティが 1 つしかなく、複数のアクティビティを持つ私のようなアプリケーションにとっては単純化しすぎのような気がします。

どのように解決するのですか?

さて、私が経験したことを説明しようと思います。私は自分では専門家だとは思っていませんが、数日間、頭を壊しました。

手始めに、私は例とアプリケーションのワークフローを理解するために非常に悪い時間を過ごしました。簡単な例から始めた方が良いと思いましたが、コードを小片に分離するのは非常に難しく、何かを壊しているのかどうかわかりません。私が持っているもの、そしてそれを動作させるために例から変更したものをお話します。

私は、すべての購入が行われる1つのアクティビティを持っています。これはProと呼ばれています。

まず、Securityクラスのbase64EncodedPublicKeyという変数を、公開されているMarketの開発者キーで更新します。

さて、BillingServiceにActivityをバインドします。

      public class Pro extends TrackedActivity implements OnItemClickListener {

            private BillingService mBillingService;
            private BillingPurchaseObserver mBillingPurchaseObserver;
            private Handler mHandler;

            @Override
            protected void onCreate(Bundle savedInstanceState) {    
                super.onCreate(savedInstanceState);     
                setContentView(R.layout.pro);


                //Do my stuff

                mBillingService = new BillingService();
                mBillingService.setContext(getApplicationContext());

                mHandler = new Handler();
                mBillingPurchaseObserver = new BillingPurchaseObserver(mHandler);

            }

        }



    @Override
    protected void onStart() {
       //Register the observer to the service
        super.onStart();
        ResponseHandler.register(mBillingPurchaseObserver);   
    }


    @Override
    protected void onStop() {
        //Unregister the observer since you dont need anymore
        super.onStop();
        ResponseHandler.unregister(mBillingPurchaseObserver);
    }

    @Override
    protected void onDestroy() {
       //Unbind the service
        super.onDestroy();
        mBillingService.unbind();
    }

このように、すべての購入はこのサービスと話をし、そのサービスはマーケットにJSONリクエストを送信します。購入は同じ瞬間に行われると思うかもしれませんが、そうではありません。リクエストを送信してから、数分後、数時間後に購入が行われるかもしれません。これは主にサーバーの過負荷とクレジットカードの承認が原因だと思います。

次に、私はアイテムのListViewを持っていて、それぞれについてAlertDialogを開き、アイテムを購入するように誘います。アイテムをクリックすると、このようになります。

  private class BuyButton implements DialogInterface.OnClickListener {

       private BillingItem item = null;
       private String developerPayload;

       public BuyButton(BillingItem item, String developerPayload) {
        this.item = item;
        this.developerPayload = developerPayload;
        }

            @Override
            public void onClick(DialogInterface dialog, int which) {

                if (GeneralHelper.isOnline(getApplicationContext())){
                    //I track the buy here with GA SDK. 

        mBillingService.requestPurchase(this.item.getSku(), this.developerPayload);             
                } else {                
                    Toast.makeText(getApplicationContext(), R.string.msg_not_online, Toast.LENGTH_SHORT).show();
                }

            }

        }

さて、マーケットが開き、ユーザーが購入を完了するか、キャンセルするのがわかるはずです。

次に重要なのは、私のPurChaseObserverで、マーケットが送信するすべてのイベントを処理します。これはその一部を切り取ったものですが、要点はご理解いただけると思います(コード中の私のコメントをご覧ください)。

private class BillingPurchaseObserver extends PurchaseObserver {
        public BillingPurchaseObserver(Handler handler) {
            super(Pro.this, handler);
        }

        @Override
        public void onBillingSupported(boolean supported) {

            if (supported) {
                //Enable buy functions. Not required, but you can do stuff here. The market first checks if billing is supported. Maybe your country is not supported, for example. 
            } else {
                Toast.makeText(getApplicationContext(), R.string.billing_not_supported, Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onPurchaseStateChange(PurchaseState purchaseState, String itemId,
                int quantity, long purchaseTime, String developerPayload) {

//This is the method that is called when the buy is completed or refunded I believe. 
// Here you can do something with the developerPayload. Its basically a Tag you can use to follow your transactions. i dont use it. 

        BillingItem item = BillingItem.getBySku(getApplicationContext(), itemId);

        if (purchaseState == PurchaseState.PURCHASED) {
            if (item != null){
//This is my own implementation that sets the item purchased in my database. BillingHelper is a class with methods I use to check if the user bought an option and update the UI. You should also check for refunded. You can see the Consts class to find what you need to check for. 

                    boolean resu = item.makePurchased(getApplicationContext());
                    if (resu){                      
                        Toast.makeText(getApplicationContext(), R.string.billing_item_purchased, Toast.LENGTH_LONG).show();
                    }
                }
            }
        }

        private void trackPurchase(BillingItem item, long purchaseTime) {           
            //My code to track the purchase in GA
        }

        @Override
        public void onRequestPurchaseResponse(RequestPurchase request,
                ResponseCode responseCode) {

               //This is the callback that happens when you sent the request. It doesnt mean you bought something. Just that the Market received it. 

            if (responseCode == ResponseCode.RESULT_OK) {               

                Toast.makeText(getApplicationContext(), R.string.billing_item_request_sent, Toast.LENGTH_SHORT).show();

            } else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
                //The user canceled the item. 
            } else {
            //If it got here, the Market had an unexpected problem. 
            }
        }

        @Override
        public void onRestoreTransactionsResponse(RestoreTransactions request,
                ResponseCode responseCode) {
            if (responseCode == ResponseCode.RESULT_OK) {
//Restore transactions should only be run once in the lifecycle of your application unless you reinstalled the app or wipe the data. 

                SharedPreferences.Editor edit = PreferencesHelper.getInstance().getDefaultSettings(getApplicationContext()).edit();
                edit.putBoolean(Consts.DB_INITIALIZED, true);
                edit.commit();

            } else {
    //Something went wrong
            }
        }
    }

で、あとは何も編集する必要はないはずです。残りのコードは"works"です。 まずはサンプルのSKUを自分のアイテムに使ってみてください "android.test.purchased". 今のところ、私はこれをテストし、それは動作しますが、私はまだ払い戻しの状態などすべてをカバーする必要があります。この場合、ユーザーには機能を残していますが、改造する前に完璧に動作することを確認したいのです。

これがあなたや他の人の役に立つことを願っています。