为什么在launchBillingFlow之后没有调用onPurchasesUpdated

时间:2018-01-25 18:10:55

标签: java android play-billing-library

我正在实施针对Android的应用广告计费,并且已经达到了我可以从商店检索产品列表的程度。并且可以通过调用launchBillingFlow()方法激活Google购买对话框。文档表明,一旦调用了该函数,就会调用onPurchasesUpdated并显示结果。然而,这对我来说并没有发生。 日志记录确认请求购买(从我的方法中:startPurchaseFlow())。我的onPurchasesUpdated()也会在活动首次运行时调用,并提供OK结果(0)以确认连接设置。

但是为什么不在launchBillingFlow()之后调用它?

持有购买机制的班级:

public class BillingManager implements PurchasesUpdatedListener {
    private final BillingClient mBillingClient; // Billing client used to interface with Google Play
    private final Store mActivity; // Referenced in constructor

   // Structure to hold the details of SKUs returned from querying store
    private static final HashMap<String, List<String>> SKUS;
    static
    {
        SKUS = new HashMap<>();
        SKUS.put(BillingClient.SkuType.INAPP, Arrays.asList("com.identifier.unlock")); // Strings for in app permanent products
    }

    public List<String> getSkus(@BillingClient.SkuType String type) {
        return SKUS.get(type);
    }

    // Constructor
    public BillingManager(Store activity) {
        mActivity = activity;
        mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).build(); // Initialise billing client and set listener
        mBillingClient.startConnection(new BillingClientStateListener() { // Start connection via billing client
            @Override
            public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponse) { // Actions to complete when connection is set up
                if (billingResponse == BillingClient.BillingResponse.OK) {
                    Log.i("dev", "onBillingSetupFinished() response: " + billingResponse);
                    mActivity.getProducts();
                } else {
                    Log.w("dev", "onBillingSetupFinished() error code: " + billingResponse);
                }
            }
            @Override
            public void onBillingServiceDisconnected() { // Called when the connection is disconnected
                Log.w("dev", "onBillingServiceDisconnected()");
            }
        });
    }

    // Receives callbacks on updates regarding future purchases
    @Override
    public void onPurchasesUpdated(@BillingClient.BillingResponse int responseCode,
                                   List<Purchase> purchases) {
        Log.d(TAG, "onPurchasesUpdated() response: " + responseCode);
        if (responseCode == 0 && !purchases.isEmpty()) {
            String purchaseToken;
            for (Purchase element : purchases) {
                purchaseToken = element.getPurchaseToken();
                mBillingClient.consumeAsync(purchaseToken, null); // Test to 'undo' the purchase TEST
            }
        }
    }

    // Used to query store and get details of products args include products to query including type and list of SKUs and a listener for response
    public void querySkuDetailsAsync(@BillingClient.SkuType final String itemType,
                                     final List<String> skuList, final SkuDetailsResponseListener listener) {
        // Create a SkuDetailsParams instance containing args
        SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
                .setSkusList(skuList).setType(itemType).build();
        //Query the billing client using the SkuDetailsParams object as an arg
        mBillingClient.querySkuDetailsAsync(skuDetailsParams,
                new SkuDetailsResponseListener() {

            // Override the response to use the listener provided originally in args
            @Override
                    public void onSkuDetailsResponse(int responseCode,
                                                     List<SkuDetails> skuDetailsList) {
                        listener.onSkuDetailsResponse(responseCode, skuDetailsList);
                    }
                });
    }

    // Start purchase flow with retry option
    public void startPurchaseFlow(final String skuId, final String billingType) {
        Log.i("dev", "Starting purchaseflow...");

        // Specify a runnable to start when connection to Billing client is established
        Runnable executeOnConnectedService = new Runnable() {
            @Override
            public void run() {
                BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                        .setType(billingType)
                        .setSku(skuId)
                        .build();
                mBillingClient.launchBillingFlow(mActivity, billingFlowParams);
                Log.i("dev", "Just called launchBillingFlow..." + skuId);

            }
        };

        // If Billing client was disconnected, we retry 1 time
        // and if success, execute the query
        startServiceConnectionIfNeeded(executeOnConnectedService);
    }
    // Starts connection with reconnect try
    private void startServiceConnectionIfNeeded(final Runnable executeOnSuccess) {
        if (mBillingClient.isReady()) {
            if (executeOnSuccess != null) {
                executeOnSuccess.run();
            }
        } else {
            mBillingClient.startConnection(new BillingClientStateListener() {
                @Override
                public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponse) {
                    if (billingResponse == BillingClient.BillingResponse.OK) {
                        Log.i(TAG, "onBillingSetupFinished() response: " + billingResponse);
                        if (executeOnSuccess != null) {
                            executeOnSuccess.run();
                        }
                    } else {
                        Log.w(TAG, "onBillingSetupFinished() error code: " + billingResponse);
                    }
                }
                @Override
                public void onBillingServiceDisconnected() {
                    Log.w(TAG, "onBillingServiceDisconnected()");
                }
            });
        }
    }

} // End of class

