Skip to main content

Flutter SDK Integration

This tutorial walks you through integrating the OpenLynk SDK into a Flutter app from scratch. By the end, your app will be able to create shareable deep links, handle incoming links, and restore deferred deep links after install.

Prerequisites

  • Completed the Quick Start tutorial (you have an app with an API key)
  • A Flutter project targeting iOS and/or Android
  • Your App ID and API Key from the OpenLynk dashboard

Step 1: Add the SDK

Add the OpenLynk SDK to your pubspec.yaml:

dependencies:
openlynk_sdk:
git:
url: https://github.com/openlynk-sdk/openlynk-flutter.git
ref: main

The SDK automatically pulls in its own dependencies (http, shared_preferences, device_info_plus, app_links), so you do not need to add them manually.

Run flutter pub get to install.

note

If you plan to implement the share button in Step 4, also add the share_plus package. It is not required by the SDK itself -- only when you want to open the native share sheet.

dependencies:
share_plus: ^7.0.0

Step 2: Get Your Credentials

In the OpenLynk dashboard, navigate to your app's settings page. You need two values:

CredentialWhere to find it
App IDApp settings page, displayed at the top
API KeyApp settings page, under "SDK API Key". Click Generate if you have not created one yet.

Keep these values handy -- you will use them in the next step.

Step 3: Initialize the SDK

In your main app widget's initState, create an OpenlynkSDK instance and call init():

import 'package:flutter/material.dart';
import 'package:openlynk_sdk/openlynk_sdk.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
const MyApp({super.key});


State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
late final OpenlynkSDK _sdk;
final _navigatorKey = GlobalKey<NavigatorState>();


void initState() {
super.initState();

_sdk = OpenlynkSDK(
appId: 'YOUR_APP_ID', // from the OpenLynk dashboard
apiKey: 'YOUR_API_KEY', // generate at dashboard -> app -> SDK API Key
config: OpenlynkSDKConfig(
autoRestoreOnInit: true,

// Called after install when pending links are restored
onRestoredLinks: (links) {
for (final link in links) {
_navigateTo(
link.destinationPath ?? link.destinationUrl,
link.parameters ?? link.metadata,
);
}
},

// Called when the app is opened via a Universal Link or App Link
onDeepLink: (parsed) {
_navigateTo(parsed.destinationPath, parsed.parameters);
},
),
);

_sdk.init();
}

void _navigateTo(String path, Map<String, dynamic> params) {
final navigator = _navigatorKey.currentState;
if (navigator == null) return;

if (path.startsWith('/product/')) {
final productId = path.split('/').last;
navigator.push(MaterialPageRoute(
builder: (_) => ProductPage(productId: productId, sdk: _sdk),
));
} else if (path.startsWith('/profile/')) {
final userId = path.split('/').last;
navigator.push(MaterialPageRoute(
builder: (_) => ProfilePage(userId: userId),
));
} else {
navigator.pushNamed(path, arguments: params);
}
}


void dispose() {
_sdk.dispose();
super.dispose();
}


Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navigatorKey,
title: 'My App',
home: HomePage(sdk: _sdk),
);
}
}
note

Replace YOUR_APP_ID and YOUR_API_KEY with the real values from your dashboard. In a production app, load these from environment configuration rather than hardcoding them.

What Happens on init()

When you call _sdk.init(), the SDK:

  1. Reports an install heartbeat (throttled to once per 24 hours)
  2. Restores any pending deferred deep links (if autoRestoreOnInit is true)
  3. Starts listening for incoming Universal Links and App Links
  4. Processes the cold-start link if the app was launched by tapping a deep link

Step 4: Create a Share Button

Add a share button to a screen that creates a deep link and opens the system share sheet. This step uses the share_plus package -- make sure it is added to your pubspec.yaml (see the note in Step 1).

import 'package:share_plus/share_plus.dart';

class ProductPage extends StatefulWidget {
final String productId;
final OpenlynkSDK sdk;

const ProductPage({required this.productId, required this.sdk, super.key});


State<ProductPage> createState() => _ProductPageState();
}

class _ProductPageState extends State<ProductPage> {
bool _isSharing = false;

Future<void> _share() async {
setState(() => _isSharing = true);
try {
final link = await widget.sdk.createLink(
destination: '/product/${widget.productId}',
metadata: {
'product_id': widget.productId,
'utm_source': 'share',
'utm_medium': 'app',
'shared_at': DateTime.now().toIso8601String(),
},
);

await Share.share(
'Check out this product: ${link.url}',
subject: 'Product ${widget.productId}',
);
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Could not create share link')),
);
}
} finally {
if (mounted) setState(() => _isSharing = false);
}
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Product ${widget.productId}'),
actions: [
IconButton(
icon: _isSharing
? const SizedBox(
width: 20, height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.share),
onPressed: _isSharing ? null : _share,
),
],
),
body: Center(
child: Text('Product details for ${widget.productId}'),
),
);
}
}

