swiftfirebasedeep-linkingfirebase-dynamic-linksuiscenedelegate

Dynamic Links not working when app is closed, only when in background


I've been working to include Dynamic Links in my app. I have set it up so that links can be generated correctly, and received correctly, but they only work when the app is open and in the background. If the app is closed completely, the link will just open the app. It looks like it is not calling the continueUserActivity method in the AppDelegate even though I am returning TRUE in the didFinishLaunchingWithOptions method. I have read that I should be getting the incoming URL in the didFinishLaunchingWithOptions method, but the available answers do not work and are outdated, so I was hoping someone would know.

Here's the code:

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate{

var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    FirebaseApp.configure()
    return true
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
            
    if let incomingURL = userActivity.webpageURL {
        
        let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
            guard error == nil else {
                print(error!.localizedDescription)
                return
            }
            if let dynamicLink = dynamicLink {
                self.handleIncomingDynamicLink(dynamicLink)
            } else {
                print("Something went wrong")
            }
        }
        if linkHandled {
            return true
        } else {
            return false
        }
    }
    return false
}

func handleIncomingDynamicLink(_ dynamicLink: DynamicLink) {
    guard let url = dynamicLink.url else {
        print("No incoming link")
        return
    }
    print("Link is: \(url)")
    SystemManager.sharedInstance.setDeepLinkTrip(tripKey: deepLinkParser(link: url))
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let initialViewController = storyboard.instantiateViewController(withIdentifier: "RootVC")
    self.window?.rootViewController = initialViewController
}

So how can I make it so that the link is properly opened when the app is starting up cold these days? Thanks for all help :)

EDIT: I have updated my app to use SceneDelegate, which all other answers suggested, but it STILL does not work. It will still open dynamic links if running in the background, but otherwise it will not open them. It doesn't look like any link is ever sent to the app. I can't find any userActivity, urlContexts, etc.

Heres new relevant code:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?

//I read that this function should be handling the link when it is clicked while the app is dead, but nothing works. Basically this checks that the user is logged in (always is), then looks for a link.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    self.scene(scene, openURLContexts: connectionOptions.urlContexts)
    
    guard let _ = (scene as? UIWindowScene) else { return }

    if Auth.auth().currentUser != nil {
        
        if let userActivity = connectionOptions.userActivities.first {
          self.scene(scene, continue: userActivity)
        } else {
          self.scene(scene, openURLContexts: connectionOptions.urlContexts)
        }
        
        if let userActivity = connectionOptions.userActivities.first {
            if let incomingURL = userActivity.webpageURL {
                _ = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
                    guard error == nil else { return }
                    if let dynamicLink = dynamicLink {
                        self.handleIncomingDynamicLink(dynamicLink)
                    }  else {
                       print("Something went wrong")
                       let storyboard = UIStoryboard(name: "Main", bundle: nil)
                       let initialViewController = storyboard.instantiateViewController(withIdentifier: "RootVC")
                       self.window?.rootViewController = initialViewController
                   }
                }
            }
        } else {

            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let initialViewController = storyboard.instantiateViewController(withIdentifier: "RootVC")
            self.window?.rootViewController = initialViewController
        }
    }
    
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        
    if let url = URLContexts.first?.url {
        _ = DynamicLinks.dynamicLinks().handleUniversalLink(url) { (dynamicLink, error) in
        guard error == nil else { return }
        if let dynamicLink = dynamicLink {
        //your code for handling the dynamic link goes here
            self.handleIncomingDynamicLink(dynamicLink)
            }
        }
    }
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    if let incomingURL = userActivity.webpageURL {
        
        _ = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
            guard error == nil else {
                print(error!.localizedDescription)
                return
            }
            if let dynamicLink = dynamicLink {
                self.handleIncomingDynamicLink(dynamicLink)
            } else {
                print("Soemthing went wrong")
            }
        }
    }
}

Solution

  • I figured out what was wrong. The issue was unrelated to SceneDelegate - the way that I handled the link was being overwritten by another network call.

    How I fixed this, since you cannot see print statements when opening an app from a cold start, is by saving a message to UserDefaults, and then creating a popup alert to read the saved message once the app loads.

    In the end, I did need to move to SceneDelegate over AppDelegate, though.