Skip to main content
AppDNA provides native SDKs for every major mobile platform. All four SDKs share an identical API surface, the same offline-first architecture, and full feature parity. Choose the SDK that matches your stack and get started in minutes.

Choose Your Platform


Platform Comparison

Requirements

iOSAndroidFlutterReact Native
PackageAppDNASDKai.appdna.sdkappdna_sdk@appdna/react-native-sdk
LanguageSwift 5.9+Kotlin 1.9+Dart 3.0+TypeScript
Min PlatformiOS 15.0Android API 24Flutter 3.10+React Native 0.72+
DistributionSPM, CocoaPodsMaven Central (Gradle)pub.devnpm
Current Version1.0.01.0.01.0.01.0.0

Dependencies

iOSAndroidFlutterReact Native
HTTPURLSession (built-in)OkHttp3Platform channelsNativeModules bridge
BillingStoreKit 2 (built-in)Google Play Billing 7.0Platform channels to nativeNativeModules bridge
Config SyncFirebaseFirestoreFirebase Firestore 24.10Platform channels to nativeNativeEventEmitter
Secure StorageKeychainAccessEncryptedSharedPreferencesPlatform-specificPlatform-specific
Flutter and React Native SDKs bridge to the native iOS and Android implementations under the hood. You do not need to add native dependencies manually — they are bundled with the SDK.

Core API

Every SDK exposes the same five core methods. The API is intentionally minimal — initialize once, identify your user, track events, and the SDK handles the rest.

configure

Initialize the SDK with your API key. Call this exactly once at app startup.
import AppDNASDK

AppDNA.configure(
    apiKey: "adn_live_xxx",
    environment: .production,
    options: AppDNAOptions(logLevel: .debug)
)

identify

Link a user identity with optional traits. Traits are merged with previously set values.
AppDNA.identify(
    userId: "user-123",
    traits: ["plan": "premium", "signup_date": "2025-01-15"]
)

track

Record a custom event with optional properties. Events are queued locally and flushed automatically.
AppDNA.track(
    event: "workout_completed",
    properties: ["duration": 45, "type": "strength"]
)

reset

Clear the user identity on sign-out. The anonymous ID is preserved so device-level analytics continue uninterrupted.
AppDNA.reset()

flush

Force-send all queued events immediately. Useful before the app enters the background.
AppDNA.flush()

Module Namespaces

Beyond the core API, the SDK organizes features into 10 module namespaces. Each namespace is accessed as a property on the AppDNA singleton and operates independently while sharing the core event pipeline, identity state, and configuration layer.
NamespacePurposeExample
pushPush notification registration and handlingAppDNA.push.requestPermission()
billingSubscription status, product fetching, purchasesAppDNA.billing.getProducts()
onboardingServer-driven onboarding flow presentationAppDNA.onboarding.present()
paywallServer-driven paywall rendering and eventsAppDNA.paywall.present("premium")
remoteConfigKey-value remote configurationAppDNA.remoteConfig.getString("key")
featuresFeature flags and entitlementsAppDNA.features.isEnabled("dark_mode")
experimentsA/B experiment assignment and exposure trackingAppDNA.experiments.getVariant("test")
surveysIn-app survey presentation and response collectionAppDNA.surveys.present("nps")
inAppMessagesTriggered in-app messagingAppDNA.inAppMessages.check()
deepLinksDeep link routing and deferred deep linksAppDNA.deepLinks.checkDeferred()
All 10 namespaces are available on all 4 platforms with identical method signatures.

Delegate and Callback Protocols

Each module that communicates events back to your application uses a delegate or callback pattern. There are 7 delegate protocols shared across all platforms:
ProtocolKey MethodsUsed By
OnboardingDelegateFlow started, step completed, flow completed, flow skippedonboarding
PaywallDelegatePresented, dismissed, purchase started, purchase completedpaywall
SurveyDelegatePresented, response submitted, dismissedsurveys
InAppMessageDelegatePresented, action taken, dismissedinAppMessages
DeepLinkDelegateLink received, deferred link resolveddeepLinks
ExperimentDelegateExposure tracked, variant assignedexperiments
PushNotificationDelegateToken received, notification presented, notification openedpush
Implement Swift protocols with default empty methods. Conform to only what you need:
class MyHandler: PaywallDelegate {
    func paywallDidPresent(paywallId: String) { }
    func paywallDidDismiss(paywallId: String, action: PaywallAction) { }
}

AppDNA.paywall.delegate = MyHandler()

Architecture

Offline-First Design

All four SDKs share the same offline-first architecture. Your app never crashes or degrades because of a network issue. Configuration priority — the SDK resolves config using a three-tier fallback:
Remote (Firestore real-time sync)
    |
    v  unavailable?
Cached (last successful fetch, persisted on device)
    |
    v  unavailable?
Bundled (appdna-config.json embedded in the app binary)
Event queue — events are persisted to disk, batched, and flushed automatically:
SettingDefaultDescription
Flush interval30 secondsTime between automatic flushes
Batch size20 eventsEvents are flushed when the batch reaches this size
Config TTL5 minutesTime before cached config is considered stale
Events survive app restarts and device reboots. They are only removed from the queue after the server acknowledges receipt.

Experiment Bucketing

All SDKs use the same MurmurHash3 algorithm for deterministic experiment assignment:
bucket = MurmurHash3(userId + experimentId + salt) % 100
This guarantees that the same user sees the same variant across all platforms, all sessions, and all app versions — with no server round-trip required.

Config Bundle for CI/CD

Generate a versioned JSON config bundle on the server and embed it in your app binary for zero-latency first launch:
Add appdna-config.json to your Xcode project as a bundle resource.

Feature Parity Matrix

All features are available on all platforms. This matrix confirms full parity across SDKs.
FeatureiOSAndroidFlutterReact Native
Event trackingYesYesYesYes
User identificationYesYesYesYes
Offline event queueYesYesYesYes
Remote configYesYesYesYes
Feature flagsYesYesYesYes
A/B experimentsYesYesYesYes
Push notificationsYesYesYesYes
Billing / subscriptionsYesYesYesYes
Server-driven onboardingYesYesYesYes
Server-driven paywallsYesYesYesYes
In-app messagesYesYesYesYes
SurveysYesYesYesYes
Deep linksYesYesYesYes
Config bundle embeddingYesYesYesYes
Consent managementYesYesYesYes
Deterministic experimentsYesYesYesYes

Configuration Options

All SDKs accept the same configuration options at initialization:
OptionTypeDefaultDescription
flushIntervalnumber30Seconds between automatic event flushes
batchSizenumber20Events to batch before flushing
configTTLnumber300Seconds before cached config is stale
logLevelenumwarningConsole log verbosity: none, error, warning, info, debug
billingProviderenumplatform defaultBilling integration: storeKit2 (iOS), playBilling (Android), revenueCat, none
Use logLevel: debug during development and logLevel: warning or logLevel: none for production builds.

Environments

EnvironmentAPI Base URLKey Prefix
Productionhttps://api.appdna.aiadn_live_
Sandboxhttps://sandbox-api.appdna.aiadn_test_
Events, experiments, and configuration are completely isolated between environments. The SDK auto-detects the environment from your API key prefix.
Never ship an app to production with a sandbox API key. Sandbox data is periodically purged and is not included in production analytics.

Next Steps

For architecture deep dives, see the Core Concepts page. For CI/CD integration with config bundles, see the Config Bundle Guide.