How to make phone call in iOS 10 using Swift?
Solution 1
You can call like this:
if let url = URL(string: "tel://\(number)") {
UIApplication.shared.openURL(url)
}
For Swift 3+, you can use like
guard let number = URL(string: "tel://" + number) else { return }
UIApplication.shared.open(number)
OR
UIApplication.shared.open(number, options: [:], completionHandler: nil)
Make sure you've scrubbed your phone number string to remove any instances of (
, )
, -
, or space
.
Solution 2
Task
Make a call with phone number validation
Details
Tested on:
- Swift 5.2, Xcode 11.4 (11E146)
Solution
// MARK: DataDetector
class DataDetector {
private class func _find(all type: NSTextCheckingResult.CheckingType,
in string: String, iterationClosure: (String) -> Bool) {
guard let detector = try? NSDataDetector(types: type.rawValue) else { return }
let range = NSRange(string.startIndex ..< string.endIndex, in: string)
let matches = detector.matches(in: string, options: [], range: range)
loop: for match in matches {
for i in 0 ..< match.numberOfRanges {
let nsrange = match.range(at: i)
let startIndex = string.index(string.startIndex, offsetBy: nsrange.lowerBound)
let endIndex = string.index(string.startIndex, offsetBy: nsrange.upperBound)
let range = startIndex..<endIndex
guard iterationClosure(String(string[range])) else { break loop }
}
}
}
class func find(all type: NSTextCheckingResult.CheckingType, in string: String) -> [String] {
var results = [String]()
_find(all: type, in: string) {
results.append($0)
return true
}
return results
}
class func first(type: NSTextCheckingResult.CheckingType, in string: String) -> String? {
var result: String?
_find(all: type, in: string) {
result = $0
return false
}
return result
}
}
// MARK: PhoneNumber
struct PhoneNumber {
private(set) var number: String
init?(extractFrom string: String) {
guard let phoneNumber = PhoneNumber.first(in: string) else { return nil }
self = phoneNumber
}
private init (string: String) { self.number = string }
func makeACall() {
guard let url = URL(string: "tel://\(number.onlyDigits())"),
UIApplication.shared.canOpenURL(url) else { return }
if #available(iOS 10, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
static func extractAll(from string: String) -> [PhoneNumber] {
DataDetector.find(all: .phoneNumber, in: string)
.compactMap { PhoneNumber(string: $0) }
}
static func first(in string: String) -> PhoneNumber? {
guard let phoneNumberString = DataDetector.first(type: .phoneNumber, in: string) else { return nil }
return PhoneNumber(string: phoneNumberString)
}
}
extension PhoneNumber: CustomStringConvertible { var description: String { number } }
// MARK: String extension
extension String {
// MARK: Get remove all characters exept numbers
func onlyDigits() -> String {
let filtredUnicodeScalars = unicodeScalars.filter { CharacterSet.decimalDigits.contains($0) }
return String(String.UnicodeScalarView(filtredUnicodeScalars))
}
var detectedPhoneNumbers: [PhoneNumber] { PhoneNumber.extractAll(from: self) }
var detectedFirstPhoneNumber: PhoneNumber? { PhoneNumber.first(in: self) }
}
Usage
PhoneNumber(extractFrom: "+1-(800)-123-4567")?.makeACall()
PhoneNumber.extractAll(from: "+1-(800)-123-4567 bla bla 1(617)111-22-33").last?.makeACall()
PhoneNumber.first(in: "+1-(800)-123-4567 bla bla 1(617)111-22-33")?.makeACall()
"+1-(800)-123-4567 bla bla 1(617)111-22-33".detectedPhoneNumbers[1].makeACall()
"+1-(800)-123-4567 bla bla 1(617)111-22-33".detectedFirstPhoneNumber?.makeACall()
Full sample
do not forget to paste the solution code here
func test() {
isPhone("blabla")
isPhone("+1(222)333-44-55")
isPhone("+42 555.123.4567")
isPhone("+1-(800)-123-4567")
isPhone("+7 555 1234567")
isPhone("+7(926)1234567")
isPhone("(926) 1234567")
isPhone("+79261234567")
isPhone("926 1234567")
isPhone("9261234567")
isPhone("1234567")
isPhone("123-4567")
isPhone("123-89-01")
isPhone("495 1234567")
isPhone("469 123 45 67")
isPhone("8 (926) 1234567")
isPhone("89261234567")
isPhone("926.123.4567")
isPhone("415-555-1234")
isPhone("650-555-2345")
isPhone("(416)555-3456")
isPhone("202 555 4567")
isPhone("4035555678")
isPhone(" 1 416 555 9292")
isPhone("1(617)111-22-33!")
isPhone("+44 1838 300284")
isPhone("+44 1838 300284, 1 416 555 9292")
isPhone("+44 1838 3d0384, 1 416 555 9292!")
}
private func isPhone(_ string: String) {
let phoneNumbers = PhoneNumber.extractAll(from: string)
let result = !phoneNumbers.isEmpty
print("\(result ? "✅" : "❌") \(string) | detected phones: \(phoneNumbers)")
}
Result
❌ blabla | detected phones: []
✅ +1(222)333-44-55 | detected phones: [+1(222)333-44-55]
✅ +42 555.123.4567 | detected phones: [555.123.4567]
✅ +1-(800)-123-4567 | detected phones: [+1-(800)-123-4567]
✅ +7 555 1234567 | detected phones: [+7 555 1234567]
✅ +7(926)1234567 | detected phones: [+7(926)1234567]
✅ (926) 1234567 | detected phones: [(926) 1234567]
✅ +79261234567 | detected phones: [+79261234567]
✅ 926 1234567 | detected phones: [926 1234567]
✅ 9261234567 | detected phones: [9261234567]
✅ 1234567 | detected phones: [1234567]
✅ 123-4567 | detected phones: [123-4567]
✅ 123-89-01 | detected phones: [123-89-01]
✅ 495 1234567 | detected phones: [495 1234567]
✅ 469 123 45 67 | detected phones: [469 123 45 67]
✅ 8 (926) 1234567 | detected phones: [8 (926) 1234567]
✅ 89261234567 | detected phones: [89261234567]
✅ 926.123.4567 | detected phones: [926.123.4567]
✅ 415-555-1234 | detected phones: [415-555-1234]
✅ 650-555-2345 | detected phones: [650-555-2345]
✅ (416)555-3456 | detected phones: [(416)555-3456]
✅ 202 555 4567 | detected phones: [202 555 4567]
✅ 4035555678 | detected phones: [4035555678]
✅ 1 416 555 9292 | detected phones: [1 416 555 9292]
✅ 1(617)111-22-33! | detected phones: [1(617)111-22-33]
✅ +44 1838 300284 | detected phones: [+44 1838 300284]
✅ +44 1838 300284, 1 416 555 9292 | detected phones: [+44 1838 300284, 1 416 555 9292]
✅ +44 1838 3d0384, 1 416 555 9292! | detected phones: [1 416 555 9292]
Solution 3
In Swift 4.2
func dialNumber(number : String) {
if let url = URL(string: "tel://\(number)"),
UIApplication.shared.canOpenURL(url) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:], completionHandler:nil)
} else {
UIApplication.shared.openURL(url)
}
} else {
// add error message here
}
}
Call this like below
dialNumber(number: "+921111111222")
Hope this help.
Solution 4
Updated for Swift 3:
used below simple lines of code, if you want to make a phone call:
// function defination:
func makeAPhoneCall() {
let url: NSURL = URL(string: "TEL://1234567890")! as NSURL
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}
// function call: [Used anywhere in your code]
self.makeAPhoneCall()
Note: Please run the app on a real device because it won't work on the simulator.
Solution 5
By mistake my answer was misplaced, please checkout this one: You can use this:
guard let url = URL(string: "tel://\(yourNumber)") else {
return //be safe
}
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
We need to check whether we're on iOS 10 or later As 'openURL' was deprecated in iOS 10.0
user3175707
Updated on May 11, 2020Comments
-
user3175707 almost 4 years
I want my app to be able to call a certain number when a button is clicked. I've tried to google it but there doesn't seem to have one for iOS 10 so far (where openURL is gone). Can someone put an example for me on how to do so? For instance like:
@IBAction func callPoliceButton(_ sender: UIButton) { // Call the local Police department }
-
rmaddy over 7 yearsThe
openURL
method is deprecated in iOS 10. The OP is asking what the replacement is. -
Paolo almost 7 years
options
andcompletionHandler
have default values so you can actually just doUIApplication.shared.open(number)
-
Parth Adroja almost 7 years@Paolo Yes that's true.
-
Dilip Tiwari over 6 yearswhat be the number in above @ParthAdroja
-
Parth Adroja over 6 years@DilipTiwari Number will be String.
-
Dilip Tiwari over 6 yearsWill it be empty right @ParthAdroja
-
Parth Adroja over 6 years@DilipTiwari No it wouldn't be empty. It will be like "tel://+911111111"
-
Dilip Tiwari over 6 yearsok i got it @ParthAdroja
-
Dilip Tiwari over 6 yearsi can also pass string from json to this telephone string @ParthAdroja
-
Parth Adroja over 6 years@DilipTiwari Yes
-
Dilip Tiwari over 6 yearsthanks @ParthAdroja
-
bhakti123 almost 6 yearsA better implementation.
-
Eric Aya over 5 yearsThis has already been posted many times...
-
Muhammad Ehsan Mirzaei about 5 yearsit's does not consider the 0 in first position
-
Srdjan about 5 yearsIs there a way to get notified when the call has ended?
-
paul_f almost 5 yearsI walked straight into upvoting with the fancy answer and bright colours/emojis... and then... ❌ +44 1838 300284 | 441838300284 | [not a phone number]. This is not working for me and returns false for everything
-
Vasily Bodnarchuk almost 5 years@paul_f did you tried to run the code on sample? Is is not working too?
-
paul_f almost 5 yearsTest works fine, whatever it is about my test case it does not work at all: "+44 1838 300284" for example. I think the spacing of the numbers is the issue. It's a common spacing here.
-
Vasily Bodnarchuk almost 5 years@paul_f check the answer. I updated the code
-
Jabbar over 4 years@VasilyBodnarchuk I actually wanted to upvote the answer but accidentally hit on the downvote button. 😥
-
Vasily Bodnarchuk over 4 years@Jabbar thank you for the comment) because downvote for me means that something wrong with my code and I have to check it again. Glad to help!
-
Jabbar over 4 years@VasilyBodnarchuk No, there is nothing wrong with the code. It works perfectly. I just accidentally hit the downvote button.
-
Sivabalaa Jothibose about 4 years@VasilyBodnarchuk, "phone:+1(617)111-22-33!".makeACall() is not working for me in Xcode 11.4, Can you help me out.
-
Vasily Bodnarchuk about 4 years@SivabalaaJothibose Hello there! Did you tried to simulate the code on a real device?
-
Sivabalaa Jothibose about 4 years@VasilyBodnarchuk Hi, In Real device.
guard isValid(regex: .phone)
is givingfalse
. -
Vasily Bodnarchuk about 4 years@SivabalaaJothibose try again. I updated the code