Actually making an app in swiftUI and trying to handle Siri intents to start a call in my app. I made a extension target in my project, added Siri capability and App groups in main and extension targets, my intent handler trigger the Siri request correctly at all, starting Siri and asking to make a call to some contact works perfectly, my apps gets launched and at this point is supposed to receive an activity from the intent, but nothing happen...
My intent handler looks like this:
import Intents
class IntentHandler: INExtension, INStartCallIntentHandling {
func handle(intent: INStartCallIntent, completion: #escaping (INStartCallIntentResponse) -> Void) {
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartCallIntent.self))
guard intent.contacts?.first?.personHandle?.value != nil else {
completion(INStartCallIntentResponse(code: .failureContactNotSupportedByApp, userActivity: userActivity))
return
}
let response = INStartCallIntentResponse(code: .continueInApp, userActivity: userActivity)
completion(response)
}
func resolveContacts(for intent: INStartCallIntent, with completion: #escaping ([INStartCallContactResolutionResult]) -> Void) {
var contactName = ""
if let contacts = intent.contacts {
contactName = contacts.first?.displayName ?? ""
}
//This shared method is used to get contact data for completion
DataManager.sharedManager.findContact(contactName: contactName, with: {
contacts in
switch contacts.count {
case 1: completion([.success(with: contacts.first ?? INPerson(personHandle: INPersonHandle(value: "1800-olakase", type: .phoneNumber), nameComponents: nil, displayName: "ola k ase", image: nil, contactIdentifier: nil, customIdentifier: INPersonHandle(value: "1800-olakase", type: .phoneNumber).value))])
case 2...Int.max: completion([.disambiguation(with: contacts)])
default: completion([.unsupported()])
}
})
}
func confirm(intent: INStartCallIntent, completion: #escaping (INStartCallIntentResponse) -> Void) {
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartCallIntent.self))
let response = INStartCallIntentResponse(code: .ready, userActivity: userActivity)
completion(response)
}
}
Added INStartCallIntent to IntentsSupported in Info.plist
So, when the code in func handle(intent: INStartCallIntent, completion: #escaping (INStartCallIntentResponse) -> Void) did complete is supposed to send the NSUserActivity to my app delegate directly to func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool ... but is not triggering that function. At the moment my app can't make new calls because is not getting any userActivity to retrieve contact data.
Also I try with func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool but is not working too.
To being more specific I follow this tutorial but changing the
INStartAudioCallIntent for INStartCallIntent because is deprecated. I don't know if swiftUI is the problem or not, I used #UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate to add my app delegate to the swiftUI life cicle
And yes, my app has request Siri authorization and enabled. Any suggestion? I'm missing something?
Ok, I figured it out: The problem was that I was trying to get the NSUserActivity from the method func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool from my AppDelegate that never gets triggered, forget about that and don't follow the documentation from apple if you are using SwiftUI because is not working anymore.
For SwiftUI you must implement .onContinueUserActivity() modifier to fetch the NSUserActivity, and from here you can do whatever you need to do. Example code:
WindowGroup {
ContentView().onContinueUserActivity(NSStringFromClass(INStartCallIntent.self), perform: { userActivity in
//do something
})
}
Related
How do you configure your app to open from safari after it has already been downloaded? In the screenshot below when clicking "Open" it opens the app in the App Store, even after the app is downloaded.
I've implemented continue userActivity in the appDelegate class:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let url = userActivity.webpageURL {
self.continueWithLink(url: url)
}
return true
}
What else do I need to do to make it function properly?
I am implementing CallKit in swift and I'm facing a problem with NSUserActivity while making a call directly from the recent log.
While tapping on my app entry in the recent log, my app is launching but any method of AppDelegate is not calling.
I have turned on Siri from application capabilities and have added NSUserActivityType in info.plist. I've added INStartAudioCallIntent and INStartVideoCallIntent inside NSUserActivityType. The method I've implemented inside AppDelegate class is the following:
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
print("Restoration")
return true
}
When tapping on any entry of my app from the recent log the following line is printed in the debugger console.
AppDelegate-BAA416CD-ED84-4161-A054-B2192AFAD47A application:continueUserActivity:restorationHandler:] has an interaction attached but it is not handled
Change the signature of the function, i.e. the restorationHandler parameter type from ([Any]?) -> Void to ([UIUserActivityRestoring]?) -> Void
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
//if its a call
guard let handle = userActivity.startCallHandle else {
print("Could not determine start call handle from user activity: \(userActivity)")
return false
}
}
For more details:
https://github.com/Lax/Learn-iOS-Swift-by-Examples/blob/master/Speakerbox/Speakerbox/AppDelegate.swift
I changed the signature and it worked for me.
I have successfully integrated Firebase dynamic links and when I click on dynamic link then my app is opening.
The issues I'm facing is after opening app from dynamic links, continue userActivity: method should be called, but nothing happens.
I've checked the all the possible thing but didn't recognised the issue.
I've searched the SO for this but none of the answer helped me.
My Code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
GIDSignIn.sharedInstance().clientID = kGoogleSignInClientId
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
// DynamicLinks.performDiagnostics(completion: nil)
FirebaseApp.configure()
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if url.absoluteString.contains(kFBAppId) {
return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, options: options)
}
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
print(dynamicLink.url ?? URL(string: "test") as Any)
return true
}
return GIDSignIn.sharedInstance().handle(url, sourceApplication: options[.sourceApplication] as? String, annotation: options[.annotation])
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
//This method is not getting called
}
Additional answer for those using separate SceneDelegate.swift apart from AppDelegate.swift:
This method in AppDelegate >
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.activityType == CSSearchableItemActionType {
}
is now in SceneDelegate >
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
}
I don't know whether they keep their doc. up to date or not.
I have just copy-pasted the code from the Google's official Firebase dynamic link document.
Why was the continue userActivity: method is not called?
The reason is (See the difference in following method)
Copy pasted from google doc. - Wrong one
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
}
I wrote this (without copy paste from google doc.) - Correct one
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
}
I've made bold the difference.
This is what I was trying for many hours. It is really very frustrating for me to blindly trust on google doc.:-|
Hope this may help other.
You need to check two times.
When app. is running in the background and is opening from Link:
Delegate method is:func checkForTransferedTicket(_ userActivity: NSUserActivity) { }
When app. is NOT running in background and is opening from Link:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,options connectionOptions: UIScene.ConnectionOptions) { if let userActivity = connectionOptions.userActivities.first {
print(userActivity)
}
}
I am using both NSUserActivity and Core Spotlight to index content on my app.
The reason I am using Core Spotlight is because I want to index this content before the user access (opens) it.
The problem I am facing is in the AppDelegate method:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool
Basically userActivity ONLY contains the correct information when I do this in my viewController:
userActivity = myUserActivity
But it does not work if I do:
CSSearchableIndex.default().indexSearchableItems(searchableItems).
By using the second method (Core Spotlight) I can see all my results in spotlight search, but when I tap the item, I don't have any information in the AppDelegate method.
The worst part is this:
po userActivity.activityType
"com.apple.corespotlightitem"
If I print the activityType, instead of getting my own, I get this one...
Any suggestions?
When your app is launched from a CoreSpotlight result you get a CSSearchableItemActionType.
You need to handle this type of action by retrieving the CSSearchableItemActivityIdentifier - This value will match the identifier you provided for your searchable item when you submitted it to the index.
Something like:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
if userActivity.activityType == CSSearchableItemActionType {
guard let selectedItem = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String else {
return
}
// Do something with selectedItem
}
}
I am trying to setup Firebase Dynamic Links in my iOS project using Swift 2.3.
When I add this function in the AppDelegate (as reported at the bottom of this page), I get the error:
Unknown attribute 'escaping'
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
guard let dynamicLinks = FIRDynamicLinks.dynamicLinks() else {
return false
}
let handled = dynamicLinks.handleUniversalLink(userActivity.webpageURL!) {
(dynamiclink, error) in
// ...
}
return handled
}
any idea which is the correct syntax for Swift 2.3?
The method which you are using is for swift3, here is the method for swift2.3
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
}
if you want to add restriction on deep link then implement bellow method like this
this delegate method call first.
func application(application: UIApplication, willContinueUserActivityWithType userActivityType: String) -> Bool {
return userActivityType == NSUserActivityTypeBrowsingWeb ? true : false
}
if you want to link which user have click or if you have multiple deep link in single app then want to identify then you can get like this.
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool{
// pass the url to the handle deep link call
print(userActivity.webpageURL)
//NSURLComponents
return true
}