App Clips for iOS: Getting Started

In this tutorial, you’ll learn how to design and implement App Clips. By Graham Connolly.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Setting up Location Confirmation

Along with App Clips, Apple introduced the Location Confirmation API. This framework provides enough information to verify that the invoked App Clip is at the expected location. The Location Confirmation API works by comparing the App Clip’s activation payload with the user’s location.

Note: You need a device running at least iOS 14 to test the Location Confirmation API. On the simulator you’ll just see an error message in the console.

In SwiftyLemonade, you’ll disable the option to place an order if you are not at the correct location. To prepare for this, open SwiftyLemonadeClipModel.swift and add the following property:

@Published var paymentAllowed = true

This property determines whether the user can order lemonade.

To set up location confirmation, open the Info.plist of the App Clip. Click the disclosure triangle next to the App Clip key to reveal the Requests location confirmation key. Change its value to YES:

Request location confirmation

Next, open SwiftyLemonadeClipApp.swift and, under import CoreLocation, add the following code:

import AppClip

This gives you access to the App Clip payload information to verify the user’s location.

Now, add the following at the bottom of handleUserActivity(_:) in SwiftyLemonadeClipApp.swift:

//1
guard let payload = userActivity.appClipActivationPayload else {
  return
}

//2
let region = CLCircularRegion(
  center: location, 
  radius: 500,
  identifier: "stand_location"
)

//3
payload.confirmAcquired(in: region) { inRegion, error in
  //4
  guard error == nil else {
    print(String(describing: error?.localizedDescription))
    return
  }

  //5
  DispatchQueue.main.async {
    model.paymentAllowed = inRegion
  }
}

This code:

  1. Gets the payload information from launching the App Clip. If it doesn’t exist, stop execution.
  2. Creates a region using the location found in the URL with a circular boundary of 500 meters. Core Location uses SI units for distance. If you’re not used to those units, a meter is just more than a yard.
  3. Checks whether the App Clip is activated within region
  4. If there’s an error, log it to the console for debugging.
  5. inRegion indicates whether the App Clip was invoked in the correct location. Use this value to enable or disable payments.
Note: If you’d like to learn about the App Clips Activation payload, check out Apple’s Documentation on APActivationPayload.

Using Custom Flags

Next, disable the ability to place an order if the user isn’t at the expected location. Open DetailView.swift, found in the Views group under SwiftyLemonade. This view allows you to order lemonade. Add the following code:

@EnvironmentObject private var model: SwiftyLemonadeClipModel

This code gives DetailView.swift access to the App Clip’s model. But this model is not available in the SwiftyLemonade target. If you select this scheme and try to build your app, you see the following error:

Cannot find type 'SwiftyLemonadeClipModel' in scope

To solve this, wrap this code in a conditional, using a Swift Compilation Flag. Open the Build Settings of your App Clip target and add the custom flag APPCLIP to both the Debug and Release schemes:

Adding custom flags

Back in DetailView.swift, wrap model in a conditional using the custom flag:

#if APPCLIP
@EnvironmentObject private var model: SwiftyLemonadeClipModel
#endif

Now, the code within the conditional will compile only when the App Clip scheme is selected. Build the app and see the errors disappear!

Next, the App Clip should display an alert that payment is disabled. To do this, add a property outside of the conditional:

@State private var showWarningAlert = false

This property determines whether to show the warning alert.

Disabling Ordering

Next, inside placeOrder(), add the following code before orderPlaced = true:

//1
#if APPCLIP
//2
guard model.paymentAllowed else {
  //3
  showWarningAlert = true
  return
}
#endif

This code:

  1. Executes the code inside the conditional only if the custom flag exists in the scheme.
  2. Checks if paymentAllowed is true. This means the App Clip can place an order.
  3. Sets showWarningAlert to true if payment is not allowed, and the rest of the code in placeOrder() is not executed.

Showing an Alert

To show the alert when placeOrder() gets called, add the following code inside body after the closing brace of the sheet view modifier:

//1
.alert(isPresented: $showWarningAlert) {
//2
  Alert(
    title: Text("Payment Disabled"),
    message: Text("The QR was scanned at an invalid location."),
    dismissButton: .default(Text("OK"))
  )
}

This code:

  1. Presents an alert if showWarningAlert is set to true
  2. Configures the alert to have a title, message and dismiss button. This alert warns the user that payment is not allowed.

One more step before you can test this out. Unless you live within 500 meters of Dignity Health Sports Park, the home of the LA Galaxy, you’ll need to simulate your location on a device. This allows you to place an order for lemonade without being anywhere near Swifty’s Lemonade Stand.

Simulating Location

To simulate being at the LA Galaxy stadium, create a GPX File in the SwiftLemonadeClip group and name it LaGalaxy.gpx. Be sure to select the SwiftLemonadeClip target:

Adding a GPX file

Open LaGalaxy.gpx and replace its contents with the following:

<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
    <wpt lat="33.8644" lon="-118.2611">
        <name>Dignity Health Sports Park</name>
        <time>2014-09-24T14:55:37Z</time>
    </wpt>
</gpx>

The code you added represents the GPS coordinates of Dignity Health Sports Park.

Putting it all Together

Finally, to test each scenario, you must set a default location when building and running the app. To do this, you must edit the scheme for the App Clip and set the default location.

First, test the error flow where you are not at the expected location. To set a default location, select the SwiftyLemonadeClip scheme and then Edit Scheme:

Selecting default location as London

It’s time to check out this beautiful error alert you added. Build and run the app and try to place an order:

Payment disabled

Next it’s time to simulate being in L.A. Go back and edit the scheme and set the default location to the GPX file you created earlier:

Setting location as L.A.

Now, with the stadium’s GPS coordinates set in your device, you should be able to order some lemonade. Build and run:

Successful order

Congratulations! You’ve used the Location Confirmation API to verify the user’s location and prevent any misplaced orders.

Wouldn’t it be great if you could get notified when lemonade is ready? That way, you could go watch the game without missing any of the action. Never fear when ephemeral notifications are here!