Growth MarketingApp Development

iOS “Universal Links” with Urban Airship

chain links in foreground with lake and shoreline in the background

Recently I’ve been working on porting one of our premiere news apps to Urban Airship, and in the course of doing that I ran across something quite surprising. It turns out Urban Airship doesn’t natively support iOS Universal Links, at least not the way you’d expect.

If one were to quickly peruse the Apple Documentation on Universal Links, you’d quickly learn that it requires a server-side apple-app-site-association file and an implementation of application:continueUserActivity:restorationHandler: in your app delegate. After getting these two pieces in place, I was surprised to find that all my links were opening the app before quickly rerouting to Safari.

The catch lies in the way Urban Airship works – by swizzling a lot of your app’s methods. Turns out their current implementation routes your notification’s request straight to openURL instead of continueUserActivity which, per Apple’s documentation:

It’s important to understand that if your app uses openURL: to open a Universal Link to your website, the link does not open in your app. In this scenario, iOS recognizes that the call originates from your app and therefore should not be handled as a Universal Link by your app.

Oh no! What to do about this?

tl;dr:

Define an UAActionPredicate to override the default “OpenExternalURLAction” to check if the link you were passed is a Universal Link you’d like to handle. If so, pass it through to your deeplink handling code. Simply register this action after your UAirship.takeOff() call and you’re good to go! No apple-app-site-association file required at all.

  func registerURLAction() {

        let urlAction: UAActionPredicate = { [weak self] (args: UAActionArguments) -> Bool in
            // validate that we actually want to handle the data we were passed
            guard let strongSelf = self,
                let urlString = args.value as? String,
                let url = URL(string: urlString),
                let host = url.host,
                host.contains("myhosticareabout.com") else {
                return args.situation != UASituation.foregroundPush
            }
            let handled = strongSelf.handleDeepLink(url: url)
            return !handled
        }
        UAirship.shared().actionRegistry.updatePredicate(urlAction, forEntryWithName: kUAOpenExternalURLActionDefaultRegistryName)

    }

However, you should absolutely still have an apple-app-site-association file in place and working so that you can still open Universal Links from locations other than notifications, such as the web and iMessage.

All in all, I’m happy with how easy it is to bake-in your own version of Universal Links, but I was incredibly surprised when I couldn’t find this documented elsewhere. Hopefully this will help someone out there from struggling with the same level of confusion as I was.

braze LTR19

Braze LTR 2019 explores 'Humanity in Action'

Last week, Braze, a top engagement platform, hosted their annual Braze LTR conference...

Read the article