infly
Flutter SDK for infl.ly: short links, App Links / Universal Links and deferred deep links (the link survives an install).
- Router-agnostic. The SDK resolves a link to a destination string such as
/board/1234. Your app decides how to navigate. - Deferred deep links on both platforms. Android uses the Play Install Referrer. iOS uses an opt-in pasteboard claim, with a ready-made code dialog as the fallback.
- No fingerprinting. Nothing device-identifying is collected.
- Plays well with other plugins. URL callbacks are never claimed, so sign-in SDKs and home widgets keep receiving theirs. UIScene apps are supported.
Install
flutter pub add infly
1. Register the app
In the infl.ly dashboard, register the app and issue a public key (pk_live_…).
| Setting | Example |
|---|---|
| App ID | goodjob |
| Path prefix | gj → links look like https://infl.ly/gj/Ab3xK91 |
| Custom scheme / host | myapp / link → fallback myapp://link/board/1234 |
| Android | package name, SHA-256 fingerprints (upload and Play app signing key), Play Store URL |
| iOS | bundle ID, Team ID, App Store URL |
2. Configure the platforms
Android
Add to the main activity in android/app/src/main/AndroidManifest.xml
(android:launchMode="singleTask" is recommended):
<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="infl.ly" android:pathPrefix="/gj/" />
</intent-filter>
<!-- Fallback for in-app browsers that block App Links -->
<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="myapp" android:host="link" />
</intent-filter>
The Play Install Referrer needs no setup.
iOS
Enable Associated Domains and add applinks:infl.ly. Register the custom scheme
in Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>myapp</string></array>
</dict>
</array>
The plugin ships a privacy manifest (PrivacyInfo.xcprivacy) and supports both
CocoaPods and Swift Package Manager.
3. Initialize and listen
import 'package:infly/infly.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Infly.onLink.listen((InflyLink link) {
router.push(link.destination); // e.g. /board/1234
});
await Infly.initialize(
appId: 'goodjob',
publicKey: 'pk_live_xxx',
scheme: 'myapp', // must match the dashboard
useIosPasteboard: true, // iOS deferred deep links, see below
);
runApp(const MyApp());
}
onLink replays the most recent link to each new subscriber, so a listener attached
after the first frame still receives the link that launched the app. Links that
arrive while the app is running go through the same stream.
Only https://infl.ly/… and myapp://link/… URLs are treated as links. Anything else
the app receives (OAuth callbacks, myapp://calendar/1 from a home widget) is ignored.
Create a link
final CreatedLink link = await Infly.createLink(
destination: '/board/1234',
metadata: const LinkMetadata(
title: 'Join my board',
description: 'Put a sticker on it with me!',
image: 'https://cdn.example.com/board.png', // https only
),
);
await SharePlus.instance.share(ShareParams(text: link.url));
The metadata becomes the preview in messengers and social apps (Open Graph and Twitter cards).
Deferred deep links
The first launch after an install checks once for the link the user tapped before
installing, and delivers it through onLink with link.isDeferred == true.
| Platform | How | App code |
|---|---|---|
| Android | Play Install Referrer carries an opaque, single-use token | none |
| iOS | The landing page's App Store button copies https://infl.ly/gj/<id>?c=<code>; the SDK reads it on first launch |
useIosPasteboard: true |
| iOS fallback | The user types the code shown on the landing page | Infly.showClaimCodeDialog(context) |
On iOS the pasteboard is read only when all of these hold:
- the app opted in with
useIosPasteboard: true, - this is the first check for this install and the install is under 24 hours old (updated apps are never asked),
- the pasteboard holds a URL (checked without reading, so no prompt otherwise).
iOS 16+ shows its "Allow Paste" prompt once in that case. When the link matched, the SDK clears the pasteboard.
If nothing matched, offer the code dialog, for example from onboarding or a "Have an invite code?" menu:
final InflyLink? link = await Infly.showClaimCodeDialog(
context,
labels: const InflyClaimCodeLabels.korean(), // or your own texts
);
A matched code is also delivered through onLink.
Keys
Ship only the public key (pk_) in the app. initialize throws if it receives a
secret key (sk_). Secret keys are for servers.
Using another link SDK at the same time
If another SDK (for example AppsFlyer) or your own code also receives the URL that
opened the app, make it ignore infl.ly URLs. Otherwise it may navigate to the raw
path (/gj/Ab3xK91) and override the destination infly resolved.
API
| Member | Purpose |
|---|---|
Infly.initialize(...) |
Configure the SDK, handle the launch link, run the deferred check |
Infly.onLink |
Stream of resolved links (InflyLink) |
Infly.createLink(...) |
Create a short link for sharing |
Infly.checkDeferredLink() |
Run the deferred check manually (force: true to repeat) |
Infly.showClaimCodeDialog(context) |
Ready-made code dialog |
Infly.redeemClaimCode(code) |
Redeem a code with your own UI |
Infly.handleUrl(url) |
Resolve a URL received through your own channel |
Libraries
- infly
- Short link, deep link and deferred deep link SDK for infl.ly.