Deprecated: Return type of I::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/i.php on line 62

Deprecated: Return type of I::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/i.php on line 91

Deprecated: Return type of I::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/i.php on line 71

Deprecated: Return type of I::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/i.php on line 101

Deprecated: Return type of I::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/i.php on line 53

Deprecated: Return type of Collection::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/public/kirby/toolkit/lib/collection.php on line 80

Deprecated: parse_str(): Passing null to parameter #1 ($string) of type string is deprecated in /home/public/kirby/toolkit/lib/url.php on line 135
One Tap Less | Late Thoughts on iOS 9 and x‑callback‑url

Late Thoughts on iOS 9 and x‑callback‑url


Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /home/public/kirby/toolkit/lib/str.php on line 506

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /home/public/kirby/toolkit/lib/str.php on line 506

Warning: Trying to access array offset on value of type null in /home/public/kirby/vendors/parsedownextra.php on line 305

Deprecated: substr(): Passing null to parameter #2 ($offset) of type int is deprecated in /home/public/kirby/vendors/parsedownextra.php on line 305

Warning: Trying to access array offset on value of type null in /home/public/kirby/vendors/parsedownextra.php on line 305

Deprecated: substr(): Passing null to parameter #2 ($offset) of type int is deprecated in /home/public/kirby/vendors/parsedownextra.php on line 305

Two years ago was probably the first time I heard of x‑callback‑url. It was the most remarkable, at least, with an article on MacStories in which Viticci chained 4 apps. He swiftly moved information between them, starting with a bookmarklet in Safari and bouncing into Drafts, then Due and returning to Safari afterwards. Seeing what an empowered iOS user could achieve mesmerized me.

Fast-forward to the present and Apple is, in many's opinion, dooming x‑callback‑url with its newest approach to URLs. Doom-mongers should have arrived sooner, though, since most of measures Apple took that could knock x‑callback‑url off were implemented in iOS 8 with Extensions. I predicted that a native alternative would appeal to developers and cause the decline of x‑callback‑url implementations in new apps.

Maintaining the x‑callback‑url Library has been my front row ticket to this downturn, as the number of new apps with x‑callback‑url support drastically decreased in the past year. Meanwhile, Workflow ascended as the de facto automation app and the landscape gained new contours.

The State of Extensions

I'm a longstanding supporter of apps as utilities, claiming that we cannot have a rich environment of app interactions without apps that serve. Extensions brought the conditions needed for them to blossom and assist with such tasks as taking a screenshot of a webpage, building a clipboard history, opening content in its respective app1 and the countless possibilities brought by Workflow.

1Password and Workflow extensions changed how I use iOS completely, but aside from a few others I use sporadically2, extensions remain clumsy. Prior to iOS 8, Jared Sinclair released a library called OvershareKit to overcome the iOS share sheet.

OvershareKit on the left—image from documentation on Github; iOS 8 share sheet on the right—image from MacStories.

The share sheet on iOS continues to clutter one third of its space to promote a feature we don't use3 and the criteria that forks the other rows blurred over time; when sharing becomes an action, and vice-versa. The overwhelming amount of sharing extensions available compared to action extensions reflect the ravenousness for your content in the App Store and how action extensions are still neglected despite the popularity of 1Password's and Workflow's.

Even if extensions do not cover all demands and we still appeal to crass url schemes, soon they'll be the primary way to exchange information among apps on iOS. Apple has been clear in its WWDC presentations:

"Many iOS apps implement what's called a custom URL scheme. These are a very effective tool, because they let apps communicate with each other but they do have a few pitfalls. First off, they don't always map to the right app [...]. Second, if your app is not installed, they fall flat. [...]. And, finally, they make protecting user's privacy difficult."
—Jonathan Grynspan, Seamless Linking to Your App

I doubt you were ever affected by the first complaint and the second is burdensome to tackle indeed, yet if you read between the lines, Apple's problem lays on the last item and how url schemes were embezzled by Twitter, and maybe other apps, to collect data on apps a user downloads. This lead Apple to restrict the use of canOpenUrl, a method to verify if an url, in this case an app's url scheme, is valid, indicating the app is installed.

