Supported on: iOS SDK 1.0.61+ · Android SDK 1.0.33+ · Flutter SDK 1.0.3+
This is the complete reference for all public methods, properties, types, and delegate classes in the appdna_sdk Flutter package. The Flutter SDK delegates rendering, business logic, and storage to the native iOS and Android layers, so every method here resolves to native execution under the hood.
Core Methods
All core methods are static on the AppDNA class.
| Method | Signature | Description |
|---|
configure | Future<void> AppDNA.configure({required String apiKey, AppDNAEnvironment env, AppDNAOptions? options}) | Initialize the SDK. Call once at app startup. |
identify | Future<void> AppDNA.identify(String userId, {Map<String, dynamic>? traits}) | Associate events with a user identity and optional traits. |
reset | Future<void> AppDNA.reset() | Clear user identity, experiment exposures, and in-session state. Call on logout. |
track | Future<void> AppDNA.track(String event, {Map<String, dynamic>? properties}) | Track a named event with optional properties. |
flush | Future<void> AppDNA.flush() | Force an immediate flush of all queued events. |
onReady | Future<void> AppDNA.onReady(void Function() callback) | Invoke callback once the SDK is initialized and remote config is loaded. |
shutdown | Future<void> AppDNA.shutdown() | Shut down the SDK, flush events, and release resources. No-op on iOS. |
setLogLevel | void AppDNA.setLogLevel(String level) | Change log verbosity at runtime. Accepts "none", "error", "warning", "info", "debug". |
setConsent | Future<void> AppDNA.setConsent({required bool analytics}) | Set analytics consent. When false, events are dropped silently. |
getSdkVersion | Future<String> AppDNA.getSdkVersion() | Get the native SDK version string (e.g., iOS "1.0.61" or Android "1.0.33"). |
Config Methods
| Method | Signature | Description |
|---|
getRemoteConfig | Future<dynamic> AppDNA.getRemoteConfig(String key) | Get a remote config value by key. |
isFeatureEnabled | Future<bool> AppDNA.isFeatureEnabled(String flag) | Check whether a feature flag is enabled. |
forceRefreshConfig | Future<void> AppDNA.forceRefreshConfig() | Force-refresh the remote config from Firestore, bypassing TTL. |
Session Data Methods
Cross-module key-value bag used by Console-configured template interpolation ({{session.*}}).
| Method | Signature | Description |
|---|
setSessionData | Future<void> AppDNA.setSessionData({required String key, required dynamic value}) | Store a session value. |
getSessionData | Future<dynamic> AppDNA.getSessionData({required String key}) | Retrieve a session value by key. |
clearSessionData | Future<void> AppDNA.clearSessionData() | Clear all session data. |
getLocationData | Future<LocationData?> AppDNA.getLocationData() | Get the last location captured via a location form field, if any. |
Consent + Traits
| Method | Signature | Description |
|---|
isConsentGranted | Future<bool> AppDNA.isConsentGranted({required String type}) | Check the current consent state for a given type (analytics, marketing, etc.). |
getUserTraits | Future<Map<String, dynamic>> AppDNA.getUserTraits() | Get the traits map currently associated with the identified user. |
Experiment Methods
| Method | Signature | Description |
|---|
getExperimentVariant | Future<String?> AppDNA.getExperimentVariant(String experimentId) | Get the assigned variant for an experiment. |
isInVariant | Future<bool> AppDNA.isInVariant(String experimentId, String variantId) | Check whether the user is in a specific variant. |
getExperimentConfig | Future<dynamic> AppDNA.getExperimentConfig(String experimentId, String key) | Get a specific config value for an experiment variant. |
Push Methods (Static)
These static helpers mirror AppDNA.push.* — use either style.
| Method | Signature | Description |
|---|
setPushToken | Future<void> AppDNA.setPushToken(String token) | Register the APNs (iOS) or FCM (Android) device token. |
setPushPermission | Future<void> AppDNA.setPushPermission(bool granted) | Report the current push permission status. |
trackPushDelivered | Future<void> AppDNA.trackPushDelivered(String pushId) | Track that a push notification was delivered. |
trackPushTapped | Future<void> AppDNA.trackPushTapped(String pushId, {String? action}) | Track that a push notification was tapped, with optional action ID. |
Presentation Methods
| Method | Signature | Description |
|---|
presentOnboarding | Future<void> AppDNA.presentOnboarding(String flowId) | Present an onboarding flow by ID. |
presentPaywall | Future<void> AppDNA.presentPaywall(String id, {PaywallContext? context}) | Present a paywall by ID with optional context. |
Web Entitlements
| Member | Signature | Description |
|---|
webEntitlement | Future<WebEntitlement?> AppDNA.webEntitlement | The current web entitlement, if any. |
onWebEntitlementChanged | Stream<WebEntitlement?> AppDNA.onWebEntitlementChanged | Broadcast stream emitting web entitlement changes. |
Deep Links
| Method | Signature | Description |
|---|
checkDeferredDeepLink | Future<DeferredDeepLink?> AppDNA.checkDeferredDeepLink() | Check for a deferred deep link captured during install attribution. |
Module Namespaces
Access module-specific functionality through these static properties on AppDNA.
| Property | Type | Description |
|---|
AppDNA.push | AppDNAPushModule | Push notification registration, tokens, and delegates |
AppDNA.billing | AppDNABilling | Products, purchases, entitlements, and restore |
AppDNA.onboarding | AppDNAOnboardingModule | Server-driven onboarding flow presentation |
AppDNA.paywall | AppDNAPaywallModule | Server-driven paywall presentation |
AppDNA.remoteConfig | AppDNARemoteConfigModule | Remote configuration access |
AppDNA.features | AppDNAFeaturesModule | Feature flag evaluation |
AppDNA.experiments | AppDNAExperimentsModule | Experiment variant assignment |
AppDNA.inAppMessages | AppDNAInAppMessagesModule | In-app message display |
AppDNA.surveys | AppDNASurveysModule | User survey presentation |
AppDNA.deepLinks | AppDNADeepLinksModule | Deep link and deferred deep link handling |
AppDNA.screen | AppDNAScreenModule | Server-driven screen lifecycle delegate |
AppDNAPushModule
| Method | Signature | Description |
|---|
setToken | Future<void> setToken(String token) | Register the device push token. |
setPermission | Future<void> setPermission(bool granted) | Update push permission status. |
trackDelivered | Future<void> trackDelivered(String pushId) | Track push delivery. |
trackTapped | Future<void> trackTapped(String pushId, {String? action}) | Track push tap with optional action ID. |
requestPermission | Future<bool> requestPermission() | Request push notification permission from the OS. Returns whether granted. |
getToken | Future<String?> getToken() | Get the current push token, if registered. |
setDelegate | void setDelegate(AppDNAPushDelegate? delegate) | Set a delegate to receive push lifecycle callbacks. Pass null to clear. |
AppDNABilling
| Method | Signature | Description |
|---|
purchase | Future<PurchaseResult> purchase(String productId, {String? offerToken}) | Initiate a purchase. Pass offerToken for Android base-plan offers. |
restorePurchases | Future<List<Entitlement>> restorePurchases() | Restore previous purchases and return all active entitlements. |
getProducts | Future<List<ProductInfo>> getProducts(List<String> productIds) | Fetch localized product info from the store. |
hasActiveSubscription | Future<bool> hasActiveSubscription() | Check whether the user has an active subscription. |
getEntitlements | Future<List<Entitlement>> getEntitlements() | Get all current entitlements for the user. |
onEntitlementsChanged | Stream<List<Entitlement>> onEntitlementsChanged | Broadcast stream emitting entitlement changes. |
onEntitlementsChangedCallback | void onEntitlementsChangedCallback(void Function(List<Entitlement>) callback) | Register a callback for entitlement changes. Alternative to the stream. |
setDelegate | void setDelegate(AppDNABillingDelegate? delegate) | Set a delegate to receive billing lifecycle callbacks. Pass null to clear. |
AppDNAOnboardingModule
| Method | Signature | Description |
|---|
present | Future<void> present(String flowId, {OnboardingContext? context}) | Present an onboarding flow with optional context. |
setDelegate | void setDelegate(AppDNAOnboardingDelegate? delegate) | Set a delegate to receive onboarding lifecycle callbacks. Pass null to clear. |
AppDNAPaywallModule
| Method | Signature | Description |
|---|
present | Future<void> present(String id, {PaywallContext? context}) | Present a paywall by ID with optional context. |
setDelegate | void setDelegate(AppDNAPaywallDelegate? delegate) | Set a delegate to receive paywall lifecycle callbacks. Pass null to clear. |
AppDNARemoteConfigModule
| Method | Signature | Description |
|---|
get | Future<dynamic> get(String key) | Get a remote config value by key. |
refresh | Future<void> refresh() | Force an immediate refresh of remote configuration. |
getAll | Future<Map<String, dynamic>> getAll() | Get all remote config values as a map. |
onChanged | void onChanged(Function callback) | Register a callback invoked when remote config values change. |
AppDNAFeaturesModule
| Method | Signature | Description |
|---|
isEnabled | Future<bool> isEnabled(String flag) | Check whether a feature flag is enabled. |
getVariant | Future<dynamic> getVariant(String flag) | Get the variant value for a multi-variate feature flag. |
onChanged | void onChanged(Function callback) | Register a callback invoked when feature flags change. |
AppDNAExperimentsModule
| Method | Signature | Description |
|---|
getVariant | Future<String?> getVariant(String experimentId) | Get the assigned variant for an experiment. |
isInVariant | Future<bool> isInVariant(String experimentId, String variantId) | Check whether the user is in a specific variant. |
getExposures | Future<List<Map<String, dynamic>>> getExposures() | Get all experiment exposures for the current user. |
AppDNAInAppMessagesModule
| Method | Signature | Description |
|---|
suppressDisplay | Future<void> suppressDisplay(bool suppress) | Suppress or resume in-app message display globally. |
setDelegate | void setDelegate(AppDNAInAppMessageDelegate? delegate) | Set a delegate to receive message lifecycle callbacks. Pass null to clear. |
AppDNASurveysModule
| Method | Signature | Description |
|---|
present | Future<void> present(String surveyId) | Present a survey by ID. |
setDelegate | void setDelegate(AppDNASurveyDelegate? delegate) | Set a delegate to receive survey lifecycle callbacks. Pass null to clear. |
AppDNADeepLinksModule
| Method | Signature | Description |
|---|
handleURL | Future<void> handleURL(String url) | Hand off an incoming deep link URL to the SDK for parsing and routing. |
setDelegate | void setDelegate(AppDNADeepLinkDelegate? delegate) | Set a delegate to receive deep link callbacks. Pass null to clear. |
AppDNAScreenModule
| Method | Signature | Description |
|---|
show | Future<ScreenResult> show(String screenId, { Map<String, dynamic>? context }) | Present a server-driven screen by ID. Returns a ScreenResult with dismissed + responses. |
showFlow | Future<FlowResult> showFlow(String flowId, { Map<String, dynamic>? context }) | Present a multi-screen flow. Returns a FlowResult with completed, screensViewed (List of screen IDs), lastScreenId, and responses. |
dismiss | Future<void> dismiss() | Dismiss the currently-presented screen. |
enableNavigationInterception | Future<void> enableNavigationInterception({List<String>? forScreens}) | Inject screens between app navigations. Pass forScreens to limit interception to specific route names (exact match or trailing * wildcard). |
disableNavigationInterception | Future<void> disableNavigationInterception() | Stop intercepting navigation events. |
preview | Future<void> preview(Map<String, dynamic> json) | Render a screen from raw JSON for debugging. |
setDelegate | void setDelegate(AppDNAScreenDelegate? delegate) | Set a delegate to receive server-driven screen lifecycle callbacks. Pass null to clear. |
Properties
| Property | Type | Description |
|---|
AppDNA.getSdkVersion() | Future<String> | Returns the native SDK version string (e.g., iOS "1.0.61" or Android "1.0.33"). |
AppDNA.currentBundleVersion | Future<int> | Version of the active config bundle (incremented every time Console publishes). Useful for cache-busting in templates. |
AppDNA.configUpdated | Stream<void> | Broadcast stream fired every time the SDK applies a new remote config bundle (initial load, TTL refresh, live Firestore push). |
Delegate Abstract Classes
Implement these abstract classes and register them with the corresponding module’s setDelegate(...). Every setDelegate accepts a nullable delegate — pass null to clear.
AppDNAOnboardingDelegate
abstract class AppDNAOnboardingDelegate {
void onOnboardingStarted(String flowId);
void onOnboardingStepChanged(String flowId, String stepId, int stepIndex, int totalSteps);
void onOnboardingCompleted(String flowId, Map<String, dynamic> responses);
void onOnboardingDismissed(String flowId, int atStep);
// Async hooks — see Onboarding > Async Step Hooks
Future<StepAdvanceResult> onBeforeStepAdvance(
String flowId,
String fromStepId,
int stepIndex,
String stepType,
Map<String, dynamic> responses,
Map<String, dynamic>? stepData,
) async => StepAdvanceResult.proceed();
Future<StepConfigOverride?> onBeforeStepRender(
String flowId,
String stepId,
int stepIndex,
String stepType,
Map<String, dynamic> responses,
) async => null;
}
AppDNAPaywallDelegate
abstract class AppDNAPaywallDelegate {
void onPaywallPresented(String paywallId);
void onPaywallAction(String paywallId, String action);
void onPaywallPurchaseStarted(String paywallId, String productId);
void onPaywallPurchaseCompleted(String paywallId, String productId, Map<String, dynamic> transaction);
void onPaywallPurchaseFailed(String paywallId, Object error);
void onPaywallRestoreStarted(String paywallId);
void onPaywallRestoreCompleted(String paywallId, List<String> restoredProductIds);
void onPaywallRestoreFailed(String paywallId, Object error);
void onPaywallDismissed(String paywallId);
Future<bool> onPromoCodeSubmit(String paywallId, String code) async => false;
void onPostPurchaseDeepLink(String paywallId, String url) {}
void onPostPurchaseNextStep(String paywallId) {}
}
AppDNAPushDelegate
abstract class AppDNAPushDelegate {
void onPushTokenRegistered(String token);
void onPushReceived(Map<String, dynamic> notification, bool inForeground);
void onPushTapped(Map<String, dynamic> notification, String? actionId);
}
AppDNABillingDelegate
abstract class AppDNABillingDelegate {
void onPurchaseCompleted(String productId, Map<String, dynamic> transaction);
void onPurchaseFailed(String productId, Object error);
void onEntitlementsChanged(List<String> entitlements);
void onRestoreCompleted(List<String> restoredProductIds);
}
AppDNAInAppMessageDelegate
abstract class AppDNAInAppMessageDelegate {
void onMessageShown(String messageId, String trigger);
void onMessageAction(String messageId, String action, Map<String, dynamic>? data);
void onMessageDismissed(String messageId);
bool shouldShowMessage(String messageId) => true;
}
shouldShowMessage is a veto — return false to suppress display before view construction and analytics.
AppDNASurveyDelegate
abstract class AppDNASurveyDelegate {
void onSurveyPresented(String surveyId);
void onSurveyCompleted(String surveyId, Map<String, dynamic> responses);
void onSurveyDismissed(String surveyId);
}
AppDNADeepLinkDelegate
abstract class AppDNADeepLinkDelegate {
bool shouldOpen(String url, Map<String, dynamic> params);
void onDeepLinkReceived(String url, Map<String, dynamic> params);
}
shouldOpen is a veto — return false to suppress default deep-link handling (e.g., defer until the user has signed in).
AppDNAScreenDelegate
abstract class AppDNAScreenDelegate {
void onScreenPresented(String screenId);
void onScreenDismissed(String screenId, Map<String, dynamic> result);
void onFlowCompleted(String flowId, Map<String, dynamic> result);
bool onScreenAction(String screenId, Map<String, dynamic> action);
}
onScreenAction is a veto — return false to intercept the action and prevent default handling.
Key Types
AppDNAEnvironment
enum AppDNAEnvironment { production, staging }
AppDNAOptions
class AppDNAOptions {
final int? flushInterval; // Default: 30 (seconds)
final int? batchSize; // Default: 20
final int? configTTL; // Default: 3600 (seconds)
final AppDNALogLevel? logLevel; // Default: warning
final AppDNABillingProvider? billingProvider; // Default: storeKit2 (iOS)
const AppDNAOptions({
this.flushInterval,
this.batchSize,
this.configTTL,
this.logLevel,
this.billingProvider,
});
}
AppDNALogLevel
enum AppDNALogLevel { none, error, warning, info, debug }
AppDNABillingProvider
enum AppDNABillingProvider { storeKit2, revenueCat, adapty, none }
StepAdvanceResult
Returned from AppDNAOnboardingDelegate.onBeforeStepAdvance to control step progression:
sealed class StepAdvanceResult {
/// Continue to the next step normally.
const factory StepAdvanceResult.proceed() = _Proceed;
/// Continue and merge additional data into the session.
const factory StepAdvanceResult.proceedWithData(Map<String, dynamic> data) = _ProceedWithData;
/// Block advancement and show an error message (red banner).
const factory StepAdvanceResult.block({required String message}) = _Block;
/// Stay on the current step without advancing. Pass a non-null `message` to render a green success banner.
const factory StepAdvanceResult.stay({String? message}) = _Stay;
/// Skip to a specific step by ID.
const factory StepAdvanceResult.skipTo({required String stepId}) = _SkipTo;
/// Skip to a specific step and merge additional data.
const factory StepAdvanceResult.skipToWithData({
required String stepId,
required Map<String, dynamic> data,
}) = _SkipToWithData;
}
StepConfigOverride
Returned from AppDNAOnboardingDelegate.onBeforeStepRender to dynamically modify a step’s content:
class StepConfigOverride {
/// Pre-fill form fields. Keys match the field IDs configured in the Console.
final Map<String, dynamic>? fieldDefaults;
/// Override the step's title.
final String? title;
/// Override the step's subtitle.
final String? subtitle;
/// Override the primary CTA label.
final String? ctaText;
/// Override layout-level config (alignment, spacing, theme tokens).
final Map<String, dynamic>? layoutOverrides;
const StepConfigOverride({
this.fieldDefaults,
this.title,
this.subtitle,
this.ctaText,
this.layoutOverrides,
});
}
PaywallAction
Event types fired into AppDNAPaywallDelegate.onPaywallAction:
abstract class PaywallAction {
static const String ctaTapped = 'cta_tapped';
static const String featureSelected = 'feature_selected';
static const String planChanged = 'plan_changed';
static const String linkTapped = 'link_tapped';
static const String custom = 'custom';
}
DismissReason
Reasons the paywall was dismissed (delivered via analytics events):
abstract class DismissReason {
static const String purchased = 'purchased';
static const String restoreSuccess = 'restore_success';
static const String dismissed = 'dismissed';
static const String tappedOutside = 'tappedOutside';
static const String programmatic = 'programmatic';
}
ScreenResult
Returned from AppDNA.screen.show(...):
class ScreenResult {
final bool dismissed;
final Map<String, dynamic> responses;
const ScreenResult({required this.dismissed, required this.responses});
}
FlowResult
Returned from AppDNA.screen.showFlow(...):
class FlowResult {
final bool completed;
final List<String> screensViewed; // Ordered list of screen IDs viewed during the flow
final String? lastScreenId;
final Map<String, dynamic> responses;
const FlowResult({
required this.completed,
required this.screensViewed,
this.lastScreenId,
required this.responses,
});
}
LocationData
Result of AppDNA.getLocationData() and form-field location captures:
class LocationData {
final double latitude;
final double longitude;
final double? accuracy;
final String? address;
final String? city;
final String? region;
final String? country;
final String? postalCode;
final DateTime timestamp;
const LocationData({
required this.latitude,
required this.longitude,
this.accuracy,
this.address,
this.city,
this.region,
this.country,
this.postalCode,
required this.timestamp,
});
}
PaywallContext
class PaywallContext {
final String? placement;
final String? experiment;
final String? variant;
final Map<String, dynamic>? customData;
const PaywallContext({
this.placement,
this.experiment,
this.variant,
this.customData,
});
}
OnboardingContext
class OnboardingContext {
final String? source;
final String? campaign;
final String? referrer;
final Map<String, dynamic>? userProperties;
final Map<String, String>? experimentOverrides;
const OnboardingContext({
this.source,
this.campaign,
this.referrer,
this.userProperties,
this.experimentOverrides,
});
}
PushPayload
class PushPayload {
final String pushId;
final String title;
final String body;
final String? imageUrl;
final Map<String, dynamic>? data;
final String? actionType;
final String? actionValue;
}
Entitlement
class Entitlement {
final String productId;
final String store; // e.g. "app_store", "play_store"
final String status; // e.g. "active", "expired"
final String? expiresAt; // ISO 8601 timestamp
final bool isTrial;
final String? offerType; // e.g. "introductory"
}
PurchaseResult
class PurchaseResult {
final String status; // "purchased", "cancelled", "pending", "unknown"
final Entitlement? entitlement; // Non-null when status == "purchased"
}
ProductInfo
class ProductInfo {
final String id;
final String name;
final String description;
final String displayPrice; // Localized formatted price
final double price; // Numeric price value
final String? currency; // ISO-4217 currency code
final String? offerToken; // Android base-plan offer token
final SubscriptionInfo? subscription; // Subscription details, if applicable
}
class SubscriptionInfo {
final String period; // ISO-8601 (e.g., P1M, P1Y)
final String periodDescription; // Localized period label
final String? freeTrialPeriod;
final IntroductoryOffer? introductoryOffer;
}
class IntroductoryOffer {
final String price;
final String period;
final String paymentMode; // pay_as_you_go | pay_up_front | free_trial
}
WebEntitlement
class WebEntitlement {
final bool isActive;
final String? planName;
final String? priceId;
final String? interval; // e.g. "month", "year"
final String status; // e.g. "active", "canceled", "trialing"
final DateTime? currentPeriodEnd;
final DateTime? trialEnd;
}
DeferredDeepLink
class DeferredDeepLink {
final String screen;
final Map<String, String> params;
final String visitorId;
}
SurveyResult
class SurveyResult {
final String surveyId;
final bool completed; // false if dismissed early
final int questionsAnswered;
final List<SurveyAnswer>? answers;
}
SurveyAnswer
class SurveyAnswer {
final String questionId;
final dynamic answer; // int, String, List, etc. depending on question type
}
Notes
Architecture
The Flutter package exposes API facades, DTOs, and platform-channel bridges; rendering, business logic, network I/O, and storage execute in the native iOS (Swift) and Android (Kotlin) SDKs. New native behavior reaches Flutter via mechanical codegen — the Dart API surface stays continuously in sync with the native ones.
Versioning
The Dart API surface stays continuously in sync with the bundled native renderer through mechanical codegen. CI enforces that the published Flutter package, the iOS SDK, and the Android SDK all advance together — every Flutter release ships with the matching renderer baked in. See the supported-versions box at the top of this page for the active versions.
AppDNABillingProvider.storeKit2 and AppDNABillingProvider.revenueCat apply on iOS only. On Android, billing always uses Google Play Billing.
requestPermission() on AppDNAPushModule triggers the iOS APNs permission prompt or the Android 13+ POST_NOTIFICATIONS runtime permission.
shutdown() releases native resources on Android. On iOS it is a no-op.
offerToken on purchase(...) is required for Android subscription offers (base-plan tokens) and ignored on iOS.