如何在iOS 10中使用Swift拨打电话?

100
我希望我的应用程序在点击按钮时能够拨打特定的电话号码。我尝试过在Google上搜索,但似乎没有适用于iOS 10的方法(其中openURL已经不存在)。有人可以给我提供一个示例,告诉我如何做到这一点吗?例如:
@IBAction func callPoliceButton(_ sender: UIButton) {
    // Call the local Police department
}

谢谢!我尝试了完全相同的代码,但当我将google.com更改为"tel://120390129391824812988238197"时,当我单击按钮时什么也没发生。 我漏了什么吗? - user3175707
我本来期望它会弹出一个窗口,问:“要拨打120390129391824812988238197吗?” - user3175707
6个回答

184
你可以这样调用:

你可以这样调用:

 if let url = URL(string: "tel://\(number)") {
     UIApplication.shared.openURL(url)
 }

对于Swift 3+,你可以这样使用

guard let number = URL(string: "tel://" + number) else { return }
UIApplication.shared.open(number)

或者

UIApplication.shared.open(number, options: [:], completionHandler: nil)

请确保您已经清理了电话号码字符串,以删除任何 ()-空格


1
openURL方法在iOS 10中已被弃用。楼主正在询问替代方法是什么。 - rmaddy
4
optionscompletionHandler 有默认值,所以你实际上只需要执行 UIApplication.shared.open(number) 就可以了。 - Paolo
以上@ParthAdroja中的数字是多少? - Dilip Tiwari
@DilipTiwari 数字将会被视为字符串。 - Parth Adroja
有没有一种方法可以在通话结束时收到通知? - Srdjan
显示剩余7条评论

89

任务

进行带有电话号码验证的电话呼叫。

详情

测试环境:

  • Swift 5.2, Xcode 11.4 (11E146)

解决方案

// 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) }
}

使用方法

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()

完整示例

不要忘记在此处粘贴解决方案代码

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)")
}

结果

 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]

@VasilyBodnarchuk 我其实想点赞这个回答,但不小心点到了踩的按钮。 - Jabbar
@Jabbar 谢谢您的评论) 因为对我来说,downvote 意味着我的代码有问题,我必须再次检查它。很高兴能够帮忙! - Vasily Bodnarchuk
@VasilyBodnarchuk 不,代码没有任何问题。它完美地工作着。我只是不小心按了踩按钮。 - Jabbar
@VasilyBodnarchuk,"phone:+1(617)111-22-33!".makeACall()在Xcode 11.4中对我不起作用,你能帮我解决吗? - Sivabalaa Jothibose
1
@SivabalaaJothibose 请再试一次。我已经更新了代码。 - Vasily Bodnarchuk
显示剩余6条评论

23

在 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 
   }
}

请按照以下方式进行调用

dialNumber(number: "+921111111222")
希望这有所帮助。

1
这个问题已经被许多人发布过了... - Eric Aya

18

已更新至Swift 3:

如果你想打电话,可以使用以下简单的代码:

// 函数定义:

func makeAPhoneCall()  {
    let url: NSURL = URL(string: "TEL://1234567890")! as NSURL
    UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}

// 函数调用:【在您的代码中任何地方都可以使用】

self.makeAPhoneCall()

注意:请在真实设备上运行应用程序,因为模拟器无法正常工作。


它不考虑第一个位置上的0。 - Muhammad Ehsan Mirzaei

7
由于我的回答被错放了,请仔细查看这个: 您可以使用以下方法:
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)
}

我们需要检查是否在iOS 10或更高版本中,因为“openURL”在iOS 10.0中已被弃用。


6
if let phoneCallURL:URL = URL(string: "tel:\(strPhoneNumber)") {
        let application:UIApplication = UIApplication.shared
        if (application.canOpenURL(phoneCallURL)) {
            let alertController = UIAlertController(title: "MyApp", message: "Are you sure you want to call \n\(self.strPhoneNumber)?", preferredStyle: .alert)
            let yesPressed = UIAlertAction(title: "Yes", style: .default, handler: { (action) in
                application.openURL(phoneCallURL)
            })
            let noPressed = UIAlertAction(title: "No", style: .default, handler: { (action) in

            })
            alertController.addAction(yesPressed)
            alertController.addAction(noPressed)
            present(alertController, animated: true, completion: nil)
        }
    }

更好的实现。 - bhakti123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接