实现界面并启动购买请求并显示产品信息的类:

public class Store extends AppCompatActivity {
    SharedPreferences prefs; // used to access and update the pro value
    BillingManager billingManager; // Used to process purchases

    // Following are used to store local details about unlock product from the play store
    String productSku = "Loading"; // Holds SKU details
    String productBillingType = "Loading";
    String productTitle = "Loading"; // Will be used to display product title in the store activity
    String productPrice = "Loading"; // Used to display product price
    String productDescription = "Loading"; // Used to display the product description

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

        // Set up toolbar
        Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
        setSupportActionBar(myToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        // Create billing manager instance
        billingManager = new BillingManager(this);
        // Set up the shared preferences variable
        prefs = this.getSharedPreferences(
                "com.identifier", Context.MODE_PRIVATE); // Initiate the preferences

        // set up buttons
        final Button btnBuy = findViewById(R.id.btnBuy);
        btnBuy.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                billingManager.startPurchaseFlow(/*productSku*/ "android.test.purchased", productBillingType); // Amended for TEST
            }
        });
        final Button btnPro = findViewById(R.id.btnPro);
        btnPro.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                getProducts();
            }
        });
        getProducts();
        updateDisplay();
    } // End of onCreate

    // Used to unlock the app
    public void unlock() {
        Log.d("dev", "in unlock(),  about to set to true");

        prefs.edit().putBoolean("pro", true).apply();
        MainActivity.pro = true;

    }

    // Go back if back/home pressed
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {

            // Respond to the action bar's Up/Home button
            case android.R.id.home:
             NavUtils.navigateUpFromSameTask(this);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
// Used to request details of products from the store from this class
    public void getProducts() {
        List<String> inAppSkus = billingManager.getSkus(BillingClient.SkuType.INAPP); // Create local list of Skus for query
        billingManager.querySkuDetailsAsync(BillingClient.SkuType.INAPP, inAppSkus, new SkuDetailsResponseListener() {
            @Override
            public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
                if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null) {
                    for (SkuDetails details : skuDetailsList) {
                        productSku = details.getSku();
                        productTitle = details.getTitle();
                        productDescription = details.getDescription();
                        productPrice = details.getPrice();
                        productBillingType = details.getType();
                    }
                    updateDisplay();
                }
            }
        });
    }
// Helper method to update the display with strings
    private void updateDisplay() {
        final TextView titleText = findViewById(R.id.txtTitle);
        final TextView descriptionText = findViewById(R.id.txtDescription);
        final TextView priceText = findViewById(R.id.txtPrice);
        titleText.setText(productTitle);
        descriptionText.setText(productDescription);
        priceText.setText(productPrice);
    }
}

1 个答案:

答案 0 :(得分:2)

好的,所以这个(替换上面的onPurchasesUpdated方法)现在正在按预期工作/响应。为什么,我不知道,但确实如此。

 @Override
 public void onPurchasesUpdated(@BillingClient.BillingResponse int responseCode,
                         List<Purchase> purchases) {
     if (responseCode == BillingClient.BillingResponse.OK
             && purchases != null) {
         for (Purchase purchase : purchases) {
             Log.d(TAG, "onPurchasesUpdated() response: " + responseCode);
             Log.i("dev", "successful purchase...");
             String purchasedSku = purchase.getSku();
             Log.i("dev", "Purchased SKU: " + purchasedSku);
             String purchaseToken = purchase.getPurchaseToken();
             mBillingClient.consumeAsync(purchaseToken, null); // Test to 'undo' the purchase TEST
             mActivity.unlock();
         }
     } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
         // Handle an error caused by a user cancelling the purchase flow.
         Log.d(TAG, "onPurchasesUpdated() response: User cancelled" + responseCode);
     } else {
         // Handle any other error codes.
     }
 }