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.
nimbus_cashier #
In-app subscriptions for Flutter apps on iOS and Android, backed by Nimbus Cashier. Purchases go through the App Store and Google Play (via in_app_purchase); Cashier verifies each one with the store, keeps it current through renewals and refunds, and answers one question: is this user entitled to premium?
Beta. The Swift and Kotlin SDKs are the reference; this package follows them. Paywalls designed in the console are drawn natively in Flutter widgets, the same documents the web and iOS SDKs render.
Install #
flutter pub add nimbus_cashier
or from git:
dependencies:
nimbus_cashier:
git: https://github.com/CodeSyncr/cashier-flutter.git
Use #
import 'package:nimbus_cashier/nimbus_cashier.dart';
await Cashier.configure(apiKey: 'cshr_pub_…'); // the PUBLIC key
await Cashier.shared.logIn(user.id); // after your own sign-in
final info = await Cashier.shared.customerInfo();
if (info.isEntitledTo('premium')) unlockPremium();
final offering = (await Cashier.shared.offerings()).current;
final result = await Cashier.shared.purchase(offering!.availablePackages.first);
await Cashier.shared.restorePurchases();
Cashier.shared.customerInfoStream emits every change — see example/lib/main.dart for a gate built on it.
Paywalls #
Design a paywall for an offering in the Cashier console and show it with one call. It is drawn natively (Flutter widgets, no web view), with the store's prices, and buys through the SDK:
final result = await Cashier.presentPaywall(
context,
requiredEntitlement: 'premium', // not shown to users who already have it; closes once granted
locale: const Locale('es'), // optional: default is the device's language
onPurchaseCompleted: (info) {},
onRestoreCompleted: (info) {},
onAnswer: (answer) { // Feedback / Marketing Consent screens
if (answer.answer == 'yes') requestNotificationPermission();
},
);
// PaywallResult.purchased | restored | cancelled | notPresented
Or place it yourself — PaywallView is an ordinary widget:
Navigator.of(context).push(MaterialPageRoute(
fullscreenDialog: true,
builder: (_) => PaywallView(onPurchaseCompleted: (info) => Navigator.pop(context)),
));
With no offering, PaywallView loads the current one; when that offering has no published paywall, a plain list of its packages is shown (fallbackBuilder replaces it). To render a document with your own purchase handling (previews, tests), use PaywallContent(doc:, packages:, onPurchase:).
What is supported:
- Every block type and variant of the schema (
title,text,image,video,art,icon,stack,custom,sheet,tabs,switch,button,carousel,countdown,timeline,social_proof,testimonial,features,award,packages,cta,header,footer,spacer), per-blocklook/look_selectedstyling, plan cards with badges, and multi-screen flows (buttons:next,back,screen,close,restore,url). - Themes (per screen too), gradient and image backgrounds, background video, animated effects (
glow,aurora,orbs,grid,rays) and entrances (rise,fade,zoom). Motion stops when the platform asks for reduced motion. - Text variables:
{{app_name}},{{product_name}},{{price}},{{period}},{{price_per_month}},{{trial}},{{savings}}(against the shortest plan of a month or more). - Translations: the document's
stringsfor the requested locale (exact tag, else the same language), applied bylocalize(doc, locale)before drawing. - Analytics: a
viewevent when first shown and acloseevent when dismissed without a purchase (fire-and-forget), with the A/B experiment the user is in. Offerings are requested with the user's id so the server can assign experiments (offerings.experiment,offering.paywallId). - Answers: buttons with an
answercallonAnswerand are sent to Cashier (POST /paywalls/responses). Cashier.shared.previewOffering('pvw_…')opens an unpublished draft from the editor's "Preview in app" (debug builds).
Prices come from the store: StoreKit 2's subscription period on iOS (and the console's trial length when the user is eligible for the introductory offer), the offer's recurring and free phases on Google Play. Links (terms, privacy, url buttons) open with url_launcher; pass onOpenUrl to handle them yourself. Background and hero videos play muted and looping through video_player; until a clip plays (or when it cannot), its poster is shown. Only https media are loaded.
The full guide is at https://nimbusgo.space/docs/cashier-flutter.
Develop #
flutter pub get
flutter analyze
flutter test
test/fixtures/paywalls.json is the shared paywall fixture set (the same file the iOS and web SDKs test against); regenerate it from nimbus-starter with PAYWALL_FIXTURES=<path> go test ./app/paywall -run Fixtures. test/paywall_widget_test.dart pumps every screen of every fixture at 390×844 and 320×568 and fails on any exception or overflow.
Release #
- Update
versioninpubspec.yamlandCHANGELOG.md. dart pub publish --dry-run, thendart pub publish.- Tag the commit with the version.
License #
MIT