Perfecto, vamos a hacer un tutorial paso a paso para implementar in_app_purchase en Flutter y crear un widget de compras. Te lo voy a estructurar de manera clara para que puedas integrarlo directamente.

Añadir dependencia
En tu pubspec.yaml agrega:
dependencies:
flutter:
sdk: flutter
in_app_purchase: 3.2.3
in_app_purchase_storekit: 0.4.6
Luego corre:
flutter pub get
Importar el paquete
En tu archivo Dart donde harás la compra:
import 'package:flutter/material.dart'; import 'package:in_app_purchase/in_app_purchase.dart';
Inicializar InAppPurchase
Antes de usar las compras, inicializa la instancia:
final InAppPurchase _iap = InAppPurchase.instance;
Crear un Widget de Compras
Vamos a crear un PurchaseWidget que liste productos y permita comprarlos.
class PurchaseWidget extends StatefulWidget {
@override
_PurchaseWidgetState createState() => _PurchaseWidgetState();
}
class _PurchaseWidgetState extends State<PurchaseWidget> {
final InAppPurchase _iap = InAppPurchase.instance;
bool _available = false;
List<ProductDetails> _products = [];
List<PurchaseDetails> _purchases = [];
@override
void initState() {
super.initState();
_initialize();
}
Future<void> _initialize() async {
_available = await _iap.isAvailable();
if (_available) {
// Define tus IDs de productos
const Set<String> _kIds = {'product1', 'product2'};
final ProductDetailsResponse response = await _iap.queryProductDetails(_kIds);
if (response.error == null) {
setState(() {
_products = response.productDetails;
});
}
// Escuchar compras
_iap.purchaseStream.listen((purchases) {
for (var purchase in purchases) {
_handlePurchase(purchase);
}
});
}
}
void _handlePurchase(PurchaseDetails purchase) {
if (purchase.status == PurchaseStatus.purchased) {
// Aquí puedes desbloquear contenido
print("Compra completada: ${purchase.productID}");
//Envia la compra al servidor y valida:
final PackageInfo info = await PackageInfo.fromPlatform();
final String packageOrBundle = info.packageName;
// Obtener el receipt base64 para iOS (depuración y fallback)
String tokenParaBackend = purchase.verificationData.serverVerificationData;
final String transactionId = purchase.purchaseID ?? '';
await InAppPurchase.instance.completePurchase(purchase);
} else if (purchase.status == PurchaseStatus.error) {
print("Error en compra: ${purchase.error}");
}
}
void _buyProduct(ProductDetails productDetails) {
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
_iap.buyConsumable(purchaseParam: purchaseParam);
}
@override
Widget build(BuildContext context) {
if (!_available) {
return Center(child: Text("Compras no disponibles"));
}
return ListView.builder(
itemCount: _products.length,
itemBuilder: (context, index) {
final product = _products[index];
return Card(
child: ListTile(
title: Text(product.title),
subtitle: Text(product.description),
trailing: TextButton(
child: Text(product.price),
onPressed: () => _buyProduct(product),
),
),
);
},
);
}
}
Notas importantes
- IDs de producto:
- En Android: definidos en Google Play Console.
- En iOS: definidos en App Store Connect.
- Tipos de compra:
buyConsumable: consumibles (ej: monedas, pistas).buyNonConsumable: no consumibles (ej: desbloqueo de features).
- Escucha de compras:
_iap.purchaseStreamescucha actualizaciones de compra, imprescindible para desbloquear contenido.
- Testing:
- Android: usa cuentas de prueba en Play Store.
- iOS: usa Sandbox testers.

Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.