Handling tel: links in voip app - ios

Is there any method in iOS (CallKit? perhaps) where a VoIP app can register to handle tel: links? That way when a user selects a phone number (in safari for instance). They would be presented with two options to complete the call.

This is supported in iOS these days if you press and hold on a tel: link. It doesn't use the standard URI scheme system, though. CallKit seems to automatically register your app as a handler of tel: links if you declare support for phone calls, and the link is passed through the following event:
import Intents
protocol SupportedStartCallIntent {
var contacts: [INPerson]? { get }
}
extension INStartAudioCallIntent: SupportedStartCallIntent {}
extension INStartVideoCallIntent: SupportedStartCallIntent {}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CXProviderDelegate {
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
let interaction = userActivity.interaction
let startCallIntent = interaction?.intent as? SupportedStartCallIntent
if let contact = startCallIntent?.contacts?.first?.displayName {
// do what you want with 'contact'
}
return true
}

That capability does not exist in iOS today. If you are interested in that, I recommend filing a bug report to request it on Apple's Bug Report website.

Related

iOS universal links not entering in UIApplicationDelegate callback

I'm trying to use universal links to be detected in a callback in an app developed in SwiftUI. I think all the settings are ok, including the AASA file, capability in the app with applinks: join-domain.com. When I tap in the link https://join-domain.com/something in the notes app it will open my app so I assume is detecting the domain but it never enters in any callback of the appDelegate.
Inside the app I have the following:
import SwiftUI
#main
struct XApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
and in AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
print("did it entered here?")
}
}
I run through stackoverflow, nothing worked. In this one thread it mentions the 'Application Scene Manifest' and configurationForConnectingSceneSession. I have nothing of that.
Any ideas?

How to integrate Siri into Flutter with MethodChannels?

I want to integrate Sirikit into my flutter application. Therefore I have to establish a MethodChannel for communication between the host and the client. I want the iOS-side to invoke a flutter function and that response be Siris answer.
This is the flutter Side:
void nativeFunc() {
const platform = const MethodChannel("flutter.siri");
Future<dynamic> _handleMethod(MethodCall call) async {
if (call.method == "message") {
return api_request("Physics", call.arguments, 50);
}
}
platform.setMethodCallHandler(_handleMethod);
}
Then I have to specify the methodChannel on the iOS-side:
//AppDelegate.swift
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name:"flutter.siri")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
//IntentHandler.swift
func handle(intent: INSendMessageIntent, completion: #escaping (INSendMessageIntentResponse) -> Void) {
// Implement your application logic to send a message here.
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
let response = methodChannel.invokeMethod()//this should invoke the MethodChannel-function from Flutter
completion(response)
}
I am no Ios-developer so I have no clue how to actually do this. Right now the problem is that the IntentHandler.swift-File doesn't have access to the method channel data because it was declared in another file. How can my Intenthandler-file call the flutter method and respond with Siri?
I was facing a similar issue and I was able to make it work.
The problem is that Siri intents are in a different Target because they can run in the background if needed and because of this your communication using Method channels would be really complicated to implement (if possible).
My approach was to use the flutter extension HomeWidget
https://pub.dev/packages/home_widget
Since Home widgets also use a different target and This extension opens a communication channel using App groups and UserDefaults we could use the same communication channel to send data to our Siri Intent.
Just follow the configuration guide of the HomeWidget extension and add AppGroups capabilities to your runner Target and also to your Siri intent.
make sure you use the same group ID in all of them including on the flutter side:
HomeWidget.setAppGroupId('YOUR_GROUP_ID');
Then you can use the extension methods to send and receive data between flutter and swift.

iOS Universal Link opens app, does not trigger app delegate methods

I am trying to enable universal links on iOS, (as part of Firebase's password-less sign-up). Testing locally on iOS 13.2.
The apple-app-site-associated (AASA) JSON looks as such (https://lokitools.page.link/apple-app-site-association):
{"applinks":{"apps":[],"details":[{"appID":"43S54AHEMG.com.jkalash.Loki","paths":["NOT /_/*","/*"]}]}}
Universal links do open the app, however I am unable to handle the app opening from them. Delegate methods:
application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
do not get called, when opening from universal links. Tried both apps running in the background and force closed. AASA validator (https://branch.io/resources/aasa-validator/) says file looks good, and I have tried troubleshooting by re-installing app and observing console logs for swcd (https://ios13.dev/universal-links-debugging-on-ios-13-cjwsux93w001p6ws1swtstmzc) but nothing out of the ordinary shows up and it does look like the AASA file was downloaded.
I have also tried following Apple's troubleshooting guide (https://developer.apple.com/library/archive/qa/qa1916/_index.html) but the final step which fails (step 8) does not cover my case which is the app does open (iOS detects universal links), but the delegate methods just don't get called.
Turns out this is not a universal links specific problem, but a change in iOS 13's way of triggering app lifecycle events. Instead of coming through UIApplicationDelegate, they come through UISceneDelegate.
One confusing thing is that the app delegate methods aren't deprecated so you won't get a warning if you have both app delegate and scene delegate methods in place but only one will be called.
Refer to App delegate methods aren't being called in iOS 13 for a comprehensive answer
I am using iOS 13 with Swift 5, replace the application (: continue: restorationHandler :) method of the AppDelegate.swift file and add the scene (: continue :) method to the SceneDelgate.swift file
In my case in the SceneDelegate.swift file add the following:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let urlToOpen = userActivity.webpageURL else {
return
}
handleURL(urlToOpen)
}
Since you are able to open the app, I think all is good with your AASA file. The following delegate method gets called fine in my case:
func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return false
}
let urlString = url.absoluteString
var queryParams: [String: String?] = [:]
if let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
let params = components.queryItems {
for param in params {
queryParams[param.name] = param.value
}
}
return true
}
Hope it helps!
If you use Google Analytics, please refer to my here. The issue may be caused by method swizzling.

