flux_dynamic_link 1.2.1 copy "flux_dynamic_link: ^1.2.1" to clipboard
flux_dynamic_link: ^1.2.1 copied to clipboard

Flutter plugin for Flux Dynamic Link

Flux Dynamic Link (Flutter) #

Flutter plugin to:

  • Receive Flux links (deep links + universal links) and emit the resolved target URL.
  • Create shortened links via your Flux backend.
  • Support deferred deep linking:
    • Android: Play Install Referrer
    • iOS: NativeLink (clipboard token) + fingerprint fallback

This package is designed to work with the Flux Dynamic Link backend (the Worker/API in this repo). You must provide:

  • publicKey: API key used as Authorization: Bearer ...
  • linkDomain: your link service domain, e.g. https://deeplink.fluxbuilder.com or a custom domain

Requirements #

  • Flutter >= 3.3.0
  • Dart >= 3.10.0

1) Create your Flux project #

Create your project in FluxBuilder (download: https://fluxbuilder.com/download).

Keep these values:

  • Project Id
  • Project Key (used as publicKey)
  • Link domain (used as linkDomain)

2) Install #

Add to your app pubspec.yaml:

dependencies:
  flux_dynamic_link: ^1.2.1

Then run:

flutter pub get

3) Platform setup #

Android #

Add deep link + app link intent-filters to your app AndroidManifest.xml on your main Activity.

Replace:

  • {projectId} with your Flux project id
  • deeplink.fluxbuilder.com with your custom domain host if you use one
<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
        android:scheme="fluxlink-{projectId}"
        android:host="deeplink.fluxbuilder.com" />
</intent-filter>

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
        android:scheme="https"
        android:host="deeplink.fluxbuilder.com" />
</intent-filter>

Also ensure your domain hosts a valid /.well-known/assetlinks.json for Android App Links verification.

iOS #

  1. Add a custom URL scheme in ios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>fluxlink-{projectId}</string>
    </array>
  </dict>
</array>
  1. Enable Universal Links (recommended):
  • Open Xcode → Runner target → Signing & Capabilities → add Associated Domains
  • Add: applinks:deeplink.fluxbuilder.com (or your custom domain)

Your domain must host a valid Apple App Site Association file (AASA).

4) Initialize #

Important: if you want deferred deep link callbacks, call FluxDynamicLink.setOnInstallReferrerDetected before initialize().

import 'package:flutter/widgets.dart';
import 'package:flux_dynamic_link/flux_dynamic_link.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  FluxDynamicLink.setOnInstallReferrerDetected((result) {
    // Called once per install (guarded by local storage)
    if (result.matched == true) {
      // Handle deferred deep link here
      // result.deepLink / result.webFallbackUrl / result.metadata
    }
  });

  await FluxDynamicLink.initialize(
    publicKey: '{publicKey}',
    linkDomain: 'https://deeplink.fluxbuilder.com',
  );

  runApp(const MyApp());
}

Use FluxDynamicLink.instance.dynamicLinkStream.

This stream emits the resolved target URL (usually actual_url from the link, otherwise a fallback resolved from the backend).

FluxDynamicLink.instance.dynamicLinkStream.listen((url) {
  final uri = Uri.tryParse(url);
  if (uri == null) return;
  // Navigate based on uri.path / uri.queryParameters
});

6) Deferred deep linking #

Android (Play Install Referrer) #

On first app open after installation, the plugin reads Play Install Referrer and attempts to match a deferred deep link. You receive the result via setOnInstallReferrerDetected.

On iOS, App Store installs do not preserve query params into the app. Flux supports a deterministic NativeLink-style flow:

  1. Your iOS landing page generates a single-use token server-side.
  2. On user gesture (CTA tap), the page copies https://<domain>/_nl?t=TOKEN into clipboard and redirects to the App Store.
  3. On first app open, the plugin:
    • reads clipboard once (to reduce repeated paste permission prompts)
    • obtains a stable install_id from Keychain
    • calls POST /api/nativelink/redeem to redeem TOKEN
  4. If NativeLink is missing/expired/overwritten/denied, the plugin falls back to fingerprint matching.

Backend requirement: expose POST /api/nativelink/redeem on your linkDomain.

Use createShortenedLink to create a link, then getFullUrl to get the shareable URL.

final linkDetails = await FluxDynamicLink.instance.createShortenedLink(
  CreateFluxDynamicLinkForm(
    slug: 'product-123',
    iosDeeplink: 'fluxstore://product/123',
    androidDeeplink: 'fluxstore://product/123',
    androidPackage: 'com.inspireui.fluxstore',
    appstoreUrl: 'https://apps.apple.com/app/id1234567890',
    playstoreUrl: 'https://play.google.com/store/apps/details?id=com.inspireui.fluxstore',
    webFallbackUrl: 'https://fluxstore.app/product/123',
    metadata: LinkMetadata(
      title: 'FluxStore Product 123',
      description: 'Check out this product',
      image: 'https://fluxstore.app/images/product-123.jpg',
    ),
    expiresAt: DateTime.now().add(const Duration(days: 30)),
  ),
);

final url = FluxDynamicLink.instance.getFullUrl(linkDetails);
// => {linkDomain}/l/{slug}

8) Custom domains (optional) #

If you use a custom domain (e.g. https://links.customer.com), update all of these:

  • App initialization: linkDomain: 'https://links.customer.com'
  • Android: intent-filter host + assetlinks.json must be served by that domain
  • iOS: Associated Domains must include applinks:links.customer.com and AASA must be served by that domain

Typical DNS is:

links.customer.com CNAME deeplink.fluxbuilder.com

Testing #

  • Android Install Referrer is only reliable when installed from Play Store (or internal testing tracks). A local flutter run install usually will not provide real referrer data.

Troubleshooting #

  • Not receiving links:
    • Ensure the clicked link host matches linkDomain (or deeplink.fluxbuilder.com).
    • Verify Android intent-filters + assetlinks.json.
    • Verify iOS Associated Domains + AASA.
  • iOS deferred not matched:
    • NativeLink must be copied on a user gesture.
    • Clipboard can be overwritten before first app open; plugin will then fallback to fingerprint.