Phone numbers detected using NSDataDetector could not be opened using openURL

1000 Views Asked by At

I use NSDataDetector to detect phone numbers like this:

func matchesFor(type: NSTextCheckingResult.CheckingType) -> [String] {
    
    do {
        
        let nsstring = self as NSString
        let detector = try NSDataDetector(types: type.rawValue)
        let matches = detector.matches(in: self, options: [], range: NSRange(location: 0, length: nsstring.length))
        
        return matches.map { nsstring.substring(with: $0.range) }
        
    } catch {
        return []
    }
}

and it finds a numbers. But then I try to open that numbers like this:

func makeACall(phoneNumber: String) {
    
    if let url = URL(string: "tel://\(phoneNumber)"), UIApplication.shared.canOpenURL(url) {
        UIApplication.shared.openURL(url)
    }
}

and it doesn't work. Why?

The example I mean is:

+48 576-786-987

Should I do anything with that number to use it in order to call?

2

There are 2 best solutions below

1
Yun CHEN On BEST ANSWER

Remove the space, this should work: +48576-786-987

0
Martin R On

As Yun CHEN said, a space is an invalid character in the phone URL.

If you use URLComponents() instead of URL(string:) then all characters are automatically escaped where necessary. Example:

let phoneNumber = "+48 576-786-987"

var urlcomps = URLComponents()
urlcomps.scheme = "tel"
urlcomps.host = phoneNumber

if let url = urlcomps.url, UIApplication.shared.canOpenURL(url) {
    print("Calling:", url.absoluteString) // Calling: tel://+48%20576-786-987
    UIApplication.shared.openURL(url)
}

Note also that NSTextCheckingResult has an optional phoneNumber property which is set when phone numbers are detected. Therefore you can simplify the code slightly to

extension String {
    func phoneNumbers() -> [String] {

        let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
        let matches = detector.matches(in: self, range: NSRange(location: 0, length: utf16.count))
        return matches.flatMap { $0.phoneNumber }
    }
}

NSDataDetector(types:) can only fail for an invalid type, which would be a programming error. Therefore a forced try is acceptable here.