URL Opening Swift App - Open Works - Called Function Does NOT work

Hello All – I am a newbie here ... trying to get my first iOS Swift (Xcode 11.2.1 / Swift 5 / iOS 13.2) app to open via URL and process the URL string. The app opens just fine, but the function (method?) does not appear to be getting called. Here's what I've got:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print("Here I iz ... in the URL responding bit.")
print(url)
return true
}
...
That code is in the AppDelegate.swift file in my project.
And that is what I have in my Info.plist file.
I launch via Safari both on-device and in the simulator with confirmevent://HelloWorld
As I said ... The app is opening, but I do not see any results from my print statements in the Xcode debug area.
In searching other posts they said that I need to use the "Wait for executable to be launched" to attach Xcode to the app, which I have done and it is indeed attaching. BUT I notice that none of my dozens of print statements that I have scattered about in my app appear when either when opening via "wait for executable to be launched" option.
Any/All help would be appreciated. I've spent over 5 hours scouring the web, but all indications are that is should "just work"
I just found a solution here: application(...continue userActivity...) method not called in ios 13
The trick is to also implement the SceneDelegate.swift functions for Apps with iOS > 13. This function should be called if you open the URL confirmevent://HelloWorld:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
print(URLContexts.debugDescription)
}
WindowGroup {
SampleView()
.onOpenURL { url in
//this url that was opened by your app
}
}
}
you need to use this function in your appDelegate
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let incomingURL = userActivity.webpageURL {
print(incomingURL)
}
return false
}

How do I know if app was launched via Firebase-Deeplink (Dynamic Links) at AppDelegate's didFinishLaunchingWithOptions

We are adding Firebase-Deeplinks to our IOS-project, so that the app can be started via deeplink.
The deeplink-feature itself work fine so far, and so does the default app launch routine. But making both startRoutines work side by side gives me some headache.
What I am trying to achieve get's obvious looking at this code snippet.
func application(_:didFinishLaunchingWithOptions:) {
FirebaseApp.configure()
if "deeplink" {
return true
}
defaultAppLaunch() // no deeplink
return true
}
If there is a deeplink one of these appDelegate-functions is called:
func application(:continueUserActivity:restorationHandler:) {
handleDeeplink()
return true
}
func application(:openURL:options:) {
handleDeeplink()
return true
}
So how do I know at application(_:didFinishLaunchingWithOptions:) if I can call defaultAppLaunch()?
I know there is the launchOptions-Argument in but in my case it is always nil, at least when running the app via XCode. And also the Firebase-Documentation says nothing about launchOptions to be set by Firebase-Deeplinks.
Help is highly appreciated.
TL;DR
You can't know that your app was opened using deeplinks through App Delegate DidFinishLaunching.
Explaination:
App delegate did finish launch is always called, regardless if app was opened normally or via deeplinks. so you can't know through app delegate
Instead, you can know that app was opened through deeplinks if the following delegate function is called.
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
// Handle the deep link. For example, show the deep-linked content or
// apply a promotional offer to the user's account.
// ...
return true
}
return false
}
and you should handle the deeplinks functionality in the same function
I'm referencing the Firebase docs in handling dynamic links for iOS:
Firebase docs for receiving dynamic links
Next, in the application:continueUserActivity:restorationHandler:
method, handle links received as Universal Links when the app is
already installed (on iOS 9 and newer):
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
// ...
}
return handled
}
Finally, in the application:openURL:sourceApplication:annotation: (iOS
8 and older) and application:openURL:options: (iOS 9 and up) methods,
handle links received through your app's custom URL scheme. These
methods are called when your app receives a link on iOS 8 and older,
and when your app is opened for the first time after installation on
any version of iOS.
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
return application(app, open: url,
sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String,
annotation: "")
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
// Handle the deep link. For example, show the deep-linked content or
// apply a promotional offer to the user's account.
// ...
return true
}
return false
}
But you did mention that the app is currently only being run on Xcode (and I'm guessing iOS Simulator, maybe you can try it on a test device too!)

Resources