Feature SDKs (Free)
paywall_sdk Free
- Tier
- Freeversion 2.0.4
- Command
archipelago generate paywall_sdk- Generates
features/paywall/paywall_apifeatures/paywall/paywall_impl
- Generates first
- core_infrastructure_packagewhen needed and missing, so there is nothing to install first
- Depends on
- flutter_l10ngenerate these first
Paywall feature SDK with pricing UI, mock purchase flow, and subscription management.
What it is
Generates a subscription/paywall feature: a PaywallSDK contract (status stream, entitlements, products, purchase, restore) plus a mock data source that returns a hardcoded product catalogue and always succeeds. Use it to stub out monetization UI and entitlement checks before wiring a real payment provider.
Variables
| Variable | Type | Default | Description |
|---|---|---|---|
| appName | string | MyApp | The name of your application |
| prefix | string | App | Prefix for generated classes (e.g. App, My) |
| uiKitPackageName | string | app_ui_kit | Name of the UI kit package |
| isForMonorepo | boolean | true | Whether this will be part of a monorepo structure |
| stateManagement | enum | bloc | State management solution: bloc, cubit, riverpod, provider |
stateManagement's default is bloc, not cubit — same reasoning as home_sdk: the parent flutter_modular_monorepo brick's enum has no cubit value, so bloc is the value standalone mason make paywall_sdk testing and real archipelago create use both reach.
Usage
Interactive
archipelago generate paywall_sdkNon-interactive (CI)
archipelago generate paywall_sdk --config my_config.jsonGenerated Structure
features/
└── paywall/
├── paywall_api/
│ ├── lib/src/
│ │ ├── paywall_sdk.dart # PaywallSDK contract
│ │ ├── paywall_event.dart
│ │ ├── paywall_product.dart
│ │ ├── purchase_result.dart
│ │ ├── subscription_status.dart
│ │ ├── subscription_tier.dart
│ │ └── typedefs.dart
│ └── pubspec.yaml
└── paywall_impl/
├── lib/src/
│ ├── paywall_sdk_impl.dart
│ ├── data/
│ │ ├── datasources/paywall_datasource.dart # MockPaywallDataSource
│ │ └── repositories/{paywall_repository.dart,paywall_repository_impl.dart}
│ ├── domain/usecases/{get_products_usecase.dart,purchase_usecase.dart}
│ ├── di/{paywall_global_module.dart,paywall_container.dart,paywall_imports.dart,injector.dart}
│ ├── presentation/
│ │ ├── paywall_shell_page.dart
│ │ ├── paywall_page.dart
│ │ └── bloc|cubit|notifiers/ # only the chosen stateManagement variant survives post_gen
│ └── router/paywall_router.dart
├── test/src/ # di/paywall_di_test.dart + one state-holder test for the chosen variant
└── pubspec.yamlPublic API
abstract interface class PaywallSDK() {
Future<void> launch(BuildContext context); // same as launchPaywall
Stream<SubscriptionStatus> get statusStream;
SubscriptionStatus get currentStatus;
SubscriptionTier get currentTier;
bool get isPremium;
bool hasEntitlement(String entitlementId);
Future<List<PaywallProduct>> getProducts();
Future<PurchaseResult> purchase(PaywallProduct product);
Future<void> restorePurchases();
Future<void> launchPaywall(BuildContext context);
VoidCallback addStatusListener(PaywallStatusListener listener);
}final paywallSDK = getIt<PaywallSDK>();
if (paywallSDK.isPremium) { /* pro/enterprise access */ }
final remove = paywallSDK.addStatusListener((event) {
switch (event) {
case PaywallPurchaseEvent(): refreshEntitlements();
case PaywallRestoreEvent(): syncData();
case PaywallExpiredEvent(): showRenewalPrompt();
case PaywallStatusChangedEvent(): updateUI();
}
});
await paywallSDK.launchPaywall(context);MockPaywallDataSource
purchase() and getProducts() are genuinely mocked — no App Store/Play Billing/RevenueCat integration ships in this brick:
@LazySingleton(as: PaywallDataSource)
class MockPaywallDataSource() implements PaywallDataSource {
// getProducts() returns 4 hardcoded PaywallProduct entries
// (pro_monthly, pro_yearly, enterprise_monthly, enterprise_yearly)
// purchase() always returns PurchaseSuccess(transactionId: 'mock_txn_123')
}The class's own doc comment says to "replace this with a real payment provider SDK (RevenueCat, etc.)".
DI and wiring
PaywallImplGlobalModuleregisters the constPaywallManifest(/paywallroutes) withFeatureSDKRegistry, andPaywallSDKas a lazy singleton whosedispose:closes the status stream. The SDK and its stream exist only once something checks an entitlement or opens the paywall. The status starts asfree.- Screen-scoped deps (data source, repository, use cases) live in
paywallContainer, aFeatureContainer: a child GetIt built byPaywallShellPage's first lease and torn down after the last release. It never falls back to the root;paywall_imports.dartforwards the root'sPaywallSDK. - The shell builds the state holder from
_lease.get<T>()above the nested router (BlocProviderfor bloc and cubit,ChangeNotifierProviderfor provider, aProviderScopeoverride for riverpod, whosepaywallNotifierProviderthrows unless the shell overrides it) and providesPaywallScope, anInheritedWidgetcarryingPaywallSDK.PaywallPagenever reads GetIt. - Tests:
test/src/di/paywall_di_test.dartchecks the manifest, the lazy SDK and the container;test/src/presentation/tests the chosen variant's state holder (load, purchase, failed load); riverpod also shipspaywall_page_test.dart, which rendersPaywallPageunder the shell'sProviderScopeoverride. post_gen.dartaddsfeatures/paywall/paywall_apiandpaywall_implto the Dart workspace, adds a path dependency onpaywall_implto the host app, and registersPaywallImplGlobalModuleintolib/di/injector.dartviaServiceLocatorUpdater. It records the brick as installed inarchipelago.yaml.
Dependencies on other bricks
core_infrastructure_api(shared/core_infrastructure_sdk/core_infrastructure_api) — declared inpaywall_impl/pubspec.yaml. If that package is missing,pre_genself-generatescore_infrastructure_packagefirst viaensureBrickPackage.- The package named by the
uiKitPackageNamevariable (defaultapp_ui_kit) — design system extensions. When generating into an existing workspace,pre_genuses the UI kit name recorded inarchipelago.yaml(detectingpackages/*_ui_kitif it was never recorded) instead of the default. - No dependency on
auth_sdk(unlikehome_sdk).
Limitations
- The purchase flow is entirely mocked: no real billing SDK, receipt validation, or server-side entitlement sync. Treat the generated feature as UI/flow scaffolding, not a production paywall.
Changelog
Run archipelago brick info paywall_sdk to see the latest published version. Enterprise customers can read the full CHANGELOG.md in the brick source repository.