Resumen
KlugBilling vende productos de compra única y suscripciones desde tu app AIR. En iPhone y iPad se comunica con la App Store, en Android con Google Play, y tu código ActionScript es el mismo para ambas.
Carga tus productos con títulos y precios localizados, abre la hoja de compra de la tienda, informa de cada paso de una transacción y la cierra una vez que has entregado el producto. Incluye la restauración de compras anteriores, el recibo de la app de iOS y los datos de compra firmados de Google Play, para que tu servidor pueda verificar cada venta.
En Android, KlugBilling usa la versión actual de Google Play Billing Library 8. Se añade automáticamente al empaquetar la app y cumple los requisitos de Google Play para apps nuevas y actualizaciones.
KlugBilling vende las suscripciones de nuestras apps en iOS y Android, nuestra prueba de concepto.
Funciones
- Autónoma: una ANE, sin biblioteca central ni ANE de dependencias que añadir
- Una única API para la App Store y Google Play
- Productos de compra única y suscripciones con renovación automática
- Títulos, descripciones y precios localizados directamente de la tienda
- Periodos de suscripción, ofertas y fases de precio
- Cada estado de la transacción como evento: comprando, comprado, fallido, cancelado, restaurado, aplazado
- Restaurar compras (iOS) y listar las compras realizadas (Android)
- Datos para comprobaciones en el servidor: el recibo de la app de iOS, los datos de compra firmados de Google y la firma
- Android: las compras se comprueban con tu clave pública de Play
Plataformas compatibles
En otras plataformas InAppBilling.isSupported devuelve false, por lo que el mismo código puede permanecer en una app multiplataforma.
Primeros pasos
Añade la extensión al descriptor de tu aplicación:
<extensions>
<extensionID>com.klug.billing</extensionID>
</extensions>
No se necesitan entradas en el manifiesto ni activities. Crea tus productos en App Store Connect y en la Google Play Console con los mismos IDs de producto, y copia la clave pública base64 de tu app desde la Play Console (Configuración de monetización).
Ejemplos de código
Cuatro flujos completos, tomados de la API que funciona en nuestras apps. Cada llamada devuelve de inmediato; los resultados llegan como eventos en InAppBilling.service. Documentación completa →
import com.klug.billing.*; import com.klug.billing.events.*; var store:InAppBillingService = InAppBilling.service; if ( InAppBilling.isSupported ) // iOS, Android { store.addEventListener( InAppBillingEvent.SETUP_SUCCESS, onSetup ); store.addEventListener( InAppBillingEvent.SETUP_FAILURE, onSetupFailed ); store.addEventListener( PurchaseEvent.PURCHASES_UPDATED, onPurchasesUpdated ); // see 3 var service:BillingService = new BillingService(); if ( store.platform == "android" ) service.setServiceType( InAppBillingServiceTypes.GOOGLE_PLAY_INAPP_BILLING ) .setGooglePlayPublicKey( "MIIBIjANBgkqh..." ); // from the Play Console, Android only else service.setServiceType( InAppBillingServiceTypes.APPLE_INAPP_PURCHASE ); store.setup( service ); } function onSetup( e:InAppBillingEvent ):void { store.checkAvailability( function( result:String ):void { if ( result == InAppBillingAvailability.AVAILABLE ) loadProducts(); // see 2 else hideShop(); // e.g. purchases disabled by Screen Time }); }
function loadProducts():void { store.addEventListener( ProductEvent.PRODUCTS_LOADED, onProducts ); store.addEventListener( ProductEvent.PRODUCTS_FAILED, function( e:ProductEvent ):void { trace( "store not reachable: " + e.message ); }); // one-time products first, subscriptions second store.getProducts( [ "com.example.removeads" ], [ "com.example.pro.monthly", "com.example.pro.yearly" ] ); } function onProducts( e:ProductEvent ):void { for each ( var p:Product in e.products ) { // e.g. "Pro Yearly · 19,99 €" in the user's currency and language addShopButton( p.id, p.title + " · " + p.priceString ); // your app function } }
function buy( productId:String ):void { var request:PurchaseRequest = new PurchaseRequest().setProductId( productId ); if ( store.checkPurchaseRequestValid( request ) ) store.makePurchase( request ); } // every step of every transaction, also open ones from earlier sessions function onPurchasesUpdated( e:PurchaseEvent ):void { for each ( var p:Purchase in e.data ) { switch ( p.transactionState ) { case Purchase.STATE_PURCHASED: case Purchase.STATE_RESTORED: // iOS: p.transactionReceipt (app receipt) // Android: p.originalMessage + p.signature (Google's signed purchase data) verifyOnServer( p, function():void { // your server call unlock( p.productId ); // your app function store.finishPurchase( p ); // close it, or the store sends it again }); break; case Purchase.STATE_FAILED: case Purchase.STATE_CANCELLED: store.finishPurchase( p ); break; case Purchase.STATE_DEFERRED: showHint( "Waiting for approval" ); // e.g. Ask to Buy break; } } }
function restore():void { if ( store.isGetPurchasesSupported ) // Android: list what the Google account owns { store.addEventListener( PurchaseEvent.GET_PURCHASES_COMPLETE, function( e:PurchaseEvent ):void { for each ( var p:Purchase in e.data ) unlock( p.productId ); }); store.getPurchases(); } else // iOS: restored transactions arrive in onPurchasesUpdated with STATE_RESTORED { store.addEventListener( PurchaseEvent.RESTORE_PURCHASES_SUCCESS, function( e:PurchaseEvent ):void { showHint( "Purchases restored" ); }); store.restorePurchases(); } }
Resumen de la API
| InAppBilling.isSupported | Verdadero en iOS y Android, falso en el resto. |
| InAppBilling.service | El servicio de tienda único; todas las llamadas y eventos de abajo. |
| setup(service) | Se conecta a la tienda descrita por un BillingService. Resultado: SETUP_SUCCESS o SETUP_FAILURE. |
| checkAvailability(callback) | AVAILABLE, NOT_AVAILABLE o STORE_UPGRADE_REQUIRED. |
| canMakePayments | Falso cuando las compras están desactivadas en el dispositivo. |
| getProducts(productIds, subscriptionIds) | Carga los datos de la tienda. Resultado: PRODUCTS_LOADED, INVALID_PRODUCT o PRODUCTS_FAILED. |
| getProduct(id) | Un Product cargado: title, description, price, priceString, currencyCode, subscriptionPeriod, subscriptionOffers. |
| makePurchase(request) | Abre la hoja de compra de la tienda para un PurchaseRequest; oferta de suscripción opcional. |
| finishPurchase(purchase) | Cierra una transacción tras la entrega. Resultado: FINISH_SUCCESS o FINISH_FAILED. |
| getPendingPurchases() | Transacciones que la tienda aún mantiene abiertas. |
| restorePurchases() | iOS: restaura las compras anteriores del Apple ID. |
| getPurchases() | Android: lista las compras de la cuenta de Google. |
| applicationReceipt | iOS: el recibo de la app en base64 para tu servidor, con refresh(). |
| dispose() | Se desconecta de la tienda. |
Eventos
| InAppBillingEvent | SETUP_SUCCESS, SETUP_FAILURE, RESTORE_PURCHASES_SUCCESS, RESTORE_PURCHASES_FAILED |
| ProductEvent | PRODUCTS_LOADED (productos), INVALID_PRODUCT, PRODUCTS_FAILED |
| PurchaseEvent | PURCHASES_UPDATED (data = objetos Purchase), PURCHASE_FAILED, FINISH_SUCCESS, FINISH_FAILED, RESTORE_PURCHASES_SUCCESS, RESTORE_PURCHASES_FAILED, GET_PURCHASES_COMPLETE, GET_PURCHASES_FAILED |
| AvailabilityEvent | COMPLETE con el resultado de disponibilidad |
| ApplicationReceiptEvent | REFRESH_SUCCESS, REFRESH_FAILED |
Compra KlugBilling
Una licencia anual para una aplicación AIR, con todas las actualizaciones durante 12 meses. Tras el pago recibes la extensión, la biblioteca ActionScript y la documentación por e-mail, normalmente en un día hábil. Licencia y términos
- Licencia para una aplicación AIR
- Todas las actualizaciones durante 12 meses
- Sin soporte
- Licencia para una aplicación AIR
- Todas las actualizaciones durante 12 meses
- Respuesta por e-mail en un plazo de 7 días
- Licencia para una aplicación AIR
- Todas las actualizaciones durante 12 meses
- Respuesta por e-mail en un plazo de 48 horas
Requisitos
| AIR SDK | 51.x (HARMAN) |
| iOS | iOS 13 o posterior, productos en App Store Connect |
| Android | Android 6.0 (API 23) o posterior, productos en la Google Play Console |
| Google Play | Play Billing Library 8.3, añadida al empaquetar |
| Servidor (recomendado) | Verifica el recibo de la app de iOS o los datos de compra firmados de Google |