11

When I designed my App Clip Launch experience, I had in mind that the App can only be triggered via QR code, NFC or App Clip Code. That why I linked the App Launch to a specific location with specific Id.

When my App went live last week, and when I try to scan a NFC tag the App is launching as expected every time.

Now, if I tap the App Clip icon on the home screen, the App is launching with the last URL scanned I dig some googling and I found that the App Clip is caching the last URL scanned and simulating a universal link launch when icon tapped!

This is not working for me! So I am looking for a way to check if the App was launched via scan or tap? I tried to log the App launch but it's always running in the order either via Scan (NFC) or icon tap:

AppDelegate.didFinishLaunchingWithOptions()
SceneDelegate.willConnectTo() // It's here where I am handling the Universal Link

How can I check if the user launched the App via Tap or Scan? Knowing that the App is always simulating Universal launch Link when icon tapped!

Or how I can look for the saved URL? I tried to fetch all UserDefaults and Some Keychain data, but I found nothing!

raed
  • 4,887
  • 4
  • 30
  • 49
  • What do mean triggering by `App Clip Code`? – Liaz Kamper Oct 11 '20 at 21:05
  • Have you considered adding a query param to the QR and NFC URLs that will indicate which URL came from which invocation? I can't think of another way – Liaz Kamper Oct 11 '20 at 21:06
  • @LiazKamper `App Clip Code` is the new QR code like created by Apple and presented during WWDC 2020, https://atadistance.net/2020/08/29/the-apple-pay-code-payment-app-clip-connection/ – raed Oct 12 '20 at 07:29
  • @LiazKamper That's exactly what I am doing, each QR code or NFC tag has its unique Id, and it's working fine when the user Scan QR code or NFC tag. The problem is once the App Clip has been installed the user cam launch it manually, hence the last QR code / NFC tag is cached and the App launch from developer point view will be like if the user has scanned a QR code / NFC tag :( – raed Oct 12 '20 at 07:32
  • Raed, you can tell if this is the first launch or consecutive launch. In you can use the AppGroup to save data, mark it as already launch, and launch the second time as you please. Does that work? – Liaz Kamper Oct 13 '20 at 08:20
  • 1
    Thanks @LiazKamper, but this will not work either, because the App launch experience is always the same, the App will always enter SceneDelegate.willConnectTo the same way. How do we check if the the N launch is the not a cached N-1? – raed Oct 13 '20 at 11:53
  • Facing exactly same problem!!! – Vinoth Kumar Jul 09 '21 at 18:59

1 Answers1

4

I faced the same issue! And unfortunately there’s no way to:

  • Check how the App was launched, icon tap or NFC/QR scan
  • To retrieve cached data from either UserDefaults or Keychain

Apple says clearly on their Human Interface Guidelines that if you want support multiple businesses you should add the location services factor!

Consider multiple businesses. An App Clip may power many different businesses or a business that has multiple locations. In both scenarios, people may end up using the App Clip for more than one business or location at a time. The App Clip must handle this use case and update its user interface accordingly. For example, consider a way to switch between recent businesses or locations within your App Clip, and verify the user’s location when they launch it.

So, now your tags for specific location should be mapped to a coordinates [Longitude, Latitude]. Apple has introduced a new location verification API just for App Clips that allows you to do a one-time check to see if the App Clip code, NFC tag or QR code that the user scanned is where it says it is.

Enable Your App Clip to Verify the User’s Location To enable your App Clip to verify the user’s location, modify your App Clip’s Info.plist file:

  1. Open your App Clip’s Info.plist, add the NSAppClip key, and set its type to Dictionary.
  2. Add an entry to the dictionary with NSAppClipRequestLocationConfirmation as the key, select Boolean as its type, and set its value to true.

But using App Clip Location services is different:

  1. Parse the information on the URL that launches the App CLip
  2. Send a request to your Database to fetch the location information for this business
  3. Use activity.appClipActivationPayload to confirm if the location (in Step 2) is in region where the user is right now.

The Code bellow (Copied from Apple) explains how to do it.

import UIKit
import AppClip
import CoreLocation

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    var window: UIWindow?
    
    // Call the verifyUserLocation(_:) function in all applicable life-cycle callbacks.

    func verifyUserLocation(_ activity: NSUserActivity?) {
        
        // Guard against faulty data.
        guard activity != nil else { return }
        guard activity!.activityType == NSUserActivityTypeBrowsingWeb else { return }
        guard let payload = activity!.appClipActivationPayload else { return }
        guard let incomingURL = activity?.webpageURL else { return }

        // Create a CLRegion object.
        guard let region = location(from: incomingURL) else {
            // Respond to parsing errors here.
            return
        }
        
        // Verify that the invocation happened at the expected location.
        payload.confirmAcquired(in: region) { (inRegion, error) in
            guard let confirmationError = error as? APActivationPayloadError else {
                if inRegion {
                    // The location of the NFC tag matches the user's location.
                } else {
                    // The location of the NFC tag doesn't match the records;
                    // for example, if someone moved the NFC tag.
                }
                return
            }
            
            if confirmationError.code == .doesNotMatch {
                // The scanned URL wasn't registered for the App Clip.
            } else {
                // The user denied location access, or the source of the
                // App Clip’s invocation wasn’t an NFC tag or visual code.
            }
        }
    }

    func location(from url:URL) -> CLRegion? {
        
        // You should retrieve the coordinates from your Database
        let coordinates = CLLocationCoordinate2D(latitude: 37.334722,
                                                 longitude: 122.008889)
        return CLCircularRegion(center: coordinates,
                                radius: 100,
                                identifier: "Apple Park")
    }
}

And that’s it, this his how your support multiple businesses with App Clip

  • 1
    Exactly, that's what Apple told me after reaching out to them. Thanks @Said – raed Oct 20 '20 at 07:18
  • We are seeing a prompt presented to user if they want to grant location permissions to the App Clip when we call payload.confirmedAcquired even though `NSAppClipRequestLocationConfirmation` is set to `true` in info.plist. We are not registering the business location with Apple since it would add significant overhead for us to register each location for each App Clip. Any suggestions to not prompt the user as my understanding is that location perms should be automatically granted when invocations happen via NFC/QR code scans. – whawhat Dec 30 '20 at 20:21