skip to Main Content

I have set up Universal Links on my flutter project for IOS.

Like the title suggests, my app does open when I click on a link relating to my site but it does not navigate to the correct page. It just opens the app.
I’m not using the uni_links package, rather I used a combination of guides (including official documentation):

https://developer.apple.com/videos/play/wwdc2019/717/

https://nishbhasin.medium.com/apple-universal-link-setup-in-ios-131a508b45d1

https://www.kodeco.com/6080-universal-links-make-the-connection

I have setup my apple-app-site-association file to look like:

{
    "applinks": {
        "details": [
            {
                "appIDs": [
                    "XXXXXXX.com.my.appBundle"
                ],
                "componenents": [
                    {
                        "/": "/*"
                    }
                ]
            }
        ]
    }
}

and I have added this to my info.plist file:

<key>FlutterDeepLinkingEnabled</key>
<true/>

and my AppDelegate.swift file looks like:

import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(_ application: UIApplication, continue userActivity: NSUserActivity, 
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    // This will allow us to check if we are coming from a universal link
    // and get the url with its components
    // The activity type (NSUserActivityTypeBrowsingWeb) is used
    // when continuing from a web browsing session to either
    // a web browser or a native app. Only activities of this
    // type can be continued from a web browser to a native app.
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
      let url = userActivity.webpageURL,
      let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
        return false
    }
    // Now that we have the url and its components,
    // we can use this information to present
    // appropriate content in the app
    return true
  }

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

My Runner-entitlements are also setup correctly like:

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:www.example.com</string>
    <string>applinks:*.example.com</string>
</array>

The issue is, if I click a hyperlink for www.example.com/mypath , it does not got to the page/route handled by /mypath, but instead just opens the app.

My routing is done using go_router: ^5.2.4

Please does anyone know why this is happening? I’m blocked by this. I have seen similar questions, but none with answers that have worked for me. Any help is appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    Ok so figured it out. The official apple documentation requests the addition of a variation of this function in the AppDelegate.swift file:

    func application(_ application: UIApplication, continue userActivity: NSUserActivity, 
        restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        // This will allow us to check if we are coming from a universal link
        // and get the url with its components
        // The activity type (NSUserActivityTypeBrowsingWeb) is used
        // when continuing from a web browsing session to either
        // a web browser or a native app. Only activities of this
        // type can be continued from a web browser to a native app.
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL,
          let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
            return false
        }
        // Now that we have the url and its components,
        // we can use this information to present
        // appropriate content in the app
        return true
      }
    

    Seems that it conflicts with the flutter framework for handling universal links. Taking that function out and just having this in my info.plist worked (everything else stayed the same):

    <key>FlutterDeepLinkingEnabled</key>
    <true/>
    

    Flutter documentation is not out for this (as at the time of posting this answer) so if people are interested, I could do a small article on the necessary steps.


  2. When you handle the dynamic link you get the universal link and other data in the userActivity parameter of the following function.

    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        if let incomingURL = userActivity.webpageURL {
            debugPrint("incoming url is", incomingURL)
            let link = DynamicLinks.dynamicLinks().shouldHandleDynamicLink(fromCustomSchemeURL: incomingURL)
            print(link)
            let linkHandle = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { link, error in
                guard error == nil else {
                    print("Error found.")
                    return
                }
                if let dynamicLink = link {
                    self.handleDynamicLinks(dynamicLink)
                }
            }
            if linkHandle {
                return true
            } else {
                return false
            }
        }
        return false
    }
    

    Parse the data from another function or you can parse in above code also. In my case I parsed the code in below function.

    func handleDynamicLinks(_ dynamicLink: DynamicLink) {
        guard let link = dynamicLink.url else {
            return
        }
        
        if let landingVC = self.window?.rootViewController as? LandingViewController {
           // Do you your handling here with any controller you want to send or anything.
        }
              // example you are getting ID, you can parse it here
    
        if let idString = link.valueOf("id"), let id = Int.init(idString) {
            print(id)
        }
    }
    

    When you get the details from the link you can simply fetch the navigation controller or the VisibleController, and then can push to the desired flow.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search