The canOpenUrl Controversy

Apple announced in the Privacy and Your App presentation that iOS 9 would restrict canOpenUrl calls to 50 distinct schemes for apps. The conversation escalated after a post by Greg Pierce, the developer behind Drafts and creator of the x‑callback‑url spec, denounced that the limit was also applied to openURL calls, a method required to, drums roll, open URLs. However, this suspicion is now discredited as a bug on the first iOS 9 beta by independent confirmation from several sources, according to Greg's article.

The deterrent of the canOpenUrl method is still a setback to automation apps, as Greg points out:

Even if that is the case, loss of the ability to call "canOpenURL" on arbitrary URLs will limit the user experience on many automation applications of URLs because an app has no way of testing if the URL can be opened successfully and will have to rely on the system to report errors.

Remember the second problem listed by Grynspan? Developers employ the canOpenUrl method to raise an error if the linked app is absent from the device—or if the url somehow fails. Apple's regulation inhibits apps from failing gracefully and also debars a feature launcher apps implemented to aid action construction: the Installed Apps tab, a list of available apps with known url schemes to shorten action composition.

The limit of 50 `canOpenUrl` calls is a double-edged sword.

I believe apps like Launch Center Pro will shake this blow off at the cost of user experience, yet this obstacle reverberated among developers . For example, Craig Pearlman from Black Fog Interactive announced he would cease development of Schemes, his app to build url actions with a drag and drop interface, to focus on the forthcoming TextTool 2 release4.

Universal Links

Apple's recommendation to replace url schemes are universal links. These are your regular http urls, but connected to apps through a signed certificate. For example, with universal links, if you click on a link to a tweet in Messages, it opens in the Twitter app if installed or Safari otherwise; in the upper-left corner, a discreet "Back to Messages" button takes you back to the original app.

Among the problems mentioned at WWDC, universal links provides a fallback by opening the link in Safari and axes the invasive app sniffing. In the upcoming months, this feature may encourage developers to expose their apps in a web layer, thus releasing users from platform lockdown.

Universal links fit a world in which 70% of the time the average user spends within apps goes to their three most-frequently-used apps. If x‑callback‑url liberated the user to bounce across apps, universal links are a one-way street that holds the user in the source app. Once a user settles with an app as core part of their experience5, other apps become just extra features, reached through extensions and now universal links. The irony is that Apple doesn't have an app known to retain users' attention and I contemplate how it benefits from this app as a temple aftermath6.

Long live x‑callback‑url

Despite my concerns on how these changes will affect the indie ecosystem, universal links are the proper course towards an integrated iOS. The WWDC announcements were the groundwork for a promising future and reinforced the synthesis between apps and the OS. There's still room for improvement regarding communication among apps as little occurred since the disclosure of extensions in iOS 8.

The x‑callback‑url downfall is inevitable; apps will circumvent the canOpenUrl limitation whenever required and continue to maintain the framework. Yet I can't believe upcoming apps will support x‑callback‑url, as resources would be better invested into an extension or a web alternative.

Universal links are capable of everything url schemes do because developers can access all parameters submitted with the url. Nothing impedes a Javascript framework from emerging and emulating x‑callback‑url's behavior on web fallbacks to universal links. iOS 9 will preemptively suppress privacy concerns and, hopefully, prepare us for access authorization across apps, broadening the CoreSpotlight API (responsible to fuel Spotlight with data from any app) beyond the OS.

One can dream at least.


  1. Opener will either be doomed by universal links or save us from them. 

  2. I mentioned Awesome Screenshot, Clips and Opener previously, but also Command-C (beta), Instashare and Blink 

  3. AirDrop doesn't work most of the time but is a remarkable idea. 

  4. If you have interest in beta-testing TextTool 2, fill this form

  5. I doubt you match that criteria, nevertheless I bet some of your friends are behind a single app most of the time, be it Facebook, WhatsApp, Twitter, Pinterest or whatever. 

  6. I also suspect universal links may harm third-party clients, a foreseeable scenario when you consider Tweetbot and other Twitter clients.