nimbus_cashier 1.1.0
nimbus_cashier: ^1.1.0 copied to clipboard
Nimbus Cashier for Flutter — App Store and Google Play subscriptions verified by your Cashier app, gated on entitlements.
import 'package:flutter/material.dart';
import 'package:nimbus_cashier/nimbus_cashier.dart';
// A minimal app: premium content behind the "premium" entitlement. The
// paywall is the one designed in the Cashier console for the current
// offering, drawn natively by the SDK.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Cashier.configure(apiKey: 'cshr_pub_your_public_key');
runApp(const MaterialApp(home: Home()));
}
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<CustomerInfo>(
stream: Cashier.shared.customerInfoStream,
initialData: Cashier.shared.cachedCustomerInfo,
builder: (context, snap) => (snap.data?.isEntitledTo('premium') ?? false)
? const Scaffold(body: Center(child: Text('Premium unlocked')))
: const Locked(),
);
}
}
class Locked extends StatefulWidget {
const Locked({super.key});
@override
State<Locked> createState() => _LockedState();
}
class _LockedState extends State<Locked> {
String _last = '';
@override
void initState() {
super.initState();
// Show the paywall on launch to users without "premium"; it closes
// itself once a purchase or restore grants it.
WidgetsBinding.instance.addPostFrameCallback((_) => _showPaywall());
}
Future<void> _showPaywall() async {
final result = await Cashier.presentPaywall(
context,
requiredEntitlement: 'premium',
// locale: const Locale('es'), // default: the device's language
onAnswer: (answer) {
// Answers from Feedback / Marketing Consent screens (also sent to Cashier).
debugPrint('${answer.question}: ${answer.answer}');
},
);
if (mounted) setState(() => _last = result.name);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My app')),
body: Center(
child: Column(mainAxisSize: MainAxisSize.min, children: [
FilledButton(onPressed: _showPaywall, child: const Text('Go premium')),
TextButton(
// Or put the paywall on a route of your own.
onPressed: () => Navigator.of(context).push(MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (context) => PaywallView(
onPurchaseCompleted: (info) => Navigator.of(context).pop(),
),
)),
child: const Text('Open PaywallView'),
),
TextButton(onPressed: () => Cashier.shared.restorePurchases(), child: const Text('Restore purchases')),
if (_last.isNotEmpty) Text('Last paywall: $_last'),
]),
),
);
}
}