Supported on: iOS SDK 1.0.61+ · Android SDK 1.0.33+ · Flutter SDK 1.0.3+
The remote config module delivers key-value pairs from the AppDNA Console to your app. Reads are served from an in-memory cache populated at SDK launch, so they return quickly without a network round trip.
Get a Config Value
final value = await AppDNA.remoteConfig.get("welcome_message");
final welcome = (value as String?) ?? "Hello!";
get returns Future<dynamic> — the value type matches whatever you configured in the Console (string, number, boolean, or JSON map). Cast to the type you expect and supply a fallback for the null case.
Reading Other Types
final retries = (await AppDNA.remoteConfig.get("max_retries") as int?) ?? 3;
final discount = (await AppDNA.remoteConfig.get("discount_rate") as double?) ?? 0.1;
final promoOn = (await AppDNA.remoteConfig.get("show_promo") as bool?) ?? false;
// JSON values arrive as Map<dynamic, dynamic> from the platform channel.
final raw = await AppDNA.remoteConfig.get("hero_banner");
final banner = raw is Map ? Map<String, dynamic>.from(raw) : null;
Get All Values
final all = await AppDNA.remoteConfig.getAll();
print("Loaded ${all.length} config keys");
getAll returns a Map<String, dynamic> containing every key the SDK currently has cached.
Force a Refresh
await AppDNA.remoteConfig.refresh();
refresh pulls the latest config from the server. The SDK already refreshes automatically (see below) — call this explicitly only when you need fresh values right now (e.g. after a user changes their preferences in another tab).
Module Access
final remoteConfig = AppDNA.remoteConfig;
Module Methods
| Method | Signature | Description |
|---|
get | Future<dynamic> get(String key) | Read a single config value (cast to the expected type) |
getAll | Future<Map<String, dynamic>> getAll() | Read every cached key/value pair |
refresh | Future<void> refresh() | Force a refresh from the server |
onChanged | void onChanged(Function callback) | Register a callback that fires when values change |
Typed Helpers
If you prefer typed accessors at the call site, add a Dart extension on the module. This keeps the SDK surface small while giving your codebase a typed feel.
extension TypedRemoteConfig on AppDNARemoteConfigModule {
Future<String> getString(String key, {String fallback = ''}) async {
final v = await get(key);
return (v as String?) ?? fallback;
}
Future<int> getInt(String key, {int fallback = 0}) async {
final v = await get(key);
if (v is int) return v;
if (v is num) return v.toInt();
return fallback;
}
Future<double> getDouble(String key, {double fallback = 0.0}) async {
final v = await get(key);
if (v is double) return v;
if (v is num) return v.toDouble();
return fallback;
}
Future<bool> getBool(String key, {bool fallback = false}) async {
final v = await get(key);
return (v as bool?) ?? fallback;
}
Future<Map<String, dynamic>?> getJson(String key) async {
final v = await get(key);
if (v is Map) return Map<String, dynamic>.from(v);
return null;
}
}
Call them like this:
final welcome =
await AppDNA.remoteConfig.getString("welcome_message", fallback: "Hello!");
final retries =
await AppDNA.remoteConfig.getInt("max_retries", fallback: 3);
When Config Refreshes
The SDK refreshes remote config automatically:
- On app launch — if the cached config has expired (default TTL: 1 hour)
- On return from background — same TTL check
If the fetch fails, the SDK continues using cached values. On first launch with no connectivity, bundled config defaults are used.
The config TTL is configurable via AppDNAOptions(configTTL: 7200) (in seconds). The default is 3600 seconds (1 hour).
Listen for Config Changes
onChanged fires once per refresh whenever the SDK receives updated config from the server. Re-read the keys you care about inside the callback.
AppDNA.remoteConfig.onChanged(() async {
final show =
(await AppDNA.remoteConfig.get("show_promo") as bool?) ?? false;
updatePromoBanner(visible: show);
});
Full Example
import 'package:appdna_sdk/appdna_sdk.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _title = "Welcome";
bool _showBanner = false;
String _bannerText = "";
@override
void initState() {
super.initState();
AppDNA.remoteConfig.onChanged(_loadConfig);
_loadConfig();
}
Future<void> _loadConfig() async {
final title =
(await AppDNA.remoteConfig.get("home_title") as String?) ?? "Welcome";
final showBanner =
(await AppDNA.remoteConfig.get("show_promo_banner") as bool?) ?? false;
final bannerText =
(await AppDNA.remoteConfig.get("promo_banner_text") as String?) ?? "";
if (!mounted) return;
setState(() {
_title = title;
_showBanner = showBanner;
_bannerText = bannerText;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(_title)),
body: Column(
children: [
if (_showBanner)
MaterialBanner(
content: Text(_bannerText),
actions: [
TextButton(onPressed: () {}, child: const Text("Learn More")),
],
),
// Rest of the home screen
],
),
);
}
}
Remote config values are managed in the Console under Settings > Remote Config. Changes take effect on the next SDK config refresh.