8

I want to use SiriKit to start a workout. Starting the workout requires opening the main app from the app extension.

The boilerplate that Apple provides for the INStartWorkoutIntentHandling handler is

func handle(startWorkout startWorkoutIntent: INStartWorkoutIntent, completion: (INStartWorkoutIntentResponse) -> Void) {
    let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartWorkoutIntent))
    let response = INStartWorkoutIntentResponse(code: .success, userActivity: userActivity)
    completion(response)
}

How can I open my own app from here? Something like myapp://workout?action=start&name=pushups This answer doesn't seem relevant, as I don't have a UIViewController with a extensionContext property for this extension type.

Last related bit: For the other actions (pause, end) I’d prefer to not open the main app, but to simply pause the workout which is running in the main app. I could use a similar custom URL to pause it, but that would open up the app which is an extra unnecessary step. Any good way to tell the main app to take a specific action from the INExtension without opening the app?

Community
  • 1
  • 1
Tyler Sheaffer
  • 1,953
  • 1
  • 16
  • 16
  • Apple has defined [`failureRequiringAppLaunch`](https://developer.apple.com/reference/intents/instartworkoutintentresponsecode) response code, which almost implies that this is not a valid use-case from Apple's perspective. Seems unreasonable to require the app extension to re-implement the core use-case of my app (e.g. workouts involve more than just audio). I'd like to have users able to say "Siri, start a 10 minute upper body workout from MY-APP" using my custom vocabulary, and it would just start the workout in the app. – Tyler Sheaffer Jul 23 '16 at 03:08

2 Answers2

3

For me I was able to launch app like so:

let activity  = NSUserActivity(activityType: NSUserActivityTypeBrowsingWeb)
activity.webpageURL = URL(string: "https://mywebsite/...")        
completion(MyIntentResponse(code: .continueInApp, userActivity: activity))

Then this will get called in the AppDelegate

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
        if let url = userActivity.webpageURL {
            handleDeeplink(url)
        }
    }
    return false
}
MendyK
  • 1,643
  • 1
  • 17
  • 30
2

For posterity: turns out this was a phase-in of this functionality between Xcode 8 betas, it's been resolved in Xcode 8 beta 3. They added the .continueInApp code to INStartWorkoutIntentResponseCode in this version , but it wasn't there in Xcode 8 beta 2. This status code allows for the direct passing of NSUserActivity (no need to use a URL scheme).

Tyler Sheaffer
  • 1,953
  • 1
  • 16
  • 16
  • By the way, if you intention is to have the user select the app, you don't need to go to the app to start. you can do it through Siri – Ace Green Sep 04 '16 at 23:41
  • Ended up doing .continueInApp because I want to show the workout with my ads – Ace Green Sep 05 '16 at 00:25
  • what to do if i want to open app from RideIntentExtension Handler ? I cant find .continueInApp type in rideIntentExtension – Ashish P Apr 27 '18 at 05:12
  • @AshishPisey Did you find a way to open main app without using continueInApp? – Bubu Nov 05 '18 at 17:40