My app has its own Shortcuts actions created using Intents Extensions. They perform background actions perfectly.
For some actions, I'm trying to make the intent extension open the main (container) app when run in Shortcuts and perform a function.
I'm having trouble with NSUserActivity and I'm not sure if it's the fact it's a SwiftUI project or the way I'm implementing it (or both).
I have registered my NSUserActivity name as an NSUserActivityType in my info.plist ("com.me.project.activityName").
I've added the code below to my AppDelegate.
I initialise a new NSUserActivity inside my intent extension with the same type as the one declared in info.plist.
I've also tried declaring the activity within the app (I don't think I need to do this?)
I'm running: iOS (iPhone XS, Beta 6) macOS 10.15 Catalina (Beta 5) Xcode 11.0 (Beta 5)
I have this in my AppDelegate:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.activityType == "com.me.project.activityName" {
if let url = URL(string: "https://www.google.com") {
UIApplication.shared.open(url)
}
return true
}
return false
}
This is within my intent extension:
let openApp = intent.launchApp?.boolValue ?? false
if openApp {
let UA = NSUserActivity(activityType: "com.me.project.activityName")
UA.title = "Dummy title"
completion(UserActivityTestIntentResponse(code: .continueInApp, userActivity: UA))
} else {
completion(UserActivityTestIntentResponse.success(result: "You chose not to open the app with a user activity."))
}
In info.plist
<key>NSUserActivityTypes</key>
<array>
<string>com.me.project.activityName</string>
</array>
I have this declared in a swift file in my project (though I don't think I need it):
let openURLActivityType = "com.me.project.activityName"
let viewPageActivity: NSUserActivity = {
let userActivity = NSUserActivity(activityType: openURLActivityType)
userActivity.title = "Dummy Title"
userActivity.suggestedInvocationPhrase = "Dummy phrase"
userActivity.isEligibleForSearch = false
userActivity.isEligibleForPrediction = false
return userActivity
}()
I'm expecting that when the action is run in Shortcuts, my app opens and the website "https://www.google.com".
Currently, after running the action in Shortcuts, my app launches to the home screen and nothing else happens. No breakpoints appear to be hit in my appDelegate.
I can't work out if it's because I'm using NSUserActivity wrong, whether it's because it's SwiftUI or whether it's something that just won't work from inside an intent.
Thank you so much in advance for any help!
Like you already commented you can use func scene(_ scene: UIScene, continue userActivity: NSUserActivity)
to continue the NSUserActivity
when the app is still in the background.
However when the app is closed you can implement let userActvity = connectionOptions.userActivities.first
inside the scene(_:willConnectTo:options:)
method inside the SceneDelegate
to access the activity the user wants to continue.
Just adding this piece of code to the standard implementation of this method would look like this:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Use a UIHostingController as window root view controller
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: ContentView())
self.window = window
window.makeKeyAndVisible()
//Standard implementation until here
if let userActvity = connectionOptions.userActivities.first {
if let intent = userActivity.interaction?.intent as? YourIntent {
print(“do something”)
}
}
}
}
This works for Siri Intents with Swift 5 Xcode 11.
For Handoff though the .userActivities
should not be used as the documentation says, instead the associated delegate methods will be called (scene(_:continue:)
):
This property does not contain user activity objects related to Handoff. At connection time, UIKit delivers only the type of a Handoff interaction in the handoffUserActivityType property. Later, it calls additional methods of the delegate to deliver the NSUserActivity object itself.
If your application is a SwiftUI app, maybe you should consider to add something like:
ContentView
.onContinueUserActivity("com.company.app.activityIdentifier") { userActivity in
handleShortcut(with: userActivity)
}
where handleShortcut
is getting userInfos from the given NSUserActivity
and launching things to be done from this opening of your app
This replace any implementations made in the func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
delegate method that is not called anymore in your SwiftUI application unless you make a few more (and not trivial) lines of code to make it called
You can find more details on :
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With