Rovenue class
Rovenue's app-facing Dart API. Use the instance singleton.
RovenuePlatform.instance is read lazily (via _platform) on every
call — never cached in a field — so tests can swap
RovenuePlatform.instance for a fake at any point and this singleton
(constructed once, like any static final) immediately picks it up.
The three event streams (changes, logs, funnelClaims) apply the
same rule at the stream level: the underlying platform stream is
subscribed to lazily, exactly once, on the first Dart-side listener
(see _StreamHub), and re-read fresh the next time a listener attaches
after every previous one has cancelled.
Properties
-
changes
→ Stream<
RovenueChangeEvent> -
Broadcast stream of
onChangeevents: something the SDK's local cache changed and the app should re-read it. Deliberately NOT given last-value replay (unlike funnelClaims, see below): it is a "go re-fetch current state" signal whose target state is always re-readable on demand (entitlementsAll(),remoteConfigAllJson(), …), so a notification missed before a listener attaches costs nothing — the next explicit read already reflects the latest state.no setter -
funnelClaims
→ Stream<
FunnelClaim> -
Broadcast stream of funnel claims resolved asynchronously on the
native side (e.g. a deferred deep link or clipboard token).
no setter
- hashCode → int
-
The hash code for this object.
no setterinherited
-
logs
→ Stream<
RovenueLogRecord> -
Broadcast stream of log lines forwarded from the Rust core. Plain
broadcast for the same reason as changes: a dropped log line before
a listener attaches has no correctness impact — logging is
best-effort observability, not state the app depends on.
no setter
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
claimFromClipboard(
) → Future< FunnelClaim?> - Reads a funnel token out of the system clipboard and claims it.
-
claimFromUrl(
String url) → Future< FunnelClaim?> -
Claims the funnel token carried by
url(a deep link / Universal Link), or resolvesnullwithout a network call for any non-funnel URL. Forward every incoming URL here from your app's link handler; see extractFunnelToken for the recognised shapes. -
claimFunnelToken(
String token) → Future< FunnelClaim> -
Claim a known funnel token (from a deep link, QR code, or referral
code) and resolve it to a subscriber + funnel-answer payload
server-side. On success, refreshes entitlements and also emits on
funnelClaims. Throws RovenueException with
RovenueErrorKind.funnelTokenNotFound/.funnelTokenExpired/.funnelTokenAlreadyClaimedfor the corresponding server rejections. -
claimInstall(
[ClaimInstallParams params = const ClaimInstallParams()]) → Future< FunnelClaim?> -
Recover a token via the install-attribution endpoint (Android's Play
Install Referrer, or an equivalent server-side match) then claim it.
Resolves
nullwhen no unattributed install matches a pending funnel token — that's the common case, not an error. -
claimViaEmail(
String email) → Future< void> - Kick off the email magic-link funnel-claim path. Resolution completes later when the link returns to the app (deep link → this resolves via claimFromUrl/funnelClaims, not via this call's own return value).
-
configure(
{required String apiKey, String? baseUrl, RovenueLogLevel logLevel = RovenueLogLevel.warn, String? appVersion, String? environment}) → Future< void> -
Initialize the SDK. Must be called before any other method here —
everything else assumes a configured native core and crashes
(
fatalErroron iOS,IllegalStateExceptionon Android) otherwise. Calling it again replaces the underlying native instance (the equivalent of calling shutdown first).appVersionis optional; when omitted, the native layer auto-reads the host app's version and getAppVersion reports back whatever was actually resolved. -
currentUser(
) → Future< RovenueUser> -
Current identity — the anonymous
rovenueIdplusappUserIdonce identify has been called. A local read; does not hit the network. -
entitlement(
String id) → Future< Entitlement?> -
Look up one entitlement by id from the local cache — resolves from
disk/memory, not a network round trip.
nullwhen the id is unknown or not currently granted. A stale cache triggers a background refresh natively; never call refreshEntitlements from anonChangelistener reacting to that refresh's own event, or it loops. -
entitlementsAll(
) → Future< List< Entitlement> > -
All currently-granted entitlements from the local cache — a cache
read, not a network call. Same background staleness-refresh
behaviour and
onChangere-entrancy footgun as entitlement. -
experiment(
String key) → Future< ExperimentAssignment?> -
This subscriber's variant assignment for experiment
key, ornullwhen not enrolled. Unlike the flag getters, a non-nullresult also records an exposure (best-effort, deduped) for experiment analysis — call this only where the variant assignment actually drives what the user sees, not speculatively, or exposure counts get inflated. -
experimentsAll(
) → Future< List< ExperimentAssignment> > - Every experiment this subscriber is currently enrolled in. Unlike experiment, this does NOT record exposures — a plain cache read for callers that need the full set (e.g. debug UI) without treating enumeration as "shown to the user".
-
flushAttributes(
) → Future< int> - Force an immediate flush of buffered attribute mutations to the server, bypassing the background tick. Returns the number of mutations actually sent. Most apps never need this — the background dispatcher already flushes on its own tick and on foreground.
-
flushSessionEvents(
) → Future< int> - Force an immediate POST of buffered session events, bypassing the dispatcher's own tick. Returns the number actually sent. Buffered events already survive a process kill, so this is for callers that want the flush to happen now rather than on the next automatic tick.
-
getAppAccountToken(
) → Future< String> -
Return the current identity scope's Apple
appAccountToken(a UUID), creating and persisting one on first call. Pass this to StoreKit's purchase options so the resulting transaction carries the token Apple echoes back — the anchor the receipt/server-to-server notification path uses to bind the transaction to this subscriber.logOutclears it, so a new anonymous scope gets its own token. -
getAppVersion(
) → Future< String?> -
The host app version configure resolved: the explicit
appVersionargument when one was given, otherwise whatever the native layer auto-read from the platform package manager/bundle.nullbefore configure has run. -
getOfferings(
) → Future< Offerings> - Fetch the project's current offerings from the backend. A network call from the app's perspective; the native/Rust layer falls back to its own last-cached response on a connectivity failure, but an auth/server rejection still throws RovenueException.
-
getVersion(
) → Future< String> -
The native SDK's own semantic version, for diagnostics — not this
Dart package's
pubspec.yamlversion and not network-derived. -
hasResolvedFunnelClaim(
) → Future< bool> - Whether this install has already successfully claimed a funnel token. A synchronous-feeling local read of persisted install state — does not hit the network. Use it to gate first-launch attribution orchestration so claimFunnelToken/claimInstall/claimViaEmail/ claimFromClipboard/claimFromUrl only run once per install, even across app restarts.
-
identify(
String appUserId) → Future< void> -
Link the anonymous device identity to
appUserId. The local write always succeeds and fires anonChangeevent; the server-sidePOST /v1/identifyis best-effort — a failure (offline/5xx) is retried automatically later, not surfaced as an error here. Throws RovenueException on validation failure (e.g. a blank id), and with RovenueErrorKind.subscriberUnresolvable when the server cannot resolve this install's subscriber (corrupt merge history) — the local link stands, unsynced, until the data is repaired. -
installId(
) → Future< String> -
Persisted per-install id (
inst_<cuid2>), generated on first access. A local read; does not hit the network. -
logOut(
) → Future< void> -
Log out the current user: mints a fresh anonymous
rovenueId, dropsappUserId, and clears scope-bound local state (buffered session events, attributes, the Apple app-account token) so the next identity starts clean. Client-local only — does not contact the server. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
purchase(
StoreProduct product, {String? promotionalOfferId, SubscriptionOption? option}) → Future< PurchaseResult> -
Purchases
product(optionally via a specific Androidoption), unpackingproductId/productType/basePlanId/offerIdfor the platform-interface call — callers work with the public StoreProduct / SubscriptionOption models, never raw ids, matching the Swift/Kotlin façades' ergonomics rather than the wire shape. -
recordSessionEvent(
SessionEventKind kind, String occurredAt, {int? durationMs}) → Future< void> -
Append one session-lifecycle event (SessionEventKind.open /
.background/.close) to the local buffer for later at-least-once delivery — does not itself hit the network.durationMsis only meaningful for.close(foreground session length); leave itnullfor.open/.background. -
refreshEntitlements(
) → Future< void> -
Force a network refresh of entitlements, bypassing the staleness
window entitlement/entitlementsAll use. Never call this from
inside an
onChangelistener triggered by entitlements changing — the refresh re-emits that same event, re-invoking the listener, forever. -
refreshRemoteConfig(
) → Future< void> -
Force an immediate Remote Config fetch from the server, bypassing the
staleness window the getters below use. Never call this from inside
a remote-config-changed
onChangelistener it triggers, or it loops. -
refreshVirtualCurrencies(
) → Future< void> - Force a network refresh of virtual-currency balances, bypassing the staleness window virtualCurrencies/virtualCurrency use. Never call this from inside the balance-changed listener it fires — that re-triggers the listener, forever.
-
remoteConfigAllJson(
) → Future< String> -
The whole Remote Config payload (
{ flags, experiments }) as a JSON string, for callers backing their own reactive/synchronous read layer instead of calling the typed getters one key at a time. -
remoteConfigBool(
String key, bool fallback) → Future< bool> -
Boolean feature-flag value for
keyfrom the local cache, orfallbackwhen absent/mistyped. Cache read, never blocks on network; a stale cache triggers a background refresh, so never call refreshRemoteConfig from a remote-config-changed listener this can trigger. -
remoteConfigDouble(
String key, double fallback) → Future< double> -
Floating-point feature-flag value for
keyfrom the local cache, orfallbackwhen absent/mistyped. Same cache-read and background staleness-refresh behaviour as remoteConfigBool. -
remoteConfigInt(
String key, int fallback) → Future< int> -
Integer feature-flag value for
keyfrom the local cache, orfallbackwhen absent/mistyped. Same cache-read and background staleness-refresh behaviour as remoteConfigBool. -
remoteConfigJson(
String key) → Future< String?> -
Raw JSON string for any present flag (object/array/primitive), or
nullwhenkeyis absent. Use this for structured flag values the typed getters above can't represent; parse it yourself. -
remoteConfigKeys(
) → Future< List< String> > - All feature-flag keys currently present in the local remote-config cache. Cache read; triggers the same background staleness refresh as the typed getters above.
-
remoteConfigString(
String key, String fallback) → Future< String> -
String feature-flag value for
keyfrom the local cache, orfallbackwhen absent/mistyped. Same cache-read and background staleness-refresh behaviour as remoteConfigBool. -
restorePurchases(
) → Future< PurchaseResult> - Restore the user's previously-purchased entitlements from the store (StoreKit's transaction history / Google Play's owned-purchases query), re-submitting any found receipts so the server can (re-)grant entitlements for this subscriber. Use for the "Restore Purchases" button required by App Store review — entitlements are already synced automatically via configure/purchase receipt posting, so this isn't needed on every launch.
-
setAttributes(
Map< String, String?> attributes) → Future<void> -
Queue a batch of subscriber-attribute mutations. Written to the
local buffer immediately; the server sync happens in the background
(periodic tick, on foreground, or via flushAttributes). A
nullvalue deletes the key. Reserved keys (prefixed with$, e.g.$email) map to first-class fields server-side — setEmail/ setDisplayName/setPhoneNumber/setPushToken are thin wrappers over this for the common ones. -
setDisplayName(
String? name) → Future< void> -
Subscriber's display name → the
$displayNamereserved attribute. Same buffered-write, background-flush contract as setAttributes;nullclears it. -
setEmail(
String? email) → Future< void> -
Subscriber's email → the
$emailreserved attribute. Same buffered-write, background-flush contract as setAttributes;nullclears it. -
setFallbackPlacements(
String json) → Future< int> -
Load a bundled fallback-placements file (once, replacing any
previously-loaded set) so placements keep resolving offline
when both network and disk cache miss. Returns the count of entries
actually loaded; a malformed file throws RovenueException
(
RovenueErrorKind.invalidArgument). -
setForeground(
bool foreground) → Future< void> -
Tell the native core whether the host app is foregrounded, gating
background polling and triggering an immediate drain of the queued
event queue on the foreground transition. Wire this to
AppLifecycleStatechanges (WidgetsBindingObserver). -
setPhoneNumber(
String? phone) → Future< void> -
Subscriber's phone number → the
$phoneNumberreserved attribute. Same buffered-write, background-flush contract as setAttributes;nullclears it. -
setPushToken(
String? token) → Future< void> -
Device push token → the platform's reserved attribute (
$apnsTokenson iOS,$fcmTokenson Android — the native layer picks the right key). Same buffered-write, background-flush contract as setAttributes;nullclears it. -
shutdown(
) → Future< void> - Stop the native core's background polling (entitlements/remote config). Most apps never need this directly — configure already tears down and replaces the previous instance when called again.
-
toString(
) → String -
A string representation of this object.
inherited
-
track(
String envelopeJson) → Future< void> -
Emit a generic event (fire-and-forget, retried a few times
internally).
envelopeJsonis the camelCase wire envelope; when it omitssubscriberId, the native layer fills it from the current identity scope. -
virtualCurrencies(
) → Future< Map< String, int> > -
All virtual-currency balances, keyed by currency code, from the local
cache — a cache read, not a network call. Stale balances trigger a
background refresh natively; never call refreshVirtualCurrencies
from an
onChangelistener reacting to that refresh's own event. -
virtualCurrency(
String code) → Future< int> -
One virtual-currency balance by code from the local cache (
0when the code is unknown — never an error). Same cache-read and re-entrancy footgun as virtualCurrencies.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited