Skip to main content

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

From a button

Result type


Handler pattern

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

Register at app init

Then show() from anywhere

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

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