如何在安卓应用中实现应用内计费?

2022-08-31 13:22:00

在Android应用程序中实现应用内计费似乎非常复杂。我该怎么做?SDK 中的示例应用只有一个活动,这对于像我这样具有多个活动的应用程序而言,这过度简化了它。


答案 1

好吧,我会试着解释我所经历的。我不认为自己是这方面的专家,但我摔断了几天的头。

对于初学者来说,我试图理解示例和应用程序的工作流程时遇到了非常糟糕的时间。我认为最好从一个简单的例子开始,但是很难将代码分成小块,并且不知道你是否破坏了任何东西。我会告诉你我有什么,以及我从这个例子中改变了什么,以使其发挥作用。

我有一个活动,我的所有购买都来自其中。它被称为Pro。

首先,您应该使用公共市场开发人员密钥更新安全类中的变量 base64EncodedPublicKey,否则您将看到一个不错的异常。

好吧,我将我的活动绑定到我的计费服务,如下所示:

      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
            }
        }
    }

我相信你不需要编辑其他任何东西。代码的其余部分“工作”。您可以先尝试在自己的商品“android.test.purchased”中使用示例SKU。到目前为止,我已经对此进行了测试,并且它有效,但是我仍然需要涵盖退款状态之类的所有内容。在这种情况下,我让用户保留这些功能,但我想在修改之前确保它完美运行。

我希望它能帮助你和其他人。


答案 2

V3:这是一个快速入门的教程。他正在使用谷歌示例(Trivial Drive)中的帮助程序类...好作为第一个“你好账单”..

http://www.techotopia.com/index.php/Integrating_Google_Play_In-app_Billing_into_an_Android_Application_%E2%80%93_A_Tutorial


推荐