Skip to main content

Set up universal links for iOS

Deep linking allows an app user to launch an app with a URI. This URI contains scheme, host, and path, and opens the app to a specific screen.

A universal link, a type of deep link exclusive to iOS devices, uses only the http or https protocols.

To set up universal links, you need to own a web domain. As a temporary solution, consider using Firebase Hosting or GitHub Pages.

Create or modify a Flutter app

#

Write a Flutter app that can handle an incoming URL.

This example uses the go_router package to handle the routing. The Flutter team maintains the go_router package. It provides a simple API to handle complex routing scenarios.

  1. To create a new application, type flutter create <app-name>.

    flutter create deeplink_cookbook
  2. To include the go_router package as a dependency, run flutter pub add:

    flutter pub add go_router
  3. To handle the routing, create a GoRouter object in the main.dart file:

    main.dart
    dart
    import 'package:flutter/material.dart';
    import 'package:go_router/go_router.dart';
    
    void main() => runApp(MaterialApp.router(routerConfig: router));
    
    /// This handles '/' and '/details'.
    final router = GoRouter(
      routes: [
        GoRoute(
          path: '/',
          builder: (_, __) => Scaffold(
            appBar: AppBar(title: const Text('Home Screen')),
          ),
          routes: [
            GoRoute(
              path: 'details',
              builder: (_, __) => Scaffold(
                appBar: AppBar(title: const Text('Details Screen')),
              ),
            ),
          ],
        ),
      ],
    );

Adjust iOS build settings

#
  1. Launch Xcode.

  2. Open the ios/Runner.xcworkspace file inside the Flutter project's ios folder.

Add associated domains

#
  1. Launch Xcode if necessary.

  2. Click the top-level Runner.

  3. In the Editor, click the Runner target.

  4. Click Signing & Capabilities.

  5. To add a new domain, click + Capability under Signing & Capabilities.

  6. Click Associated Domains.

    Xcode associated domains screenshot

  7. In the Associated Domains section, click +.

  8. Enter applinks:<web domain>. Replace <web domain> with your own domain name.

    Xcode add associated domains screenshot

  1. Open the ios/Runner/Runner.entitlements XML file in your preferred editor.

  2. Add an associated domain inside the <dict> tag.

    xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>com.apple.developer.associated-domains</key>
      <array>
        <string>applinks:example.com</string>
      </array>
    </dict>
    </plist>
  3. Save the ios/Runner/Runner.entitlements file.

To check that the associated domains you created are available, perform the following steps:

  1. Launch Xcode if necessary.

  2. Click the top-level Runner.

  3. In the Editor, click the Runner target.

  4. Click Signing & Capabilities. The domains should appear in the Associated Domains section.

    Xcode add associated domains screenshot

You have finished configuring the application for deep linking.

Associate your app with your web domain

#

You need to host an apple-app-site-association file in the web domain. This file tells the mobile browser which iOS application to open instead of the browser. To create the file, find the appID of the Flutter app you created in the previous section.

Locate components of the appID

#

Apple formats the appID as <team id>.<bundle id>.

  • Locate the bundle ID in the Xcode project.
  • Locate the team ID in the developer account.

For example: Given a team ID of S8QB4VV633 and a bundle ID of com.example.deeplinkCookbook, you would enter an appID entry of S8QB4VV633.com.example.deeplinkCookbook.

Create and host apple-app-site-association JSON file

#

This file uses the JSON format. Don't include the .json file extension when you save this file. Per Apple's documentation, this file should resemble the following content:

json
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appIDs": [
          "S8QB4VV633.com.example.deeplinkCookbook"
        ],
        "paths": [
          "*"
        ],
        "components": [
          {
            "/": "/*"
          }
        ]
      }
    ]
  },
  "webcredentials": {
    "apps": [
      "S8QB4VV633.com.example.deeplinkCookbook"
    ]
  }
}
  1. Set one value in the appIDs array to <team id>.<bundle id>.

  2. Set the paths array to ["*"]. The paths array specifies the allowed universal links. Using the asterisk, * redirects every path to the Flutter app. If needed, change the paths array value to a setting more appropriate to your app.

  3. Host the file at a URL that resembles the following structure.

    <webdomain>/.well-known/apple-app-site-association

  4. Verify that your browser can access this file.

#

Test a universal link using a physical iOS device or the Simulator.

  1. Before testing, install the Flutter app on the iOS device or Simulator, Use flutter run on the desired device.

    Simulator screenshot

    When complete, the Flutter app displays on the home screen of the iOS device or Simulator.

  2. If you test using the Simulator, use the Xcode CLI:

    xcrun simctl openurl booted https://<web domain>/details
  3. If you test with a physical iOS device:

    1. Launch the Note app.
    2. Type the URL in the Note app.
    3. Click the resulting link.

    If successful, the Flutter app launches and displays its details screen.

    Deeplinked Simulator screenshot

Find the source code

#

You can find the source code for the deeplink_cookbook recipe in the GitHub repo.