Migrating from 0.x to 1.0
Version 1.0 is a major rewrite of the AppDNA SDK with breaking changes across all platforms. This guide walks you through every change you need to make to upgrade from 0.x.
Overview of Changes
| Area | 0.x | 1.0 |
|---|
| Initialization | AppDNA.initialize() | AppDNA.configure(apiKey:options:) |
| Method organization | Flat methods on AppDNA | Namespaced modules (e.g., AppDNA.onboarding) |
| Delegates | Single global delegate | Per-module delegates |
| Offline support | Network-dependent | Offline-first with config bundles |
| API key format | appdna_ prefix | adn_live_ / adn_test_ prefixes |
| Identity | setUserId() | identify(userId:traits:) |
| Events | logEvent() | track(name:properties:) |
1. Initialization
The initialize() method has been replaced with configure(), which now requires an explicit API key parameter and accepts an options object.
iOS
Android
Flutter
React Native
// 0.x
AppDNA.initialize(config: AppDNAConfig(
projectId: "proj-123"
))
// 1.0
AppDNA.configure(
apiKey: "adn_live_xxx",
environment: .production,
options: AppDNAOptions(logLevel: .debug)
)
// 0.x
AppDNA.initialize(this, AppDNAConfig(
projectId = "proj-123"
))
// 1.0
AppDNA.configure(
context = this,
apiKey = "adn_live_xxx",
environment = Environment.PRODUCTION,
options = AppDNAOptions(logLevel = LogLevel.DEBUG)
)
// 0.x
await AppDNA.initialize(config: AppDNAConfig(
projectId: 'proj-123',
));
// 1.0
await AppDNA.configure(
'adn_live_xxx',
environment: AppDNAEnvironment.production,
options: AppDNAOptions(logLevel: AppDNALogLevel.debug),
);
// 0.x
await AppDNA.initialize({
projectId: 'proj-123',
});
// 1.0
await AppDNA.configure('adn_live_xxx', 'production', {
logLevel: 'debug',
});
The projectId is no longer needed. The API key encodes both the organization and app identifiers.
2. Module Namespaces
In 0.x, all methods lived directly on the AppDNA singleton. In 1.0, methods are organized into module namespaces:
| 0.x Method | 1.0 Equivalent |
|---|
AppDNA.trackOnboardingStep() | AppDNA.onboarding.trackStep() |
AppDNA.presentOnboarding() | AppDNA.onboarding.present() |
AppDNA.showPaywall() | AppDNA.paywall.present() |
AppDNA.getProducts() | AppDNA.billing.getProducts() |
AppDNA.purchaseProduct() | AppDNA.billing.purchase() |
AppDNA.requestPushPermission() | AppDNA.push.requestPermission() |
AppDNA.getExperimentVariant() | AppDNA.experiments.getVariant() |
AppDNA.getRemoteConfig() | AppDNA.remoteConfig.getString() |
AppDNA.isFeatureEnabled() | AppDNA.features.isEnabled() |
AppDNA.showSurvey() | AppDNA.surveys.present() |
iOS
Android
Flutter
React Native
// 0.x
AppDNA.trackOnboardingStep("welcome", step: 2)
AppDNA.showPaywall("premium")
let variant = AppDNA.getExperimentVariant("test-1")
// 1.0
AppDNA.onboarding.trackStep("welcome", step: 2)
AppDNA.paywall.present("premium")
let variant = AppDNA.experiments.getVariant("test-1")
// 0.x
AppDNA.trackOnboardingStep("welcome", step = 2)
AppDNA.showPaywall("premium")
val variant = AppDNA.getExperimentVariant("test-1")
// 1.0
AppDNA.onboarding.trackStep("welcome", step = 2)
AppDNA.paywall.present("premium")
val variant = AppDNA.experiments.getVariant("test-1")
// 0.x
AppDNA.trackOnboardingStep("welcome", step: 2);
AppDNA.showPaywall("premium");
final variant = AppDNA.getExperimentVariant("test-1");
// 1.0
AppDNA.onboarding.trackStep("welcome", step: 2);
AppDNA.paywall.present("premium");
final variant = AppDNA.experiments.getVariant("test-1");
// 0.x
AppDNA.trackOnboardingStep("welcome", 2);
AppDNA.showPaywall("premium");
const variant = AppDNA.getExperimentVariant("test-1");
// 1.0
AppDNA.onboarding.trackStep("welcome", 2);
AppDNA.paywall.present("premium");
const variant = AppDNA.experiments.getVariant("test-1");
3. Delegates
In 0.x, there was a single AppDNADelegate protocol/interface that handled callbacks for all modules. In 1.0, each module has its own delegate:
| 0.x | 1.0 |
|---|
AppDNADelegate | OnboardingDelegate |
| PaywallDelegate |
| BillingDelegate |
| PushDelegate |
| ExperimentDelegate |
| SurveyDelegate |
iOS
Android
Flutter
React Native
// 0.x — single delegate
class AppController: AppDNADelegate {
func onboardingCompleted(flowId: String) { ... }
func paywallDismissed(paywallId: String) { ... }
func pushReceived(notification: AppDNANotification) { ... }
}
AppDNA.delegate = AppController()
// 1.0 — per-module delegates
class OnboardingHandler: OnboardingDelegate {
func onboardingDidComplete(flowId: String) { ... }
}
class PaywallHandler: PaywallDelegate {
func paywallDidDismiss(paywallId: String, action: PaywallAction) { ... }
}
AppDNA.onboarding.delegate = OnboardingHandler()
AppDNA.paywall.delegate = PaywallHandler()
// 0.x — single delegate
AppDNA.delegate = object : AppDNADelegate {
override fun onOnboardingCompleted(flowId: String) { ... }
override fun onPaywallDismissed(paywallId: String) { ... }
}
// 1.0 — per-module delegates
AppDNA.onboarding.delegate = object : OnboardingDelegate {
override fun onCompleted(flowId: String) { ... }
}
AppDNA.paywall.delegate = object : PaywallDelegate {
override fun onDismissed(paywallId: String, action: PaywallAction) { ... }
}
// 0.x — single delegate
AppDNA.delegate = MyAppDNADelegate();
// 1.0 — per-module delegates
AppDNA.onboarding.delegate = MyOnboardingDelegate();
AppDNA.paywall.delegate = MyPaywallDelegate();
// 0.x — single listener
AppDNA.addListener('onboardingCompleted', handler);
AppDNA.addListener('paywallDismissed', handler);
// 1.0 — per-module listeners
AppDNA.onboarding.onCompleted(handler);
AppDNA.paywall.onDismissed(handler);
4. Config Bundles (New in 1.0)
Version 1.0 introduces config bundle embedding, a key part of the offline-first architecture. You can now embed a JSON config file in your app binary during CI/CD so the SDK has a complete configuration available on first launch without any network request.
This is a new feature with no 0.x equivalent. See the Config Bundles in CI/CD guide for setup instructions.
API keys have changed format to clearly distinguish environments:
| Environment | 0.x Format | 1.0 Format |
|---|
| Production | appdna_pk_xxx | adn_live_xxx |
| Sandbox / Test | appdna_sk_xxx | adn_test_xxx |
Old appdna_ prefixed keys are not compatible with 1.0 SDKs. Generate new API keys in Console > Settings > SDK > API Keys.
6. Identity
The setUserId() method has been replaced with identify(), which now accepts user traits for segmentation and targeting:
iOS
Android
Flutter
React Native
// 0.x
AppDNA.setUserId("user-123")
// 1.0
AppDNA.identify(
userId: "user-123",
traits: [
"plan": "premium",
"signup_date": "2025-01-15"
]
)
// 0.x
AppDNA.setUserId("user-123")
// 1.0
AppDNA.identify(
userId = "user-123",
traits = mapOf(
"plan" to "premium",
"signup_date" to "2025-01-15"
)
)
// 0.x
AppDNA.setUserId('user-123');
// 1.0
await AppDNA.identify('user-123', traits: {
'plan': 'premium',
'signup_date': '2025-01-15',
});
// 0.x
AppDNA.setUserId('user-123');
// 1.0
await AppDNA.identify('user-123', {
plan: 'premium',
signup_date: '2025-01-15',
});
Traits are merged with previously set traits on each call. You only need to pass traits that have changed, not the full set every time.
7. Events
The logEvent() method has been replaced with track(), which accepts structured properties:
iOS
Android
Flutter
React Native
// 0.x
AppDNA.logEvent("purchase", metadata: ["price": "9.99"])
// 1.0
AppDNA.track(
event: "purchase_completed",
properties: ["price": 9.99, "currency": "USD"]
)
// 0.x
AppDNA.logEvent("purchase", metadata = mapOf("price" to "9.99"))
// 1.0
AppDNA.track(
event = "purchase_completed",
properties = mapOf("price" to 9.99, "currency" to "USD")
)
// 0.x
AppDNA.logEvent('purchase', metadata: {'price': '9.99'});
// 1.0
await AppDNA.track('purchase_completed', properties: {
'price': 9.99,
'currency': 'USD',
});
// 0.x
AppDNA.logEvent('purchase', { price: '9.99' });
// 1.0
await AppDNA.track('purchase_completed', {
price: 9.99,
currency: 'USD',
});
In 1.0, event properties support typed values (numbers, booleans, strings, arrays) rather than being limited to string-only metadata. This enables richer analytics and segmentation in the dashboard.
iOS
- Minimum deployment target raised from iOS 13 to iOS 15.
- Swift version requirement is now Swift 5.9+.
- SPM package name changed from
AppDNA to AppDNASDK. Update your import statements: import AppDNASDK.
- Concurrency: Several async methods now use Swift concurrency (
async/await) instead of completion handlers.
Android
- Minimum SDK raised from API 21 to API 24 (Android 7.0).
- Kotlin version requirement is now 1.9+.
- Artifact coordinates changed from
ai.appdna:core to ai.appdna:sdk.
- Coroutines: Suspend functions are now used instead of callback-based APIs.
Flutter
- Dart version requirement is now Dart 3.0+.
- Flutter version requirement is now Flutter 3.10+.
- Package name changed from
appdna to appdna_sdk. Update your pubspec.yaml and import statements.
React Native
- React Native version requirement is now 0.72+.
- Package name changed from
react-native-appdna to @appdna/react-native-sdk. Update your package.json and import statements.
- New Architecture: Full support for the React Native New Architecture (TurboModules/Fabric).
Deprecation Timeline
| Date | Milestone |
|---|
| 1.0 GA | 0.x SDKs enter maintenance mode. No new features. |
| 1.0 GA + 3 months | 0.x SDKs receive critical bug fixes only. |
| 1.0 GA + 6 months | 0.x SDKs reach end-of-life. No further updates, including security patches. |
We strongly recommend migrating to 1.0 as soon as possible. After the 6-month deprecation window, 0.x SDKs will no longer receive security patches and may stop functioning if server-side API changes are made.