Skip to content
Back to archipelago.banuacoder.com

Feature SDKs (Free)

paywall_sdk Free ​

Tier
Freeversion 2.0.4
Command
archipelago generate paywall_sdk
Generates
  • features/paywall/paywall_api
  • features/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 ​

VariableTypeDefaultDescription
appNamestringMyAppThe name of your application
prefixstringAppPrefix for generated classes (e.g. App, My)
uiKitPackageNamestringapp_ui_kitName of the UI kit package
isForMonorepobooleantrueWhether this will be part of a monorepo structure
stateManagementenumblocState 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 ​

bash
archipelago generate paywall_sdk

Non-interactive (CI) ​

bash
archipelago generate paywall_sdk --config my_config.json

Generated Structure ​

text
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.yaml

Public API ​

dart
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);
}
dart
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:

dart
@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 ​

  • PaywallImplGlobalModule registers the const PaywallManifest (/paywall routes) with FeatureSDKRegistry, and PaywallSDK as a lazy singleton whose dispose: closes the status stream. The SDK and its stream exist only once something checks an entitlement or opens the paywall. The status starts as free.
  • Screen-scoped deps (data source, repository, use cases) live in paywallContainer, a FeatureContainer: a child GetIt built by PaywallShellPage's first lease and torn down after the last release. It never falls back to the root; paywall_imports.dart forwards the root's PaywallSDK.
  • The shell builds the state holder from _lease.get<T>() above the nested router (BlocProvider for bloc and cubit, ChangeNotifierProvider for provider, a ProviderScope override for riverpod, whose paywallNotifierProvider throws unless the shell overrides it) and provides PaywallScope, an InheritedWidget carrying PaywallSDK. PaywallPage never reads GetIt.
  • Tests: test/src/di/paywall_di_test.dart checks the manifest, the lazy SDK and the container; test/src/presentation/ tests the chosen variant's state holder (load, purchase, failed load); riverpod also ships paywall_page_test.dart, which renders PaywallPage under the shell's ProviderScope override.
  • post_gen.dart adds features/paywall/paywall_api and paywall_impl to the Dart workspace, adds a path dependency on paywall_impl to the host app, and registers PaywallImplGlobalModule into lib/di/injector.dart via ServiceLocatorUpdater. It records the brick as installed in archipelago.yaml.

Dependencies on other bricks ​

  • core_infrastructure_api (shared/core_infrastructure_sdk/core_infrastructure_api) — declared in paywall_impl/pubspec.yaml. If that package is missing, pre_gen self-generates core_infrastructure_package first via ensureBrickPackage.
  • The package named by the uiKitPackageName variable (default app_ui_kit) — design system extensions. When generating into an existing workspace, pre_gen uses the UI kit name recorded in archipelago.yaml (detecting packages/*_ui_kit if it was never recorded) instead of the default.
  • No dependency on auth_sdk (unlike home_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.