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.

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).

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.

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.