Skip to main content
The AppDNA Android SDK is designed to work reliably in offline and degraded network conditions. It uses a layered configuration strategy and persistent event queue to ensure your app functions correctly regardless of connectivity.

Configuration Priority

The SDK resolves configuration using the following priority order:
PrioritySourceDescription
1Remote (Firestore)Live configuration fetched from Firebase Firestore
2Cached (SharedPreferences)Previously fetched config stored locally
3Bundled (assets)Static config file bundled with the app
When the SDK initializes, it attempts to fetch remote configuration. If the network is unavailable, it falls back to cached config. If no cache exists (first launch with no connectivity), it uses the bundled config.

SharedPreferences Cache

The SDK persists configuration data in SharedPreferences under the namespace ai.appdna.sdk.

Cache Keys

KeyDescription
cache_flagsFeature flag configuration
cache_experimentsExperiment assignments and variants
cache_surveysSurvey configuration
cache_paywallsPaywall templates and products
cache_onboardingOnboarding flow definitions

Cache TTL

The configTTL parameter in AppDNAOptions controls how long cached config is considered fresh. The default is 300 seconds (5 minutes). After this period, the SDK will attempt to fetch updated configuration from the remote source.
AppDNA.configure(
    context = this,
    apiKey = "adn_live_xxx",
    environment = Environment.PRODUCTION,
    options = AppDNAOptions(
        configTTL = 600L // Cache for 10 minutes
    )
)
Setting a longer configTTL reduces network requests but delays propagation of configuration changes. For most apps, the default of 300 seconds provides a good balance.

Bundled Configuration

For the best first-launch experience, bundle a configuration file with your app. This ensures the SDK has valid configuration even when the user has no network connectivity on first launch.

Setup

  1. Export your current configuration from the AppDNA console
  2. Place the file at src/main/assets/appdna-config.json
The SDK automatically reads this file as the fallback when no cached or remote configuration is available.

Bundle Version

Access the current bundled config version:
val version = AppDNA.currentBundleVersion
// Returns Int
Update the bundled config file with each app release to minimize the gap between bundled and remote configuration. This ensures users always have a reasonable baseline on first launch.

Event Queue

The SDK queues events locally when they cannot be sent immediately. Events are persisted to SharedPreferences to survive app restarts.

Queue Behavior

SettingValueDescription
Max queue size10,000Maximum number of events stored locally
PersistenceSharedPreferencesEvents survive app restarts
Auto-flushTimer + batchEvents flush on timer interval or batch threshold
Events are flushed automatically based on the flushInterval and batchSize values configured in AppDNAOptions. You can also call AppDNA.flush() to trigger an immediate flush.
When the event queue reaches 10,000 events, the oldest events are dropped to make room for new ones. Under normal conditions with regular connectivity, the queue should never reach this limit.

Networking

OkHttp Timeouts

The SDK uses OkHttp3 for all HTTP requests with the following timeout configuration:
TimeoutDurationDescription
Connect10sMaximum time to establish a connection
Read30sMaximum time to read a response
Write30sMaximum time to write a request

Retry Strategy

Failed requests due to server errors (5xx) or network errors are retried with exponential backoff:
AttemptDelay
1st1s
2nd2s
3rd4s
After 3 failed attempts, the request is abandoned and events remain in the queue for the next flush cycle.

Request Headers

All requests include the following headers:
HeaderValue
AuthorizationBearer {apiKey}
Content-Typeapplication/json

Device Identification

The SDK uses Settings.Secure.ANDROID_ID as the device identifier. This value is unique per app per device and persists across app reinstalls on the same device (unless the device is factory reset).

Coroutine Scopes

The SDK uses Kotlin coroutines with the following dispatcher assignments:
ScopeDispatcherUsed For
IODispatchers.IONetworking, file I/O, SharedPreferences
MainDispatchers.MainUI operations, billing callbacks
All SDK operations are non-blocking. Network requests and persistence operations run on the IO dispatcher, while UI-related callbacks (billing flows, paywall/onboarding rendering) are dispatched on the Main thread.

Next Steps