I've implemented spotlight index for iOS/macOS both shows the items in the Spotlight search.
To handle the tap, there is a dedicated method for iOS
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
...
}
but it seems like that method is not available for macOS.
I've read the documentation unfortunately there is no explanation about it.
My goal is to handle the click of spotlight search item for a macOS app in AppDelegate.
Note: The app is native Appkit based app.
Related
I'm using Firebase's deep linking to try and provide a certain function in my app when a user clicks a link that was sent to them. The deep link is setup properly on the Firebase web portal.
Clicking the link sent to the user DOES open my app, but does not trigger the continue userActivity method in my App Delegate, as none of the code contained in there is every executed.
I've tried the solution suggested in this StackOverflow post but no success, that's switching [UIUserActivityRestoring] to [Any] in the method declaration.
In Xcode, I have setup the associated domain to match what I set on Firebase: applinks:myappname.page.link; and I have added a "URL type" with identifier "Bundle ID", and URL scheme of ca.mycompany.myappname, with role editor.
All this is running on-device, of course, as I don't expect this to work in the simulator.
This is the method in my app delegate which should be called, however is not.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
print ("The link worked")
}
I made sure didFinishLaunchingWithOptions returns true always as well.
I expect the "The link worked" to actually print in debugging console, but it does not. Breakpoints indicate the method isn't being called at all, as the breakpoints are never reached.
There is a good change that somebody facing this problem deals with iOS13 / SwiftUI, too. Just like me.
I have found this article which solved all my problems.
Basically you have to be aware that some methods from the new SceneDelegate replace what was called in AppDelegate before iOS 13. Additionally there seem to be edge cases where methods from the AppDelegate still might be needed to handle deeplinks processing.
For anyone who needs it:
you need to use the below code to handle deep links from the link to the app that is already installed(other func application are for different things)
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
// ...
}
return handled
}
https://firebase.google.com/docs/dynamic-links/ios/receive #6
For scene application try to add your logic as part of
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
//...
}
}
I'm computing a NSUserActivity for when I view a specific screen in my app. (Doesn't matter what, imagine a Location)
I set a lot of information about this activity/location using the contentAttributeSet.
When I visit this screen over and over, I set the viewController's userActivity property to this derived activity, and also call becomeCurrent() on it.
Eventually Siri will suggest that shortcut in Spotlight. As expected and desired. I tap on that, it launches my app and calls:
func application( _ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
however, the .contentAttributeSet property will be nil.
Why? Have I not understood something here? I guess any data I need to access later should be in the userInfo dictionary? That works (as long as I don't set webpageURL)
I have set a universal link that's correctly opening my app when I tap on it, however I tried it when the app is not in background. The app gets opened through application: didFinishLaunchingWithOptions, but I don't see the URL anywhere in the options dictionary. So what should I do ?
Thanks for your help
Ok I asked that question too quickly, I finally fetched it in AppDelegate in:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool
Contained in userActivity.webpageURL.
I have enabled Universal Links in my app. The corresponding delegate call to handle those links is
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
if canHandle(userAcitivity) {
// Handle the universal link.
}
else {
// ⛔️ Don't handle the universal link.
return false
}
}
No I wonder what exactly happens when I return false from this method. In the beginning I thought that Safari would simply open the link instead as it would without universal links enabled. However, I figured that my app is still opened and the documentation states:
If you do not implement this method or if your implementation returns false, iOS tries to create a document for your app to open using a URL.
What exactly does this mean?
What kind of document is created and how is my app notified about that?
Actually, for continueUserActivity the description of the return value is:
Returns true to indicate that your app handled the activity or false to let iOS know that your app did not handle the activity.
If you return YES from this function the OS will understand that no further processing of the NSUserActivity will be required - your app has done everything that needs to be done. If you return NO from this function, the OS will understand that an activity requiring OS processing may have occurred and may need to be handled.
You can get more background on all this in Apple's Handoff docs, here: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html#//apple_ref/doc/uid/TP40014338
The Swift 3 converter changed this (perfectly functioning) line:
func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
to this:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
but both produce the warning
Instance method 'application(:handleActionWithIdentifier:for:completionHandler:)' nearly matches optional requirement 'application(:handleActionWithIdentifier:for:completionHandler:)' of protocol 'UIApplicationDelegate'
and offer the solution of making the function private, or adding #nonobjc.
Whether the function is left with the warning, reverted to the Swift 2 syntax, or fixed in either suggested way, launching the app with a shortcut item does not trigger it.
This is not listed as a known issue here either. Does anybody have an idea?
The signature for that method is now:
optional func application(_ application: UIApplication,
performActionFor shortcutItem: UIApplicationShortcutItem,
completionHandler: #escaping (Bool) -> Void)
Note the completion handler is now #escaping, per SE-103 (Make non-escaping closures the default). This attribute changes the type signature of the closure parameter, which in turn changes the type signature of the method it's an argument to, so method with the old declaration won't be called.
In general, the compiler warnings/fixits aren't so great for catching all type signature changes, especially between betas. Your best bet is to return to the SDK header (or rather, the Swift interface generated from it) or the documentation on Apple's site / in Xcode for the class/protocol that defines a problem method so you can see what its new definition is.
Apple introduced the #escaping tag to the Swift 3 Beta 6.
All closures now are by default no escaping, so if you want a closure that escapes, you need to give that tag. For some reason swift translator did not add this tag, but according to documentation in the link below, you need this tag added before the closure.
https://developer.apple.com/reference/uikit/uiapplicationdelegate/1622935-application
Adding the closure to my code removed the warning:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler:#escaping (Bool) -> Void)
I did not test it, so it might just removed the warning for some other reason.