Swift
iOS Development
Phone Call
Swift Programming
Mobile App Development

Calling a phone number in swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Calling a phone number from an iOS app is technically simple, but the user experience and device constraints matter more than the one-line API call. The action should be user-initiated, the number should be sanitized, and the app should handle devices that cannot place calls. A safe implementation combines tel: URLs with validation and graceful fallback.

The Core Mechanism

iOS uses the tel: URL scheme for phone calls. You build a URL, ask UIApplication whether it can be opened, and then open it.

swift
1import UIKit
2
3func callNumber(_ phoneNumber: String) {
4    let digits = phoneNumber.filter { $0.isNumber || $0 == "+" }
5    guard let url = URL(string: "tel:\(digits)") else {
6        print("Invalid phone number")
7        return
8    }
9
10    guard UIApplication.shared.canOpenURL(url) else {
11        print("This device cannot place calls")
12        return
13    }
14
15    UIApplication.shared.open(url)
16}

This works on real iPhones with calling capability. It will not place a call on the simulator.

Sanitize the Input

Phone numbers often come from contacts, CMS content, or user input, so they may contain spaces, parentheses, or dashes. Removing formatting before building the URL avoids failed calls.

swift
1func normalizedPhoneNumber(from raw: String) -> String {
2    raw.filter { $0.isNumber || $0 == "+" }
3}
4
5print(normalizedPhoneNumber(from: "(555) 123-4567"))

If the data source is inconsistent, normalization should happen in one helper rather than repeated ad hoc in buttons.

Let the User Confirm the Action

Phone calls should feel intentional. A confirmation alert is often a better experience than immediately jumping to the Phone app.

swift
1func presentCallPrompt(on viewController: UIViewController, phoneNumber: String) {
2    let alert = UIAlertController(
3        title: "Call",
4        message: phoneNumber,
5        preferredStyle: .alert
6    )
7
8    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
9    alert.addAction(UIAlertAction(title: "Call", style: .default) { _ in
10        callNumber(phoneNumber)
11    })
12
13    viewController.present(alert, animated: true)
14}

This is especially useful when the UI contains several tappable contact actions close together.

Handle Unsupported Devices

Not every Apple device can place a call. iPads without cellular calling, simulators, and some managed environments will fail canOpenURL.

That means your UI should handle failure cleanly:

  • disable the call button when call capability is unavailable
  • show the number so users can copy it
  • offer alternative actions such as message or email

Treat calling as a feature that may not exist, not a guaranteed capability.

SwiftUI Bridge Example

If your app is SwiftUI-based, you can still use the same URL scheme through openURL.

swift
1import SwiftUI
2
3struct CallButton: View {
4    @Environment(\.openURL) private var openURL
5    let phoneNumber: String
6
7    var body: some View {
8        Button("Call Support") {
9            let digits = phoneNumber.filter { $0.isNumber || $0 == "+" }
10            if let url = URL(string: "tel:\(digits)") {
11                openURL(url)
12            }
13        }
14    }
15}

The logic is the same. The only change is the UI framework.

Testing the Behavior

Testing should cover:

  1. number normalization
  2. unsupported-device handling
  3. alert presentation flow

A small unit test for normalization is easy and worthwhile:

swift
1import XCTest
2
3final class PhoneNumberTests: XCTestCase {
4    func testNormalization() {
5        XCTAssertEqual(normalizedPhoneNumber(from: "(555) 123-4567"), "5551234567")
6    }
7}

You do not need to automate an actual phone call. You need to automate the decision logic around it.

Common Pitfalls

  • Building a tel: URL from uncleaned text such as spaces and punctuation.
  • Assuming the simulator or every iPad can place calls.
  • Triggering a call without clear user intent or confirmation.
  • Forgetting to check canOpenURL before calling open.
  • Duplicating phone-number cleanup logic across multiple screens.

Summary

  • Use the tel: URL scheme to start a phone call from Swift.
  • Normalize phone numbers before building the URL.
  • Check device capability with canOpenURL.
  • Prefer a confirmation step for better UX.
  • Test the sanitization and fallback logic even if the real call stays manual.

Course illustration
Course illustration

All Rights Reserved.