Deep link into apps with Hotwire Native and universal links (iOS)

- Name
- Dennis Paagman
- @djfpaagman
By default all external links in your Hotwire Native app will open in a Safari modal. This is great for most cases, but it’s also very nice to directly open links in a specific app, for example, when linking to a location on Google Maps, or an Instagram post.
This is where universal links come in. They are just standard https links that you can also open in the browser, but if the user has the app installed, the system will open the link directly in the app.
When users tap or click a universal link, the system redirects the link directly to your app without routing through Safari or your website. In addition, because universal links are standard HTTP or HTTPS links, one URL works for both your website and your app. If the user has not installed your app, the system opens the URL in Safari, allowing your website to handle it.
Hotwire Native
Fortunately, Hotwire Native offers some flexibility on how to deal with links, and with a little bit of code we can open links that have a the corresponding app installed in their app, and open the rest in a Safari modal.
Implement handle(externalURL:) to customize the behavior when an external URL is visited. URLs are considered “external” if they do not match the same domain as the first visited link. By default, this will present a SFSafariViewController modally.
- Open links through the system (
.openViaSystem
). - Open links in a Safari modal (
.openViaSafariController
), the default. - Do nothing (
.reject
), which is not very useful on it’s own, but we will use later.
The first option works well with universal links, they open in their app as expected. But if you don’t have the app installed (or there is no app at all), those links will now be opened in the Safari app, no longer in a modal.
Instead of using one of the options above, we can also write a little bit of custom code and have the best of both worlds.
In your SceneController
(or where you extend NavigatorDelegate
) you can define a handle
function that tells the Navigator how to handle external URLs. We will call the open
function (like Hotwire itself does when set to openViaSystem
), but with a custom option to only allow universal links.
The nice part is that this method has a ‘completion handler’ that will tell us if the URL was opened successfully. If it was, we know the system opened the link in the app that handles it and we’re done. If not, we will open the link in a Safari modal.
Finally we return .reject
to tell the Delegate to do nothing with the external URL anymore, since we’ve handled everything ourselves.
func handle(externalURL: URL) -> ExternalURLNavigationAction {
UIApplication.shared.open(externalURL, options: [.universalLinksOnly: true]) { success in
if !success {
// no app to handle the link, open in a modal
self.navigator.open(externalURL: externalURL, .openViaSafariController)
}
}
// link will be handled, Hotwire itself doesn't need to do anything anymore
return .reject
}
This way your users will have the best user experience for all links in your app. If a link has a corresponding app installed, that will be used. If not, the link will open in a modal Safari screen in your app.