Flutter SDK
Deferred deep linking and optional in-app link creation for Flutter apps.
Installation
dependencies:flinku_sdk: ^0.7.2
Configure
void main() async {WidgetsFlutterBinding.ensureInitialized();Flinku.configure(baseUrl: 'https://yourapp.flku.dev');runApp(MyApp());}
match()
match() recovers deferred install attribution. It is not your App Link / Universal Link / URI scheme handler. If your app already routes a launch URL, do not let a deferred match() result overwrite it — call match() only when no launch URL is present. See Apps that already handle their own deep links.
final link = await Flinku.match();if (link.matched) {// link.deepLink, link.params, link.slug}
reset()
await Flinku.reset();
Clears the cached match result only. Does not clear the stored user id or pending referral attribution. This changed in 0.6.0.
resetAll()
await Flinku.resetAll();
Clears everything reset() clears, plus the stored user id, referral project id, all pending referral records, and any tracked-once markers. Testing only — do not call in production. Calling it in production destroys real referral attribution. Added in 0.7.0.
createLink()
Correct architecture: Keep the API key on your own backend. Your app calls your backend, your backend calls Flinku, your backend returns the short URL to your app.
App → Your Backend → Flinku API → short URL → App shares itThe example below shows the SDK call itself, but you should run this on your backend (Dart server / Cloud Function / Node.js / etc.), not inside the mobile app. The Flutter SDK in your app should only call Flinku.match() for deferred deep linking.
// ✅ Run this on your backend, NOT in the mobile appFlinku.configure(baseUrl: 'https://yourapp.flku.dev',apiKey: 'flk_live_your_api_key', // backend-only);final link = await Flinku.createLink(FlinkuLinkOptions(title: 'Summer Campaign',deepLink: 'yourapp://promo',params: {'ref': 'instagram'},));print(link.shortUrl);
From your mobile app, call your own backend endpoint (e.g. POST /api/share), and have your backend return the short URL.
createLinkInstant()
Returns the short URL instantly without waiting for the server. The link is saved in the background. Use this for share buttons where speed matters.
If the background save fails on a transient error (network, timeout, 5xx, or 429), the SDK retries up to three times with 1s, 2s, and 4s delays. A URL shared immediately can still 404 for up to roughly 7 seconds while retries run. Enable debug logging in Flinku.configure(debug: true) to surface terminal failures in the console.
⚠️ Do not wrap createLinkInstant in an async function. It is synchronous and returns immediately. Wrapping it in async/await will add unnecessary delay and defeat the purpose.
import 'package:share_plus/share_plus.dart';final link = Flinku.createLinkInstant(FlinkuLinkOptions(title: 'Summer Campaign',deepLink: 'yourapp://promo',params: {'ref': 'instagram'},));await Share.share(link.shortUrl);
Universal Links not opening the app on iOS (Flutter)
These are Flutter and iOS platform issues, not Flinku behaviour. Flinku short links are ordinary Universal Links and are subject to the same delivery constraints as any other HTTPS Universal Link. If the OS or your deep-link plugin never delivers the URL to Dart, Flinku.match() and your own routing cannot see it.
1. Link opens the app but lands on the wrong screen, or the app opens and nothing routes
Cause: On Flutter 3.38 and later the UIScene lifecycle is mandatory, and app_links 6.x only listens on the old app delegate callbacks, so the Universal Link never reaches Dart and getInitialLink() returns null.
Fix: Upgrade to app_links 7.0.0 or later, which adds UISceneDelegate support.
2. Tapping a link opens the app, then a browser flashes, then the app reopens
Cause: FlutterDeepLinkingEnabled defaults to true, so when no plugin claims the link the Flutter engine hands it back to iOS, which opens it in the browser.
Fix: Set FlutterDeepLinkingEnabled to false in ios/Runner/Info.plist:
<key>FlutterDeepLinkingEnabled</key><false/>
3. Links work sometimes and not others, more often on cold start
Cause: app_links 7.x emits the launch URL on uriLinkStream when the listener attaches. If subscription happens after async startup work, the emission is lost — the stream is not replayed.
Fix: Subscribe to uriLinkStream synchronously at the start of initState, before any await.
@overridevoid initState() {super.initState();// Subscribe before any await — do not defer this._linkSub = AppLinks().uriLinkStream.listen(_handleUri);_bootstrap(); // async work after the subscription}