web-dev-qa-db-ja.com

Google Play Billing Libraryバージョン2を実装する

GoogleはAndroid=での支払いを処理するための新しいバージョンを公開しましたが、しばらく検索した後、実装に成功した人からの単一の例やチュートリアルを見つけることができません。

ドキュメントは非常に短く、必要なコードの一部のみを提供しています: https://developer.Android.com/google/play/billing/billing_library_overview

提供されている唯一のサンプルはKotlinで作成されています: https://github.com/Android/play-billing-samples

Java開発者について忘れていたようです...

オンラインでチュートリアルを知っている人や、実装に成功した人はいますか?私の現在のコードはまだ公開されるにはほど遠いです。

4
Yoann Hercouet

私はAndroid Studioで初心者で、課金ライブラリ2.1.0を実装しています。Android studioのドキュメントと多くのチュートリアルを読んでから1週間後請求ライブラリ私はこれを作成しましたJavaクラスですが、私は十分ではないと感じています、少なくともそれは必要なことをします。改善する方法を見つけたら、コメントしてください。ありがとう:

1.-クラスPago.Java:

package com.example.billing;

import Android.app.Activity;
import Android.content.Context;
import Android.util.Log;
import Android.widget.Toast;

import androidx.annotation.Nullable;

import com.Android.billingclient.api.BillingClient;
import com.Android.billingclient.api.BillingClientStateListener;
import com.Android.billingclient.api.BillingFlowParams;
import com.Android.billingclient.api.BillingResult;
import com.Android.billingclient.api.ConsumeParams;
import com.Android.billingclient.api.ConsumeResponseListener;
import com.Android.billingclient.api.Purchase;
import com.Android.billingclient.api.PurchasesUpdatedListener;
import com.Android.billingclient.api.SkuDetails;
import com.Android.billingclient.api.SkuDetailsParams;
import com.Android.billingclient.api.SkuDetailsResponseListener;
import com.example.R;

import static com.Android.billingclient.api.BillingClient.BillingResponseCode.SERVICE_TIMEOUT;
import static com.Android.billingclient.api.BillingClient.BillingResponseCode.OK;
import static com.Android.billingclient.api.BillingClient.BillingResponseCode.USER_CANCELED;
import static com.Android.billingclient.api.BillingClient.BillingResponseCode.BILLING_UNAVAILABLE;
import static com.Android.billingclient.api.BillingClient.BillingResponseCode.ITEM_UNAVAILABLE;
import static com.Android.billingclient.api.BillingClient.BillingResponseCode.ERROR;
import static com.Android.billingclient.api.BillingClient.SkuType.INAPP;

import Java.util.ArrayList;
import Java.util.List;


public class Pagos implements PurchasesUpdatedListener, BillingClientStateListener, SkuDetailsResponseListener, ConsumeResponseListener {


    private BillingClient billingClient;
    private Context contextPago;
    private String skuId;
    private List<SkuDetails> misProductos;


    // Constructor de la clase Pagos
    public Pagos(Context context) {

        contextPago = context;

    }


    // Asigna el sku del producto que se quiere comprar
    public void comprar(String skuId) {

        this.skuId = skuId;
        configurarBillingClient();

    }


    // Configura el Billing Client para iniciar la conexión con Google Play Console
    private void configurarBillingClient() {

        //  1. Configura el Billing Client
        billingClient = BillingClient.newBuilder(contextPago)
                .enablePendingPurchases()
                .setListener(this)
                .build();

        // 2. Inicia la conexión y asigna los Listener
        billingClient.startConnection(this);

    }


    @Override
    // Evento salta al llamar billingClient.startConnection()
    public void onBillingSetupFinished(BillingResult billingResult) {

        // Busca compras en el Servidor de Google y las marca como consumidas
        consumeCompras();

        // Verifica que la versión de Play Store sea compatible con INAPP
        if (!billingClient.isReady()) {
            String mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_VERSIÓN_NO_COMPATIBLE);
            Toast.makeText(contextPago, mensaje, Toast.LENGTH_LONG).show();
            return;
        }

        // Verifica que la versión de Play Store sea compatible con Suscripciones
        // if (billingClient.isFeatureSupported(SUBSCRIPTIONS).getResponseCode() != OK) {
        //     String mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_VERSIÓN_NO_COMPATIBLE);
        //     Toast.makeText(contextPago, mensaje, Toast.LENGTH_LONG).show();
        //     return; //GooglePlayNoSoportaComprasDeSuscripciones
        // }

