Home Developer Setup Flutter Setup Guide

Flutter Setup Guide

Last updated on Apr 04, 2026

Flutter setup tutorial

Ship the same implementation as the /example app in the Flutter plugin.

Before you start

  • LinkMe app configured with your iOS bundle ID and Android package name
  • Flutter 3.22+
  • Access to update iOS entitlements and Android manifest

1. Create keys

  1. Portal → Apps → Your app.
  2. Generate (or reuse) an API key; copy the appId and appKey.
  3. Enable pasteboard support for iOS if you want deterministic deferred links.

2. Install the package

flutter pub add flutter_linkme_sdk

Latest release: flutter_linkme_sdk 0.2.8. This package wraps LinkMeKit 0.2.8 (iOS/macOS) and the Android SDK 0.2.8.

The example project lives at sdks/flutter/example. Open it in VS Code or Android Studio to compare with your implementation.

3. Configure platforms

  • iOS: In Xcode, enable Associated Domains and add applinks:links.yourco.com. LinkMe hosts the AASA file automatically.
  • Android: In AndroidManifest.xml, add an intent filter with android:autoVerify="true" for https://links.yourco.com. (You can also add a custom scheme.)

Manual deep-link config mapping

Use these values for your Flutter deep-link setup:

{
  "hosts": ["links.yourco.com"],
  "associatedDomains": ["links.yourco.com"],
  "schemes": ["yourapp"]
}

What each field does and why it must be set:

  • hosts: your HTTPS deep-link domain(s). These map to iOS Associated Domains and Android App Links hosts.
  • associatedDomains: domain allowlist for iOS universal links; keep this aligned with your HTTPS hosts.
  • schemes: fallback custom URL scheme(s) for explicit scheme opens.

Why this is required:

  • Without hosts / associatedDomains, universal links cannot be verified/routed into the iOS app.
  • Without hosts on Android, HTTPS links will not resolve as verified App Links.
  • Without schemes, yourapp://... style links will not open your app.
  • If host/scheme values are missing or mismatched, links fall back to browser or fail to route.

add the same values manually in Flutter native targets:

  • hosts / associatedDomains:
    • iOS Runner target → Signing & Capabilities → Associated Domains:
applinks:links.yourco.com
  • Android android/app/src/main/AndroidManifest.xml in your launch activity:
<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="links.yourco.com" />
</intent-filter>
  • schemes:
    • iOS Info.plist URL types (CFBundleURLSchemes) add yourapp
    • Android custom scheme intent filter:
<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="yourapp" />
</intent-filter>

4. Initialize LinkMe in main.dart

import 'package:flutter/material.dart';
import 'package:flutter_linkme_sdk/flutter_linkme_sdk.dart';

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

  await LinkMe.shared.configure(
    const LinkMeConfig(
      baseUrl: 'https://links.yourco.com',
      appId: String.fromEnvironment('LINKME_APP_ID'),
      appKey: String.fromEnvironment('LINKME_APP_KEY'),
    ),
  );

  final initial = await LinkMe.shared.getInitialLink();
  final deferred = initial ?? await LinkMe.shared.claimDeferredIfAvailable();

  runApp(App(initialPayload: initial, deferredPayload: deferred));
}

class App extends StatefulWidget {
  const App({super.key, this.initialPayload, this.deferredPayload});
  final LinkMePayload? initialPayload;
  final LinkMePayload? deferredPayload;

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  late final StreamSubscription<LinkMePayload> _sub;

  @override
  void initState() {
    super.initState();
    _sub = LinkMe.shared.onLink.listen(routeUser);
  }

  @override
  void dispose() {
    _sub.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(
        initial: widget.initialPayload,
        deferred: widget.deferredPayload,
      ),
    );
  }

  void routeUser(LinkMePayload payload) {
    // push to Navigator based on payload.path/params
  }
}

Call LinkMe.shared.track('open') after key app events and LinkMe.shared.setAdvertisingConsent(true) once the user accepts your consent flow.

5. Test with the plugin example

To replicate the shipped sample:

  1. cd sdks/flutter/example
  2. cp .env.example .env and fill in your keys (or pass via --dart-define).
  3. flutter run on iOS + Android devices, then click one of your LinkMe slugs.

Next steps