The missing guide to deep linking in Flutter apps - Part 2, iOS

If you've missed the first part, you can read here.

What you need to do:

  • Adjust Info.plist

  • Add "Associated Domains" capability to each bundle ID

  • Host the apple-app-site-association file

  • Test with a simulator or a real device, or via the XCode CLI

Edit 4 March 2023: Additional info from Reddit comment

User walker_Jayce shared his gotchas when he was implementing deeplink, which I have now included in this article - see original comment here. Do check out his other Flutter notes on Github too.

Adjust Info.plist

Overall, the setup for iOS has relatively less quirks and the official guide covers almost everything you need. However, when you are updating the Info.plist file, take note if you are using app_links package you should not include the FlutterDeepLinkingEnabled property.

Add "Associated Domains" capability to each bundle ID

Follow the official guide. Apart from setting the associated domain(s) in XCode, you should also remember to set the same in Apple Developer Portal (Certificates, Identifiers & Profiles > Identifiers > Select an identifier > Capabilities).

Host the apple-app-site-association file

Similar to assetlinks.json , you would also need to host the Apple-equivalent file on your web server. However, unlike Android, iOS universal links must be in https, which some internal test servers may not be.

The directory to host is the same (.well-known), only the file name is different: <webdomain>/.well-known/apple-app-site-association . You can apply the same tip to host it with Firebase Hosting if you don't already have a web server and update the web domain accordingly.

You can also associate a single web domain with multiple app IDs, e.g. when you have different flavours of the app, like so:

  "applinks": {
      "apps": [],
      "details": [
        "appID": "<team_id>",
        "paths": ["*"]
        "appID": "<team_id>",
        "paths": ["*"]
        "appID": "<team_id>.com.example.myapp",
        "paths": ["*"]

You can configure the domain association to only match a specific path of the web domain, especially when you only want a certain paths to be redirected to your app. It can also support advanced matching, as showcased here.

Testing if it works

Similar to that in Android, make sure you have reinstalled the app after you have done the above steps, you can type a URL in a separate app (e.g. in a Note app, or send an email to yourself, or type in a Google Doc) and then tap on the URL (note: typing or pasting the URL in the browser would not work!). It should navigate to the app and open the specific screen correspondingly.

Alternatively, you can run this command to trigger: xcrun simctl openurl booted https://<web domain>/details . There is also a warning in the official guide that it might take up to 24 hours before Apple’s Content Delivery Network (CDN) requests the apple-app-site-association (AASA) file from your web domain, so the app link won’t work until the CDN requests the file.

Here are some additional troubleshooting tips (thanks walker_Jayce!):

  1. When testing, check if your link ends with a ., if yes you will have to use apps like this and this to launch the links, since most text editors will not include the . when clicking and open the link.

  2. If you would like to test deep links on a server not reachable by Apple CDN, you can use Associated Domains Development to force your device to fetch the json file directly. Apple's video discussing this, start at 18:22

    1. Enable Developer Mode (Settings > Privacy & Security > Developer Mode)

    2. Enable Associated Domains Development (Settings > Developer > Section: Universal Links > Associated Domains Development) and insert internal link in Diagnostics to fetch the apple-app-site-association file. (the Developer section is quite low, so scroll lower, should be just before your 3rd party apps section)

  3. Guide to troubleshoot deeplinks

  4. You can check if your file is hosted correctly on Apple's CDN by launching this link, replace <your website link> with your own link:<your website link>

  5. If your rootViewController is not a FlutterViewController (if you somehow overwritten it in your AppDelegate.swift file), you may need to manually add code to capture the request from iOS side.

Alright, that's all for the deep linking. Let me know if I missed something, leave a comment if you find this kind of guide useful, so I'd be motivated to write more :D