LinkMe Flutter SDK

Cross-platform deep linking, deferred deep linking, and attribution for Flutter apps.

pub.dev License

Quick start

1. Prerequisites

  • A LinkMe app configured with your iOS bundle ID and Android package name
  • API keys (appId and appKey) from App Settings > API Keys
  • Flutter 3.44+ (Swift Package Manager is enabled by default)

2. Install

flutter pub add flutter_linkme_sdk

Or add manually to pubspec.yaml:

dependencies:
  flutter_linkme_sdk: ^0.3.0

3. Configure native platforms

iOS — Set the Runner deployment target to iOS 14 or newer, then enable Associated Domains on the Runner target:

applinks:links.yourco.com

Add a custom URL scheme in Info.plist (CFBundleURLSchemes): yourapp

Android — In android/app/src/main/AndroidManifest.xml, add intent filters:

<!-- HTTPS App Links -->
<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>

<!-- Custom scheme -->
<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>
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(
      appId: String.fromEnvironment('LINKME_APP_ID'),
      appKey: String.fromEnvironment('LINKME_APP_KEY'),
    ),
  );

  // Cold-start link
  final initial = await LinkMe.shared.getInitialLink();

  // Deferred deep link (first install)
  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();
    // Live links while app is running
    _sub = LinkMe.shared.onLink.listen(routeUser);
  }

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomeScreen());
  }

  void routeUser(LinkMePayload payload) {
    // Navigate based on payload.path / payload.params
  }
}

Deferred deep linking

Platform Primary Fallback
iOS Pasteboard (cid token) Fingerprint (/api/deferred/claim)
Android Play Install Referrer (/api/install-referrer) Fingerprint (/api/deferred/claim)

Enable Pasteboard for Deferred Links in App Settings for deterministic iOS attribution.

Swift Package Manager

Flutter discovers the plugin's Swift packages from ios/flutter_linkme_sdk/Package.swift and macos/flutter_linkme_sdk/Package.swift. Flutter 3.44+ generates the FlutterFramework package sibling automatically, and the plugin resolves LinkMeKit 0.2.14 from its repository-root Swift package. CocoaPods remains available for projects that have not migrated to SwiftPM.

Forced web redirects

If a payload contains forceRedirectWeb: true and a non-empty webFallbackUrl, the SDK opens the external browser automatically and does not deliver that payload to getInitialLink(), claimDeferredIfAvailable(), or onLink.

API reference

Method Description
configure(config) Initialize the SDK
getInitialLink() Get the payload that launched the app
onLink (Stream) Stream of payloads while the app is running
claimDeferredIfAvailable() Claim deferred deep link on first install
track(event, {properties}) Send analytics events
setUserId(userId) Associate a user ID
setAdvertisingConsent(granted) Toggle Ad ID inclusion
setReady() Signal readiness to process queued links
debugVisitUrl(url, {headers}) Debug helper for testing link resolution

Config options

Field Type Default Description
appId String? App identifier
appKey String? Optional read-only key
sendDeviceInfo bool true Include device metadata
includeVendorId bool true Include vendor identifier
includeAdvertisingId bool false Include Ad ID (requires consent)
debug bool false Enable verbose native logs

Instance-based client

final client = LinkMeClient();
await client.configure(const LinkMeConfig(appId: 'app_123'));

Use LinkMeClient for dependency injection or test-friendly patterns. It mirrors the LinkMe API.

Example app

The example/ directory contains a runnable sample:

cd example
cp .env.example .env  # fill in your keys
flutter run

Troubleshooting

  • See the Android Troubleshooting guide for App Links verification issues.
  • Enable debug: true in LinkMeConfig to see native logs for link resolution and deferred claims.

License

Apache-2.0