Martian Chronicles
Evil Martians’ team blog
iOS

An invitation system using URL Schemes and Universal Links

Our experience in making an invitation system on iOS using URL Schemes and lately introduced Universal Links.

The first release

It is the time to start promotions, aiming to get featured on the App Store.

At the launch, it is seldom clear how the application will perform with live users. There is no problem worse than an unexpected one, therefore, we do all kinds of testing to ensure everything will go as planned.

An invitation system

Invite Only

An invitation system is just the tool you need to prevent such problems and make better decisions based on the actual user context. Also, the invitation system covers not less than three aspects:

  1. It makes possible to limit the swarm of new users.

  2. A “Not for everybody” experience can attract new customers since people love to feel involved in exclusive, special things.

  3. There is an opportunity to analyze the application performance, and, in so doing, to improve the user experience and fix hidden issues, while the number of users is still small.

Using an URL scheme approach

An invite letter illustration

It is awkward and annoying to type an invitation code via a virtual keyboard. A copy-paste procedure is not any better.

Invitation codes must not be entered manually. Why should an ordinary user know how the invitation code looks like or if it exists at all?

So, we have decided to make something better.

When a user is sent an invitation via our application, that person gets an email with the how-to instruction. Step-by-step, it explains how to download the app from the App Store, and, after it has been installed, to tap the activation link to make use of the invitation.

To use the invitation, the only thing the user has to do is just to perform a few taps.

It’s quite simple on the code-side as well.

First of all, we have to configure Info.plist. Let’s make the system aware that we want to open the app via, for example, marsmap scheme.

URL Types

We use JLRoutes. It is a well-designed advanced URL routing/parsing library with a block-based callback API.

To handle URL scheme calls, we implement the following protocol method for UIApplicationDelegate.

func application(application: UIApplication,
                 openURL url: NSURL,
           sourceApplication: String?,
                  annotation: AnyObject) -> Bool {

                    return JLRoutes.routeURL(url)
}

Next, we add a new route. It looks like the following:

JLRoutes.addRoute("/user/invite/activate/:invite_code") {

  [weak self] (parameters) -> Bool in

  if let inviteCode = parameters["invite_code"] as? String {

    // here we do things

    return true   
  }

  return false
}

Gmail strips unusual URL schemes

Custom URL schemes will work fine in Apple Mail and almost any other application. However, email clients such as Gmail or Inbox strip unusual URL schemes for some reason.

People do use Gmail a lot. Therefore, our invite letters don’t contain any URL schemes. Instead, we use the regular https scheme. Clicking the activation link will open our landing site and immediately forward the user to marsmap.

So, here is some advice: don’t use custom URL schemes in email letters. Google email clients strip out custom schemes from emails.

Two reasons to make an invitation system disableable

First, at some moment, the application will have to be available for everybody. We don’t want to go through the review process again, make a user download and install a new version of the application simply to make it available. Such shift should not take longer than an instant.

The second reason is Apple. Let’s take a look at an App Store Review Guidelines, statement 2.9:

2.9. Apps that are "demo", "trial", or "test" versions will be rejected. Beta Apps may only be submitted through TestFlight and must follow the TestFlight guidelines.

We know that some App Store reviewers occasionally apply that statement to reject apps with invitation systems. Does the statement relate to the situation with our application? Surely not.

Our application is a fully functional product, although we do want to limit access to it. In fact, App Store contains an enormous amount of applications available for download but not available for everybody’s use.

Anyway, it’s pretty easy to appeal the rejection of an app in such situation. However, our choice is to be ready to enable or disable our invitation system whenever necessary.

At the WWDC event, held on June 2015, Apple introduced a deep-linking feature named Universal Links. Users can finally tap the link to a website and get seamlessly redirected to the installed app without Safari being opened up.

To adopt Universal Links, we have to create and upload the apple-app-site-association file to our web server. JSON should contain information about the links that the application can handle.

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "TeamID.BundleID",
                "paths": [ "/invites/*" ]
            }
        ]
    }
}

Next, we update the project capabilities. In the Associated Domains section, list the application domains and prefix them with applinks.

Associated Domains section

To handle our website URL calls and redirect them to the application, we implement another UIApplicationDelegate method.

func application(application: UIApplication,
continueUserActivity userActivity: NSUserActivity,
               restorationHandler: ([AnyObject]?) -> Void) -> Bool {

        return JLRoutes.routeURL(userActivity.webpageURL)
}

Next, we add the new route in the same manner as in the example above.

JLRoutes.addRoute("/invites/:invite_code") { ... }

Universal Links are extremely useful, as they allow opening an installed application right away without using Safari.

However, in this particular case, we cannot fully rely on them because:

  • The feature is only available on the latest iOS.
  • Also, ​it only works after the first application run is done and when the application has downloaded the apple-app-site-association file from the web service.

The reality is that there are many other ways of making an invitation system. It is quite natural that you may prefer another one.

Besides that, I hope it was interesting for you to read about my experiment.