GoogleはAndroid=での支払いを処理するための新しいバージョンを公開しましたが、しばらく検索した後、実装に成功した人からの単一の例やチュートリアルを見つけることができません。
ドキュメントは非常に短く、必要なコードの一部のみを提供しています: https://developer.Android.com/google/play/billing/billing_library_overview
提供されている唯一のサンプルはKotlinで作成されています: https://github.com/Android/play-billing-samples
Java開発者について忘れていたようです...
オンラインでチュートリアルを知っている人や、実装に成功した人はいますか?私の現在のコードはまだ公開されるにはほど遠いです。
私は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
それがすべてです。皆さんのおかげで、私のコードを改善してください。
JavaでのGoogle Play Billingバージョン2のサンプルアプリは次のとおりです。