The createLink call generates a short URL like https://myapp.openlynk.to/1709876543-x7k9m2. All metadata you pass is preserved through the entire link lifecycle -- from creation, through click tracking, to deferred restore after install.

Step 5: Platform Setup for iOS

For Universal Links to open your app directly (bypassing the browser), you need to configure Associated Domains in Xcode.

Add Associated Domains

  1. Open your Flutter project's iOS workspace in Xcode (ios/Runner.xcworkspace)
  2. Select the Runner target
  3. Go to Signing & Capabilities
  4. Click + Capability and add Associated Domains
  5. Add the entry: applinks:YOUR_APP_SLUG.openlynk.to

Replace YOUR_APP_SLUG with your app's slug from the dashboard (e.g. applinks:myshop.openlynk.to).

Verify Your Bundle ID

Make sure the bundle ID in Xcode matches the iOS Bundle ID you entered in the OpenLynk dashboard. The AASA (Apple App Site Association) file that OpenLynk serves at https://YOUR_APP_SLUG.openlynk.to/.well-known/apple-app-site-association must reference your exact bundle ID and team ID.

tip

You can verify the AASA file by visiting that URL in a browser. Look for your appID in the format {TeamID}.{BundleID}.

Step 6: Platform Setup for Android

For App Links to open your app directly, you need an intent filter in your Android manifest and a verified SHA-256 fingerprint.

Add the Intent Filter

Open android/app/src/main/AndroidManifest.xml and add an intent filter to your main activity:

<activity android:name=".MainActivity">
<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="YOUR_APP_SLUG.openlynk.to" />
</intent-filter>
</activity>

Add Your SHA-256 Fingerprint

Get your signing certificate fingerprint:

# For debug builds
keytool -list -v -keystore ~/.android/debug.keystore \
-alias androiddebugkey -storepass android -keypass android

# For release builds
keytool -list -v -keystore your-release-key.keystore -alias your-alias

Copy the SHA-256 fingerprint and enter it in the OpenLynk dashboard under your app's Android settings. OpenLynk uses this to generate the assetlinks.json file at https://YOUR_APP_SLUG.openlynk.to/.well-known/assetlinks.json.

Step 7: Test Deep Linking

Test on iOS

Universal Links do not work in the iOS Simulator. Use a physical device:

  1. Install your app on the device
  2. Open the Notes app, paste your link URL, and long-press it. You should see an option to open in your app.
  3. Alternatively, send the link via Messages and tap it.

Test on Android

Use adb to simulate an App Link:

adb shell am start -a android.intent.action.VIEW \
-d "https://YOUR_APP_SLUG.openlynk.to/YOUR_LINK_SLUG" \
com.example.myapp

Verify that your app opens and the onDeepLink callback fires with the correct destination path and parameters.

Step 8: Test Deferred Deep Linking

Deferred deep linking preserves the link destination when the app is not yet installed:

  1. Uninstall your app from the test device
  2. Open your OpenLynk link in a browser on the device
  3. You will be redirected to the App Store or Play Store (or your web fallback)
  4. Install and launch the app
  5. The onRestoredLinks callback should fire with the original link data, and your app should navigate to the correct screen
warning

Deferred deep link restore relies on device fingerprinting and IP matching. For the most reliable results, test on the same network (do not switch from Wi-Fi to cellular between clicking the link and launching the app after install).

Exit Checklist

  • SDK added to pubspec.yaml and installed
  • SDK initialized with App ID and API Key
  • onDeepLink callback navigates to the correct screen
  • onRestoredLinks callback handles deferred deep links
  • Share button creates links and opens the share sheet
  • Associated Domains configured in Xcode (iOS)
  • Intent filter added to AndroidManifest.xml (Android)
  • Deep linking tested on a physical device
  • Deferred deep linking tested after uninstall and reinstall

What's Next?

  • Flutter SDK Reference -- Full API reference with all methods, configuration options, and data types.
  • Handle Deep Links -- Advanced patterns for routing, fallback handling, and multi-path navigation.
  • Custom Domains -- Serve links from your own domain instead of openlynk.io.
  • Analytics -- Track clicks, installs, and campaign performance.