实施 Google Play 结算库版本 2

Yoa*_*uet 7 android in-app-billing android-billing

谷歌发布了一个全新的版本来处理 Android 中的支付,但在搜索了一段时间后,我找不到成功实施它的人的一个示例或教程。

文档很短,只提供了一部分必要的代码:https : //developer.android.com/google/play/billing/billing_library_overview

提供的唯一示例是使用 Kotlin 制作的:https : //github.com/android/play-billing-samples

似乎他们忘记了 Java 开发人员...

有谁知道在线教程或成功实施它?我目前的代码还远未发布。

Yoa*_*uet 12

感谢@Webfreak,您对 Kotlin 的回答引导我走向正确的方向。

这是我为 Java 实现它的方法:

首先将 'billingclient' 库添加到 gradle :

implementation 'com.android.billingclient:billing:X.X.X'
Run Code Online (Sandbox Code Playgroud)

并在清单文件中添加所需的权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.android.vending.BILLING" />
Run Code Online (Sandbox Code Playgroud)

Activity 必须实现以下接口:

public class MainActivity extends AppCompatActivity implements
        ...
        PurchasesUpdatedListener,
        AcknowledgePurchaseResponseListener {
Run Code Online (Sandbox Code Playgroud)

然后我在 onCreate 方法中初始化计费客户端:

/** IN-APPS PURCHASE */
    private BillingClient mBillingClient;
    private long mLastPurchaseClickTime = 0;
    private List<String> mSkuList = new ArrayList<>();
    private List<SkuDetails> mSkuDetailsList = new ArrayList<>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // AppPrefs is just a standalone class I used to get or set shared preferences easily
        mPrefs = AppPrefs.getInstance(this);


        // Rest of your code ...


        /** IN-APP PURCHASES */
        // Initialize the list of all the in-app product IDs I use for this app
        mSkuList.add(Parameters.UNIT_P1);// NoAdsPurchased
        mSkuList.add(Parameters.UNIT_P2);// CustomizationPurchased
        mSkuList.add(Parameters.UNIT_P3);// ChartsPurchased

        // Initialize the billing client
        setupBillingClient();

        // Apply the upgrades on my app according to the user's purchases
        applyUpgrades();
    }
Run Code Online (Sandbox Code Playgroud)

设置计费客户端的方法在这里,以及我用来从应用程序中检索可用的应用程序内产品的方法:

private void setupBillingClient() {
        mBillingClient = BillingClient
                .newBuilder(MainActivity.this)
                .enablePendingPurchases() // Useful for physical stores
                .setListener(MainActivity.this)
                .build();

        mBillingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    // Load the available products related to the app from Google Play
                    getAvailableProducts();

                    Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);// Or SkuType.SUBS if subscriptions

                    // Init all the purchases to false in the shared preferences (security prevention)
                    mPrefs.setNoAdsPurchased(false);
                    mPrefs.setCustomizationPurchased(false);
                    mPrefs.setChartsPurchased(false);

                    // Retrieve and loop all the purchases done by the user
                    // Update all the boolean related to the purchases done in the shared preferences
                    if (purchasesResult.getPurchasesList() != null) {
                        for (Purchase purchase : purchasesResult.getPurchasesList()) {
                            if (purchase.isAcknowledged()) {
                                Log.e(TAG, purchase.getSku());

                                switch (purchase.getSku()) {
                                    case Parameters.UNIT_P1:
                                        mPrefs.setNoAdsPurchased(true);
                                        break;
                                    case Parameters.UNIT_P2:
                                        mPrefs.setCustomizationPurchased(true);
                                        break;
                                    case Parameters.UNIT_P3:
                                        mPrefs.setChartsPurchased(true);
                                        break;
                                }
                            }
                        }
                    }
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
                // TODO Note: It's strongly recommended that you implement your own connection retry policy and override the onBillingServiceDisconnected() method. Make sure you maintain the BillingClient connection when executing any methods.
                Log.e(TAG, "onBillingServiceDisconnected");
            }
        });
    }

    private void getAvailableProducts() {
        if (mBillingClient.isReady()) {
            SkuDetailsParams params = SkuDetailsParams
                    .newBuilder()
                    .setSkusList(mSkuList)
                    .setType(BillingClient.SkuType.INAPP)
                    .build();

            mBillingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() {
                @Override
                public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
                    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                        mSkuDetailsList = skuDetailsList;
                    }
                }
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

当用户完成购买时(我允许在我的应用程序中购买多个 Fragment),我在主 Activity 上调用此函数(使用接口):

@Override
    public void purchase(String sku) {
        // Mis-clicking prevention, using threshold of 3 seconds
        if (SystemClock.elapsedRealtime() - mLastPurchaseClickTime < 3000){
            Log.d(TAG, "Purchase click cancelled");
            return;
        }
        mLastPurchaseClickTime = SystemClock.elapsedRealtime();

        // Retrieve the SKU details
        for (SkuDetails skuDetails : mSkuDetailsList) {
            // Find the right SKU
            if (sku.equals(skuDetails.getSku())) {
                BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                        .setSkuDetails(skuDetails)
                        .build();
                mBillingClient.launchBillingFlow(MainActivity.this, flowParams);
                break;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这里我实现了继承的方法:

@Override
    public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (Purchase purchase : purchases) {
                handlePurchase(purchase);
            }
        } else {
            displayError(R.string.inapp_purchase_problem, billingResult.getResponseCode());
        }
    }

    private void handlePurchase(Purchase purchase) {
        if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
            // Grant entitlement to the user.
            applyPurchase(purchase);

            // Acknowledge the purchase if it hasn't already been acknowledged.
            if (!purchase.isAcknowledged()) {
                AcknowledgePurchaseParams acknowledgePurchaseParams =
                        AcknowledgePurchaseParams.newBuilder()
                                .setPurchaseToken(purchase.getPurchaseToken())
                                .build();
                mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, MainActivity.this);
            }
        }
    }

    @Override
    public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
            displayError(R.string.inapp_purchase_success, billingResult.getResponseCode());
        }
    }
Run Code Online (Sandbox Code Playgroud)

我添加的用于在我的应用上确认购买的方法:

private void applyPurchase(Purchase purchase) {

        switch (purchase.getSku()) {
            case Parameters.UNIT_P1:
                mPrefs.setNoAdsPurchased(true);
                break;
            case Parameters.UNIT_P2:
                mPrefs.setCustomizationPurchased(true);
                break;
            case Parameters.UNIT_P3:
                mPrefs.setChartsPurchased(true);
                break;
        }

        // I remove the ads right away if purchases
        if(mPrefs.getNoAdsPurchased()) {
            destroyAds();
        }
    }
Run Code Online (Sandbox Code Playgroud)

最后一种方法用于在应用程序上应用所有升级/购买(以删除广告为例):

private void applyUpgrades() {
        // No ads
        if (mPrefs.getNoAdsPurchased()) {
            destroyAds();
        } else {
            loadAds();
        }

        if (mPrefs.getCustomizationPurchased()) {
            // Allow customization
            // ...
        }

        if (mPrefs.getChartsPurchased()) {
            // Allow charts visualization
            // ...
        }
    }
Run Code Online (Sandbox Code Playgroud)

我想这个解决方案还不完美,但它正在工作,如果我发现改进,我会修改代码。