How do I trigger SceneDelegate method scene:continue: in main app with app clip url prefix?

1.3k Views Asked by At

I'm currently developing an App Clip and I'm having trouble triggering the func scene(_ scene: UIScene, continue userActivity: NSUserActivity) sceneDelegate method in my main app target. I was able able to test the App Clip by setting the _XCAppClipURL environmental variable in my app clip target. I tried installing both main and app clip targets on a physical device, setup local experience with my app clip's BUNDLE ID & URL PREFIX, but only the app clip launches. How do I test the user experience of app clip if it launches my main app?

2

There are 2 best solutions below

2
On

Try checking the func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) instead of the continue userActivity that you mentioned.

I had to do that inside the Clip's SceneDelegate too.

You can extract the NSUserActivity like this if you need to modify the experience based on the Clip:

if let activity = connectionOptions.userActivities.filter({ $0.activityType == NSUserActivityTypeBrowsingWeb }).first {
  // do something with your activity... for example
  guard
    activity.activityType == NSUserActivityTypeBrowsingWeb,
    let incomingUrl = activity.webpageURL,
    let components = NSURLComponents(url: incomingUrl, resolvingAgainstBaseURL: true)
  else { return }
}
0
On

This is a limitation in App Clip apple for some reason didn't describe or emphasize in their docs.

Let's consider this scenario:

  1. User scans QR code and install and runs App Clip.
  2. User decides to install the full app based on the App Clip Card reference or the App Clip reference.
  3. Full app opens

We would expect the invocation URL will be passed into the full app, BUT IT DOES NOT HAPPEN. The poor user is forced to scan the QR code, and then the full app is opened using a Universal Link flow.

The App Clip is opened using in both cases

  1. When the App Clip is not already installed on the device, using:
   func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        // Get URL components from the incoming user activity
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let incomingURL = userActivity.webpageURL,
              let components = NSURLComponents(url: incomingURL,
              resolvingAgainstBaseURL: true)
        else {
            return
        }
              
        // log url
        print("AppClip invocation url is : \(incomingURL)") 
    }
  1. App Clip already installed on the device. The user won't see a difference, but there is a difference in the scene life-cycle:
   func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else { return }
        
        // Get URL components from the incoming user activity.
        guard let userActivity = connectionOptions.userActivities.first,
            userActivity.activityType == NSUserActivityTypeBrowsingWeb,
            let incomingURL = userActivity.webpageURL,
            let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true)
        else {
            return
        }
                
        // log url
        print("AppClip invocation url is : \(incomingURL)")
    }

We solved the issue for AppsFlyer users by allowing them to use our OneLink flow for deferred deep linking