My first date with iOS Universal Links

Michael Barshinger
6 min readOct 13, 2015

--

Back in the old days of iOS 8, I could use some fancy JavaScript in my web app to create a hidden iFrame and use it to launch my iOS app. It was a handy way to drive users from my web app into my iOS app if it was installed. Apparently that was a security risk, so Apple put an end to it with iOS 9.

Along with the mayhem created by this unfortunate loss, iOS 9 came with an improvement named ‘Universal Links’. The idea with Universal Links is to allow users to click on a link and navigate directly to the app if it is installed but fallback to the web site if the app is not installed.

For example, if someone texts me a link to an item on Amazon’s web site and I have the Amazon app installed, it launches to show me the item instead of Safari launching the web page. What’s new about this is that I don’t have to ping pong through Safari to get to the app. So I set off to give Universal Links a go and this post is about some of the things I learned.

More information about Universal Links is available in the documentation on Apple’s Developer web site and there’s a video recording of a WWDC session that’s worth watching too.

Universal Links don’t work in the Simulator

I read in the comments on blog.branch.io, that Universal Links weren’t working with Xcode’s device simulator. So I focused my efforts on setting up Universal Links on my iPhone. After I got that working, I tried the Xcode’s device simulator. Unfotunately, I couldn’t get them working in the simulator. It doesn’t make sense, but this has been my experience.

Don’t sign the apple-app-site-association file

I read in numerous places that it was necessary to sign the apple-app-site-association file with an SSL Certificate. Not true for iOS 9. With iOS 8, this same file was used to enable handoff and iOS 8 required it to be signed but Apple realized this was a PITA and as of IOS 9 we don’t need to sign the file. Since I don’t care about iOS 8 devices, apple-app-site-association doesn’t need to be signed.

Serving apple-app-site-association from IIS

IIS only serves files of known types, defined by their file extension. Since apple-app-site-association doesn’t include a file extention, IIS throws a 404 error, when I try to open it with a browser. I fixed this by adding a mimeMap to c:\inetpub\wwwroot\web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<staticContent>
<!-- required for apple-app-site-association: -->
<mimeMap fileExtension="." mimeType="application/json" />
</staticContent>
</system.webServer>
</configuration>

Activity Continuation is required

The documentation shows a sample apple-app-site-association file like this:

{
"applinks": {
"apps": [],
"details": [{
"appID": "9JA89QQLNQ.com.apple.wwdc",
"paths": [ "/wwdc/news/", "/videos/wwdc/2015/*" ]
}]
}
}

I found that Universal Links won’t work unless I also include Activity Continuation properties like this:

{
"activitycontinuation": {
"apps": [
"9JA89QQLNQ.com.apple.wwdc"
]
},
"applinks": {
"apps": [],
"details": [{
"appID": "9JA89QQLNQ.com.apple.wwdc",
"paths": [ "/wwdc/news/", "/videos/wwdc/2015/*" ]
}]
}
}

Setting app capabilities in Xcode

The app needs to be configured to make an HTTPS request for the apple-app-site-association file. To do this we just launch Xcode, open the project, select it from the Navigator on the left, select the Capabilities tab and enable Associated Domains as shown here:

Note: I had to add entries for both activitycontinuation and applinks in order to get Universal Links working for my app.

Testing access to apple-app-site-association

During my troubleshooting, I discovered it’s best to verify an app is making the HTTPS request for the apple-app-site-association file. It’s important to know that apps only attempt to this once per installation. The request occurs the first time an app is launched after installation. Furthermore, force closing an app and then launching it will NOT trigger the app to reload apple-app-site-association.

The only evidence I have found that an app is trying to access an apple-app-site-association file is to take the file offline, reinstall the app and check the device log for an error.

Steps to verify app is requesting apple-app-site-association:

  1. Uninstall the app from my phone. This step is necessary to trigger the app to request the apple-app-site-association file.
  2. Rename apple-app-site-association to apple-app-site-association.bak on web server
  3. Open the app in Xcode
  4. Choose Window / Devices, then select my iPhone
  5. Expand the device log by clicking on the triangular button at the bottom of the screen
  6. Purge the device log by clicking on the trashcan
  7. Go back to Xcode and press play
  8. After the app launches, go back to the device log and press cmd+f to search ‘apple-app-site-assocation’. I’m expecting an error since we took the file offline in step 1. Now I know the app is trying to access the file.
  9. Rename apple-app-site-association.bak to apple-app-site-association
  10. Perform steps 1–7 again, this time the device log should not contain errors about the apple-app-site-association file

Testing Universal Links

Since my apple-app-site-association is ready for testing, I can now install and launch the app. It’s important to remember that any changes to the apple-app-site-association file, won’t be observed until I re-install the app.

At this point, I should be able to launch Safari and navigate to my website, and then pull down to reveal a banner build into Safari that says “Open in the <MyApp> app”. This is a good sign!

For a real time saver, I started saving links into the Notes app on my iPhone. From the Notes app, I can tap a link to my site to see if it is going to launch Safari or my app. I also noticed that when the app associates with my website, I can long-tap on a link in the Notes app to reveal a context menu that list several options including “Open in Safari” and “Open in <MyApp>”.

Dealing with sub-domains

Unfortunately, Apple’s design for website-to-app associations is currently flawed with regards dealing with multiple sub-domains. Consider a web app that users sub-domains to partition user access such as client1.myapp.com vs client2.myapp.com vs client3.myapp.com. I’d like to be able to associate *.myapp.com with my app, but as far as I can tell there is currently no way to do this. The only option is to explicity list every sub-domain in the Xcode project under Associated Domains. This is awful for to reasons:

  1. Every time a new client is provisioned, the Xcode project must be updated, and republished, and re-installed by the new client. Seriously?
  2. During the first launch after installation of my app, the apple-site-association-file will be requested for each sub-domain. This simply doesn’t scale. It might work for a dozen or even a hundred sub-domains, but what if I have thousands? Thousands of HTTPS requests for each sub-domain during the initial launch of my app — I don’t think so!

That pretty much sums up my first date with Universal Links. Since there really isn’t much of an alternative, it was more of a shotgun wedding than a date.

I’m hoping others will see this post and shed some light on some of the mysteries I encountered or commiserate with my frustrations.

Credit belongs to HOKO for the image I used in post.

Credit belongs to HOKO for the image I used in post.

--

--