Skip to main content

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

  1. Open your pubspec.yaml file in the root of your Flutter project
  2. Add flutter_ulink_sdk to your dependencies:
pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_ulink_sdk: ^0.1.0
  1. Run the following command in your terminal:
flutter pub get
Code Generation

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.

  1. Open android/app/src/main/AndroidManifest.xml in your Flutter project
  2. 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 ...>
  1. Find your main activity (usually MainActivity or io.flutter.embedding.android.FlutterActivity)
  2. 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>
Android Configuration Notes
  • Replace links.shared.ly with the domain you configured in the ULink dashboard
  • Replace myapp with 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
Finding Your Main Activity

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

  1. Open your iOS project in Xcode:

    open ios/Runner.xcworkspace

    (Use .xcworkspace, not .xcodeproj if you're using CocoaPods)

  2. Select the Runner target in the project navigator

  3. Go to the Info tab

  4. Scroll down to URL Types section

  5. Click the + button to add a new URL Type

  6. Fill in the following:

    • Identifier: Your bundle identifier (e.g., com.yourapp)
    • URL Schemes: Enter your scheme (e.g., myapp - this will create URLs like myapp://)
    • Role: Editor
URL Scheme Best Practices
  • Use lowercase letters and numbers only
  • Keep it short and memorable (e.g., myapp, shop, news)
  • Avoid special characters or spaces
  1. In Xcode, with the Runner target selected, go to the Signing & Capabilities tab
  2. Click + Capability and select Associated Domains
  3. Click + under Domains to add a new domain
  4. Enter your domain in the format: applinks:yourdomain.com or applinks:links.shared.ly
    • Replace yourdomain.com with 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)
Domain Configuration

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.

Alternative: Edit Info.plist Directly

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:

  1. Open your lib/main.dart file
  2. Import the SDK:
import 'package:flutter_ulink_sdk/flutter_ulink_sdk.dart';
  1. Initialize the SDK in your main function:
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());
}
Initialization Timing
  • 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 await to ensure it completes
Complete Example

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.

  1. Find your Bundle ID in Xcode under your target's General tab, or in ios/Runner.xcodeproj/project.pbxproj as PRODUCT_BUNDLE_IDENTIFIER
  2. 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:

  1. Go to Apple Developer PortalMembership
  2. Copy your Team ID (a 10-character string like ABC123DEF4)

Or find it in Xcode:

  1. Open ios/Runner.xcworkspace in Xcode
  2. Select the Runner target → Signing & Capabilities tab
  3. 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.

  1. Find your package name in android/app/build.gradle.kts as namespace = "com.yourapp", or in AndroidManifest.xml as package="com.yourapp"
  2. 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:

  1. Click Add Fingerprint in the SHA-256 section
  2. Paste your fingerprint
  3. Repeat for all signing keys (debug, release, Play App Signing)
Add All Signing Keys

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

  1. Navigate to the Domains section
  2. 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
  3. Ensure the domain matches:
    • Android: The android:host value in your intent filter (step 3.1)
    • iOS: The domain in your Associated Domains (step 3.2, without applinks: prefix)
Matching Configuration

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.

Follow the same dashboard process as native apps:

  1. Links → Create Link
  2. Choose Unified (store) or Dynamic (deep link parameters)
  3. Save and copy the short URL

7. Test on devices

  1. Run flutter run on iOS and Android.
  2. Tap the short URL (use adb or share sheets).
  3. Ensure:
    • Flutter log shows DEBUG: Link listeners setup complete.
    • Your onDynamicLink or onUnifiedLink callback receives data.

See Receive Links → Flutter for wiring the streams to navigation.

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

Cross-Platform Verification

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.