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
- Portal → Apps → Your app.
- Generate (or reuse) an API key; copy the
appIdandappKey. - 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_sdk0.2.8. This package wraps LinkMeKit0.2.8(iOS/macOS) and the Android SDK0.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 withandroid:autoVerify="true"forhttps://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
hostson 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
Runnertarget → Signing & Capabilities → Associated Domains:
- iOS
applinks:links.yourco.com
- Android
android/app/src/main/AndroidManifest.xmlin 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.plistURL types (CFBundleURLSchemes) addyourapp - Android custom scheme intent filter:
- iOS
<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:
cd sdks/flutter/examplecp .env.example .envand fill in your keys (or pass via--dart-define).flutter runon iOS + Android devices, then click one of your LinkMe slugs.
Next steps
- Use the Flutter-compatible iOS and Android references for method details.
- Read the Deferred Deep Linking Guide for first-install attribution behavior.