Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encorekit.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Encore.placement(id).show() returns a Future<EncorePresentationResult>. You can either await it and switch on the result (async-result) or register global setOnPurchaseRequest / setOnPassthrough handlers (handler-based). Both work; pick whichever fits the call site. For the cross-platform decision tree, see Integration Patterns.

Async-result pattern

Use this when the widget that triggers show() already has access to your purchase + decline logic.

Basic example

import 'package:encore_flutter/encore_flutter.dart';

Future<void> onCancelTapped(BuildContext context) async {
  final result = await Encore.shared.placement('cancel_flow').show();

  switch (result) {
    case EncorePresentationResultGranted(:final offerId):
      // User accepted
      Navigator.of(context).pushReplacementNamed('/home');
      break;
    case EncorePresentationResultNotGranted(:final reason):
      // User declined or no offers — proceed with original flow
      await proceedWithCancellation(reason);
      break;
  }

  // Code that runs in both branches lives here, written once
  analytics.track('cancel_flow_resolved');
}

From a button

FilledButton(
  onPressed: () async {
    final result = await Encore.shared.placement('cancel_flow').show();
    if (result is EncorePresentationResultGranted) {
      if (context.mounted) Navigator.of(context).pop();
    } else {
      await proceedWithCancellation();
    }
  },
  child: const Text('Cancel Subscription'),
)

Result type

sealed class EncorePresentationResult {}

class EncorePresentationResultGranted extends EncorePresentationResult {
  final String? offerId;
  final String? campaignId;
}

class EncorePresentationResultNotGranted extends EncorePresentationResult {
  final String reason;
}

Handler pattern

Use this when show() is invoked from many sites that share post-purchase logic.

Register at app init

import 'package:encore_flutter/encore_flutter.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Encore.configure(apiKey: 'pk_live_...');

  Encore.shared.setOnPurchaseRequest((request) async {
    // Route to RevenueCat / in_app_purchase / your billing
    await billing.purchase(request.productId);
  });

  Encore.shared.setOnPassthrough((placementId) {
    AppRouter.handlePassthrough(placementId);
  });

  runApp(const MyApp());
}

Then show() from anywhere

ElevatedButton(
  onPressed: () => unawaited(Encore.placement('cancel_flow').show()),
  child: const Text('Cancel Subscription'),
)
unawaited(...) (from dart:async) is the idiomatic way to fire-and-forget when you don’t need the result.

When to use which

  • Async-result — widget already imports your billing client. Branch-specific code lives at the call site.
  • Handler — registered once at app init; many show() sites share the same purchase delegation.
  • Mixed — handlers cover cross-cutting telemetry; specific call sites still await show().
See the decision tree for the full rationale.

Re-registration semantics

Encore.shared.setOnPurchaseRequest((_) async { /* v1 */ });
Encore.shared.setOnPurchaseRequest((_) async { /* v2 — replaces v1 */ });
Each setOn* call replaces the previous callback. No double-fires.

Platform-specific notes

  • setOn* naming — Flutter uses setOnPurchaseRequest, setOnPurchaseComplete, setOnPassthrough (rather than the bare onPurchaseRequest setter on iOS/Android). Same semantics.
  • Native renders the UI — the offer sheet renders natively (SwiftUI on iOS, Compose on Android). The Flutter layer is a thin bridge that triggers show() and receives results.
  • unawaited(...) for fire-and-forget — use when the trigger is a synchronous callback and you don’t want the analyzer warning about an unused Future.
  • Sealed-class switch — Dart 3 sealed classes give you exhaustive switch over EncorePresentationResultGranted / EncorePresentationResultNotGranted. The compiler tells you when you’ve forgotten a branch.

See also