Visão geral
O KlugBilling vende produtos de compra única e assinaturas a partir do seu app AIR. No iPhone e iPad ele se comunica com a App Store, no Android com o Google Play, e o seu código ActionScript continua o mesmo para os dois.
Ele carrega os seus produtos com títulos e preços localizados, abre a tela de compra da loja, informa cada etapa de uma transação e a finaliza depois que você entrega o produto. A restauração de compras anteriores, o recibo do app iOS e os dados de compra assinados do Google Play estão incluídos, para que o seu servidor possa verificar cada venda.
No Android, o KlugBilling usa a versão atual da Google Play Billing Library 8. Ela é adicionada automaticamente quando o app é empacotado e atende aos requisitos do Google Play para novos apps e atualizações.
O KlugBilling vende as assinaturas de nossos apps no iOS e Android, nossa prova de conceito.
Recursos
- Autossuficiente: uma ANE, sem biblioteca principal nem ANEs de dependência para adicionar
- Uma única API para a App Store e o Google Play
- Produtos de compra única e assinaturas com renovação automática
- Títulos, descrições e preços localizados direto da loja
- Períodos de assinatura, ofertas e fases de preço
- Cada estado da transação como evento: comprando, comprado, falhou, cancelado, restaurado, adiado
- Restaurar compras (iOS) e listar as compras existentes (Android)
- Dados para verificações no servidor: o recibo do app iOS, os dados de compra assinados do Google e a assinatura
- Android: as compras são verificadas com a sua chave pública do Play
Plataformas compatíveis
Em outras plataformas, InAppBilling.isSupported retorna false, de modo que o mesmo código pode permanecer em um app multiplataforma.
Primeiros passos
Adicione a extensão ao descritor do seu aplicativo:
<extensions>
<extensionID>com.klug.billing</extensionID>
</extensions>
Não são necessárias entradas no manifesto nem activities. Crie seus produtos no App Store Connect e no Google Play Console com os mesmos IDs de produto e copie a chave pública base64 do seu app no Play Console (Configuração de monetização).
Exemplos de código
Quatro fluxos completos, extraídos da API que roda em nossos apps. Cada chamada retorna imediatamente; os resultados chegam como eventos em InAppBilling.service. Documentação 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(); } }
Visão geral da API
| InAppBilling.isSupported | Verdadeiro no iOS e Android, falso nas demais plataformas. |
| InAppBilling.service | O serviço único da loja; todas as chamadas e eventos abaixo. |
| setup(service) | Conecta-se à loja descrita por um BillingService. Resultado: SETUP_SUCCESS ou SETUP_FAILURE. |
| checkAvailability(callback) | AVAILABLE, NOT_AVAILABLE ou STORE_UPGRADE_REQUIRED. |
| canMakePayments | Falso quando as compras estão desativadas no dispositivo. |
| getProducts(productIds, subscriptionIds) | Carrega os dados da loja. Resultado: PRODUCTS_LOADED, INVALID_PRODUCT ou PRODUCTS_FAILED. |
| getProduct(id) | Um Product carregado: title, description, price, priceString, currencyCode, subscriptionPeriod, subscriptionOffers. |
| makePurchase(request) | Abre a tela de compra da loja para um PurchaseRequest; oferta de assinatura opcional. |
| finishPurchase(purchase) | Finaliza uma transação após a entrega. Resultado: FINISH_SUCCESS ou FINISH_FAILED. |
| getPendingPurchases() | Transações que a loja ainda mantém abertas. |
| restorePurchases() | iOS: restaura compras anteriores do Apple ID. |
| getPurchases() | Android: lista as compras da conta Google. |
| applicationReceipt | iOS: o recibo do app em base64 para o seu servidor, com refresh(). |
| dispose() | Desconecta da loja. |
Eventos
| InAppBillingEvent | SETUP_SUCCESS, SETUP_FAILURE, RESTORE_PURCHASES_SUCCESS, RESTORE_PURCHASES_FAILED |
| ProductEvent | PRODUCTS_LOADED (produtos), 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 com o resultado da disponibilidade |
| ApplicationReceiptEvent | REFRESH_SUCCESS, REFRESH_FAILED |
Compre o KlugBilling
Uma licença anual para um app AIR, com todas as atualizações por 12 meses. Após o pagamento, você recebe a extensão, a biblioteca ActionScript e a documentação por e-mail, normalmente em até um dia útil. Licença e termos
- Licença para um app AIR
- Todas as atualizações por 12 meses
- Sem suporte
- Licença para um app AIR
- Todas as atualizações por 12 meses
- Resposta por e-mail em até 7 dias
- Licença para um app AIR
- Todas as atualizações por 12 meses
- Resposta por e-mail em até 48 horas
Requisitos
| AIR SDK | 51.x (HARMAN) |
| iOS | iOS 13 ou posterior, produtos no App Store Connect |
| Android | Android 6.0 (API 23) ou posterior, produtos no Google Play Console |
| Google Play | Play Billing Library 8.3, adicionada no empacotamento |
| Servidor (recomendado) | Verifica o recibo do app iOS ou os dados de compra assinados do Google |