AssetFlux Flutter SDK

pub package License: BSD-3-Clause

Manage remote image assets in Flutter with automatic density selection, CDN caching, and gradual rollout support. Upload assets once via the AssetFlux dashboard and serve optimized variants to every device — no app update required.

  • Drop-in RemoteImage widget — density- and format-aware, with shimmer placeholder
  • Offline-first — memory + disk cache with configurable TTL
  • Gradual rollout — roll out new asset versions to a percentage of users
  • Prefetch API — warm the cache before the UI needs it

Getting Started

1. Install

# pubspec.yaml
dependencies:
  assetflux_flutter: ^1.0.0
flutter pub get

Android — add internet permission if not already present:

<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET"/>

iOS — no additional setup required.

2. Initialize

import 'package:assetflux_flutter/assetflux_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await AssetFlux.init(
    projectId: 'af_...', // From AssetFlux dashboard → Settings → API Keys
    apiKey: 'afk_...',   // Use an SDK key (afk_ prefix)
  );

  runApp(const MyApp());
}

3. Display a Remote Asset

RemoteImage('home.hero.banner')

That's it. The SDK automatically selects the right density (1x / 2x / 3x), picks the best format (WebP > PNG), caches the result, and shows a shimmer while loading.

Usage

RemoteImage Widget

// Basic
RemoteImage('home.hero.banner')

// With placeholder, error handling, and sizing
RemoteImage(
  'home.hero.banner',
  placeholder: const ShimmerPlaceholder(),
  errorWidget: const Icon(Icons.broken_image),
  fallbackAsset: 'assets/images/default_banner.png',
  width: double.infinity,
  height: 200,
  fit: BoxFit.cover,
)

Prefetch

Warm the cache before the UI renders:

// Single asset
await AssetFlux.prefetch('home.hero.banner');

// Multiple assets
await AssetFlux.prefetchAll(['home.logo', 'home.banner', 'profile.avatar']);

// Glob pattern
await AssetFlux.prefetchPattern('home.*');

Direct URL Resolution

Use resolveAssetUrl when you need the URL for a custom widget or download:

final url = AssetFlux.resolveAssetUrl(assetKey: 'home.banner');

Debug Info

Inspect how an asset resolves — version, rollout bucket, selected density:

final info = AssetFlux.getDebugInfo('home.banner');
// {found: true, version: 2, bucket: 37, inRollout: true, targetDensity: 2.0, ...}

Configuration

All options have sensible defaults. Override only what you need:

await AssetFlux.init(
  projectId: 'af_...',
  apiKey: 'afk_...',
  config: const AssetFluxConfig(
    cacheTTL: Duration(hours: 24),         // Manifest cache lifetime
    refreshInterval: Duration(minutes: 15), // Background refresh interval
    timeout: Duration(seconds: 10),         // Network request timeout
    retryAttempts: 3,                       // Retries with exponential backoff
    fallbackBehavior: FallbackMode.cacheFirst,
    identifierType: IdentifierType.device,
    debug: false,
  ),
);
Option Type Default Description
cacheTTL Duration 24 h How long the cached manifest is considered fresh
refreshInterval Duration 15 min Background manifest refresh interval
timeout Duration 10 s Network request timeout
retryAttempts int 3 Max retries with exponential backoff
fallbackBehavior FallbackMode cacheFirst What to do when offline (see below)
identifierType IdentifierType device Identifier source for rollout buckets
customIdentifier String? null Value used when identifierType is custom
instanceConfig InstanceConfig? null Custom API base URL (defaults to https://api.assetflux.io)
debug bool false Print detailed logs to the console

Fallback Modes

Mode Behavior
cacheFirst Serve stale cache when offline. Error only if no cache exists. (default)
bundled Fall back to a bundled asset (fallbackAsset on RemoteImage).
placeholder Show an error widget when remote + cache both fail.

Gradual Rollout

Roll out a new version of an asset to a percentage of users. Each device (or user) is deterministically assigned to a bucket (0–99) so they always see the same version.

// Device-based (default) — same device always sees same version
AssetFluxConfig(identifierType: IdentifierType.device)

// User-based — same user across devices
AssetFluxConfig(identifierType: IdentifierType.user)
// then after login:
AssetFlux.setUserId('user_12345');

// Custom — e.g. organization, A/B test group
AssetFluxConfig(
  identifierType: IdentifierType.custom,
  customIdentifier: 'org_abc',
)

Rollout percentages are configured in the AssetFlux dashboard, not in client code.

Reactive Rebuilds

RemoteImage rebuilds automatically when the manifest updates. For custom widgets, listen to the notifier:

ValueListenableBuilder(
  valueListenable: AssetFlux.manifestNotifier,
  builder: (context, _, child) {
    final url = AssetFlux.resolveAssetUrl(assetKey: 'home.banner');
    return Image.network(url ?? '');
  },
)

Requirements

Minimum
Flutter 3.0
Dart 3.0
iOS 12.0
Android API 21

Documentation

Full documentation is available at docs.assetflux.io/flutter.

License

BSD 3-Clause. See LICENSE for details.

Libraries

assetflux_flutter
AssetFlux Flutter SDK