Flutter Getting Started
Install the Flutter plugin, connect it to your ULink project, and validate on both platforms.
1. Prerequisites
Development Environment
- Flutter SDK installed
- iOS: Xcode 15+ and iOS 13+ deployment target (for iOS builds)
- Android: Android Studio Giraffe or newer, Gradle 8+, Min SDK 21+ (for Android builds)
ULink Account Setup
- ULink account and project (create one here)
- API key generated from Dashboard → Settings → API Keys → Generate API Key
- Domain configured in your project (Domains → Add Domain)
Platform Configuration
- iOS: URL scheme and associated domain configured (see step 3.2)
- Android: Intent filters and permissions configured (see step 3.1)
2. Add the dependency
- Open your
pubspec.yamlfile in the root of your Flutter project - Add
flutter_ulink_sdkto your dependencies:
dependencies:
flutter:
sdk: flutter
flutter_ulink_sdk: ^0.1.0
- Run the following command in your terminal:
flutter pub get
If you use code generation elsewhere in your project, you may also need to run flutter pub run build_runner build. This is typically only needed if you're using packages like json_serializable or freezed.
3. Configure Native Platforms
Flutter apps need platform-specific configuration for both iOS and Android. You'll need to configure each platform separately.
Step 3.1: Configure Android Platform
Android requires intent filters in the manifest to handle deep links.
- Open
android/app/src/main/AndroidManifest.xmlin your Flutter project - Add required permissions at the top level (inside
<manifest>tag, before<application>):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourapp">
<!-- Add these permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application ...>
- Find your main activity (usually
MainActivityorio.flutter.embedding.android.FlutterActivity) - Add intent filters inside the activity tag:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Existing launcher intent filter (keep this) -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Android App Link intent filter (for HTTPS links) -->
<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.shared.ly" />
</intent-filter>
<!-- Optional: Custom URL scheme intent filter -->
<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" />
</intent-filter>
</activity>
- Replace
links.shared.lywith the domain you configured in the ULink dashboard - Replace
myappwith your custom URL scheme (if using one) - The
android:autoVerify="true"attribute enables Android App Links verification - The
android:launchMode="singleTop"ensures proper deep link handling - Keep your existing launcher intent filter - don't remove it
In Flutter projects, the main activity is typically:
MainActivity(if you have a custom one)io.flutter.embedding.android.FlutterActivity(default Flutter activity)
Check your AndroidManifest.xml to see which one you're using.
Step 3.2: Configure iOS Platform
iOS requires URL schemes and Associated Domains to handle deep links.
Configure URL Scheme
-
Open your iOS project in Xcode:
open ios/Runner.xcworkspace(Use
.xcworkspace, not.xcodeprojif you're using CocoaPods) -
Select the Runner target in the project navigator
-
Go to the Info tab
-
Scroll down to URL Types section
-
Click the + button to add a new URL Type
-
Fill in the following:
- Identifier: Your bundle identifier (e.g.,
com.yourapp) - URL Schemes: Enter your scheme (e.g.,
myapp- this will create URLs likemyapp://) - Role:
Editor
- Identifier: Your bundle identifier (e.g.,
- Use lowercase letters and numbers only
- Keep it short and memorable (e.g.,
myapp,shop,news) - Avoid special characters or spaces
Configure Associated Domains (Universal Links)
- In Xcode, with the Runner target selected, go to the Signing & Capabilities tab
- Click + Capability and select Associated Domains
- Click + under Domains to add a new domain
- Enter your domain in the format:
applinks:yourdomain.comorapplinks:links.shared.ly- Replace
yourdomain.comwith the domain you configured in the ULink dashboard - The
applinks:prefix is required by iOS - For shared domains, use:
applinks:links.shared.ly(or your custom subdomain)
- Replace
The domain you add here must match exactly with the domain configured in your ULink dashboard under Domains. If you're using a shared domain like links.shared.ly, make sure it's added in both places.
If you prefer editing files directly, you can also configure URL schemes in ios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.yourapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
And Associated Domains in ios/Runner/Runner.entitlements:
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:links.shared.ly</string>
</array>
4. Initialize the SDK in Dart
Initialize the ULink SDK in your Flutter app before rendering the widget tree:
- Open your
lib/main.dartfile - Import the SDK:
import 'package:flutter_ulink_sdk/flutter_ulink_sdk.dart';
- Initialize the SDK in your
mainfunction:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize ULink SDK
await ULink.instance.initialize(
ULinkConfig(
apiKey: 'ULINK_API_KEY', // Replace with your API key
baseUrl: 'https://api.ulink.ly',
debug: true, // Set to false in production
),
);
runApp(MyApp());
}
- Call
WidgetsFlutterBinding.ensureInitialized()first - this is required for async initialization - Initialize the SDK before
runApp()to ensure it's ready when your app starts - The SDK initialization is asynchronous, so use
awaitto ensure it completes
Here's a complete example of a main.dart file with SDK initialization:
import 'package:flutter/material.dart';
import 'package:flutter_ulink_sdk/flutter_ulink_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize ULink SDK
await ULink.instance.initialize(
ULinkConfig(
apiKey: 'your-api-key-here',
baseUrl: 'https://api.ulink.ly',
debug: true,
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: HomeScreen(),
);
}
}
5. Configure Dashboard Settings
Now that your app is configured, you need to match those settings in the ULink dashboard. These settings are required for ULink to generate the verification files that enable Universal Links (iOS) and App Links (Android).
iOS Configuration
Navigate to Configuration → General → iOS in your ULink dashboard.
Bundle Identifier
Your Bundle Identifier uniquely identifies your iOS app.
- Find your Bundle ID in Xcode under your target's General tab, or in
ios/Runner.xcodeproj/project.pbxprojasPRODUCT_BUNDLE_IDENTIFIER - Enter it in the Bundle ID field
Team ID
Your Apple Developer Team ID is required for Universal Links to work.
Find your Team ID:
- Go to Apple Developer Portal → Membership
- Copy your Team ID (a 10-character string like
ABC123DEF4)
Or find it in Xcode:
- Open
ios/Runner.xcworkspacein Xcode - Select the Runner target → Signing & Capabilities tab
- Your Team ID appears in parentheses next to your team name
Enter your Team ID in the Team ID field in the ULink dashboard.
URL Scheme
Enter the URL scheme you configured in step 3.2 (e.g., myapp — without the ://).
Android Configuration
Navigate to Configuration → General → Android in your ULink dashboard.
Package Name
Your Package Name uniquely identifies your Android app.
- Find your package name in
android/app/build.gradle.ktsasnamespace = "com.yourapp", or inAndroidManifest.xmlaspackage="com.yourapp" - Enter it in the Package Name field
SHA-256 Certificate Fingerprints
SHA-256 fingerprints are required for Android App Links verification.
Get your fingerprint:
Run this command in your Flutter project root:
cd android && ./gradlew signingReport
Look for the SHA-256 line under your signing configuration.
Alternatively, use keytool:
# Debug keystore
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android | grep SHA-256
Add to dashboard:
- Click Add Fingerprint in the SHA-256 section
- Paste your fingerprint
- Repeat for all signing keys (debug, release, Play App Signing)
For App Links to work in all environments, add fingerprints for:
- Debug keystore — For development
- Release keystore — For production builds
- Play App Signing — If using Google Play App Signing, find the fingerprint in Play Console → Setup → App signing
URL Scheme (Optional)
If you configured a custom URL scheme in step 3.1, enter it (e.g., myapp — without the ://).
Domain Configuration
- Navigate to the Domains section
- Add your domain if not already configured:
- Shared domains: Click Add Domain → Select Shared Domain (.shared.ly)
- Custom domains: Click Add Domain → Enter domain → Complete DNS verification
- Ensure the domain matches:
- Android: The
android:hostvalue in your intent filter (step 3.1) - iOS: The domain in your Associated Domains (step 3.2, without
applinks:prefix)
- Android: The
All these settings must match exactly between your app and the dashboard:
- iOS: Bundle ID, Team ID, URL Scheme, Domain
- Android: Package Name, SHA-256 Fingerprints, URL Scheme, Domain
If any don't match, deep links will open in the browser instead of your app.
6. Create a test link
Follow the same dashboard process as native apps:
- Links → Create Link
- Choose Unified (store) or Dynamic (deep link parameters)
- Save and copy the short URL
7. Test on devices
- Run
flutter runon iOS and Android. - Tap the short URL (use
adbor share sheets). - Ensure:
- Flutter log shows
DEBUG: Link listeners setup complete. - Your
onDynamicLinkoronUnifiedLinkcallback receives data.
- Flutter log shows
See Receive Links → Flutter for wiring the streams to navigation.
7.5 Verify with ULink CLI (Recommended)
The ULink CLI verifies both iOS and Android configurations in your Flutter project.
Install the CLI
# macOS / Linux
curl -fsSL https://ulink.ly/install.sh | bash
# Windows (PowerShell)
irm https://ulink.ly/install.ps1 | iex
Run Verification
# Authenticate
ulink login
# Link your project
cd /path/to/your/flutter-app
ulink project set
# Run verification (checks both platforms)
ulink verify -v
What the CLI Verifies
Android:
- SDK dependency in
android/app/build.gradle - Intent filters in
AndroidManifest.xml - Asset Links file validation
- Package name and SHA256 fingerprint matching
iOS:
- URL schemes in
Info.plist - Bundle identifier configuration
- Entitlements and associated domains
- AASA file validation
Fixing Issues
The verification report highlights exactly what's misconfigured for each platform. Address issues in the corresponding platform directories (android/ or ios/).
The CLI automatically detects Flutter projects and validates both platforms in a single command.
8. Confirm analytics
- In Links, check that click counts increment.
- Click the Analytics button for that specific link to open its analytics page and ensure the platform shows the correct value (iOS or Android) and geo data populates.
If not, revisit the platform-specific getting-started pages or Troubleshoot & Test Deep Links.