        // Verifica que la Configuración se haya hecho bien, sino muestra mensaje de error
        if (verificaResponseCode(billingResult.getResponseCode()) == OK) {
            consultaProductos();
        }

    }


    // Asigna los elemento que se consultarán a Google y los envía con querySkuDetailsAsync
    private void consultaProductos() {

        // Inicializa constantes
        String ITEM_SKU_1 = "Android.test.item_unavailable";
        String ITEM_SKU_2 = "Android.test.canceled";
        String ITEM_SKU_3 = "Android.test.purchased";
        String ITEM_SKU_4 = "donar";
        String ITEM_SKU_5 = "prueba.1";

        // Agrega los productos que se consultarán a Google
        List<String> skuList = new ArrayList<>();
        skuList.add(ITEM_SKU_1);
        skuList.add(ITEM_SKU_2);
        skuList.add(ITEM_SKU_3);
        skuList.add(ITEM_SKU_4);
        skuList.add(ITEM_SKU_5);
        // TODO Cambiar el ingreso manual de items por una consulta a servidor propio de backend seguro.

        SkuDetailsParams.Builder skuDetailsParams = SkuDetailsParams
                .newBuilder()
                .setSkusList(skuList)
                .setType(INAPP);

        // Envía consulta a Google y devuelve el listado de productos mediante onSkuDetailsResponse
        billingClient.querySkuDetailsAsync(skuDetailsParams.build(), this);

    }


    @Override
    // Evento salta cuando Google envía los detalles de los Productos en Venta
    public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {

        if (verificaResponseCode(billingResult.getResponseCode()) == OK) {
            if (skuDetailsList != null) {
                misProductos = skuDetailsList;
                muestraDialogoCompra();
            } else {
                String mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_NO_SKUDETAILSLIST);
                Toast.makeText(contextPago, mensaje, Toast.LENGTH_LONG).show();
            }
        }

    }


    // Lanza el dialogo de compra de Google
    private void muestraDialogoCompra() {

        BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                .setSkuDetails(getSkuIdDetails())
                .build();
        billingClient.launchBillingFlow((Activity) contextPago, flowParams);

    }


    // Obtiene el Producto que se comprará según el Sku ingresado mediante comprar(sku);
    private SkuDetails getSkuIdDetails() {

        if (misProductos == null) return null;
        for (SkuDetails skuProducto : misProductos) {
            if (skuId.equals(skuProducto.getSku())) return skuProducto;
        }
        return null;

    }


    @Override
    // Evento salta cuando se finaliza el Proceso de compra
    public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> list) {

        if (verificaResponseCode(billingResult.getResponseCode()) == OK) {
            // Validar compra con consulta a Google para evitar ingeniería inversa de hackers
            if (validaCompra()) {
                // Compra confirmada
                Log.i("Pagos", "Compra encontrada en servidor");
            } else {
                // Compra no encontrada: Mensaje de error - Revocar privilegios
                Log.i("Pagos", "Compra no encontrada posible hacker");
            }
            consumeCompras();
        }

    }


    // Valida la compra y Devuelve True si encuentra la compra del usuario en el Servidor de Google
    private boolean validaCompra() {

        List<Purchase> purchasesList = billingClient.queryPurchases(INAPP).getPurchasesList();
        if (purchasesList != null && !purchasesList.isEmpty()) {
            for (Purchase purchase : purchasesList) {
                if (purchase.getSku().equals(skuId)) {
                    return true;
                }
            }
        }
        return false;

    }


    // Busca compras en el Servidor de Google y las marca como consumidas
    private void consumeCompras() {

        Purchase.PurchasesResult queryPurchases = billingClient.queryPurchases(INAPP);
        if (queryPurchases.getResponseCode() == OK) {
            List<Purchase> purchasesList = queryPurchases.getPurchasesList();
            if (purchasesList != null && !purchasesList.isEmpty()) {
                for (Purchase purchase : purchasesList) {
                    ConsumeParams params = ConsumeParams.newBuilder()
                            .setPurchaseToken(purchase.getPurchaseToken())
                            .build();
                    billingClient.consumeAsync(params, this);
                }
            }
        }

    }


    @Override
    // Evento salta cuando se ha consumido un producto, Si responseCode = 0, ya se puede volver a comprar
    public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
        if (billingResult.getResponseCode() == OK) {
            Log.i("Pagos", "Token de Compra: " + purchaseToken + " consumida");
        } else {
            Log.i("Pagos", "Error al consumir compra, responseCode: " + billingResult.getResponseCode());
        }
    }


    @Override
    // Evento salta cuando se pierde la conexión durante una compra
    public void onBillingServiceDisconnected() {
        billingClient.startConnection(this);
    }


    // Verifica que el estado del responseCode sea OK, si no muestra mensaje de Error
    private int verificaResponseCode(int responseCode) {

        if (responseCode == OK) return OK;
        if (responseCode == USER_CANCELED) return USER_CANCELED;

        String mensaje = "";
        switch (responseCode) {
            case SERVICE_TIMEOUT:
                mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_SERVICE_TIMEOUT);
                break;
            case BILLING_UNAVAILABLE:
                mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_BILLING_UNAVAILABLE);
                break;
            case ITEM_UNAVAILABLE:
                mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_ITEM_UNAVAILABLE);
                break;
            case ERROR:
                mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_ERROR);
                break;
            default:
                mensaje = contextPago.getString(R.string.PAGOS_MENSAJE_ERROR) + " código: " + responseCode;
                break;
        }
        Toast.makeText(contextPago, mensaje, Toast.LENGTH_LONG).show();
        return responseCode;

    }


}

3.-マニフェスト

<uses-permission Android:name="Android.permission.INTERNET" />
<uses-permission Android:name="com.Android.vending.BILLING" />

4.- build.gradle

// Google Play Billing Library
implementation 'com.Android.billingclient:billing:2.1.0'

5.-使用方法、請求コンポーネントを表示する場所にこのコードを配置します。

private final String SKU_UNAVAILABLE = "Android.test.item_unavailable";
private final String SKU_CANCELED = "Android.test.canceled";
private final String SKU_PURCHASED = "Android.test.purchased";
private final String SKU_DONAR = "donar";


private void donar() {
    Pagos pagos = new Pagos(this);
    pagos.comprar(SKU_DONAR);
    cargandoDialogoCompra(true);
}

SKU_DONARをSKU_UNAVAILABLE、SKU_CANCELED、SKU_PURCHASEDに変更できます。これらはテスト目的のアイテムであり、私が読んだので、それらを再生コンソールに追加する必要がないためです。

6.- Google Playコンソール

Presencia en Google Play Store-> Productos integrados en laaplicación-> Productos administrados:

ドナシオン(ドナー)PEN 9.99

それがすべてです。皆さんのおかげで、私のコードを改善してください。

0
Angel

JavaでのGoogle Play Billingバージョン2のサンプルアプリは次のとおりです。

Javaで上品なタクシー

0
Dyadee