在Swift iOS中获取部分mailto链接

时间:2018-02-21 00:21:52

标签: ios swift

我打开了一个包含mailto链接(mailto:test@test.com)

的网页的webview

我能够获得url=mailto:test@test.com但不能获得与常规网址不同的部分。我想在撰写邮件时从mailto url中提取电子邮件以进行预填充。有没有一种优雅的方法从Swift iOS中的mailto url中提取test@test.com?


func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
 let request: URLRequest = navigationAction.request

        if let url = request.url,
            url.scheme == "mailto" {
            decisionHandler(.cancel)
            let urlString = "scheme://myapp/open/compose?\(url.absoluteString.replacingOccurrences(of: ":", with: "="))
            UIApplication.shared.open(URL(string: urlString)!)
            return
        }
}

2 个答案:

答案 0 :(得分:6)

您可以获取您的网址路径组件:

let url = URL(string: "mailto:test@test.com")!
if url.scheme == "mailto", 
    let components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
    let email = components.path
    print(email)  // "test@test.com\n"
}

您还可以按以下方式扩展网址:

extension URL {
    var email: String? {
        return scheme == "mailto" ? URLComponents(url: self, resolvingAgainstBaseURL: false)?.path : nil
    }
}
if let email = url.email {
    print("email:", email)    // "email: test@test.com\n"
}

答案 1 :(得分:1)

为了完成@Leo Dabus的回答,我写了一篇详尽的struct,该文档处理了RFC2368中指定的所有情况:

struct EmailParameters {
    /// Guaranteed to be non-empty
    let toEmails: [String]
    let ccEmails: [String]
    let bccEmails: [String]
    let subject: String?
    let body: String?

    /// Defaults validation is just verifying that the email is not empty.
    static func defaultValidateEmail(_ email: String) -> Bool {
        return !email.isEmpty
    }

    /// Returns `nil` if `toEmails` contains at least one email address validated by `validateEmail`
    /// A "blank" email address is defined as an address that doesn't only contain whitespace and new lines characters, as defined by CharacterSet.whitespacesAndNewlines
    /// `validateEmail`'s default implementation is `defaultValidateEmail`.
    init?(
        toEmails: [String],
        ccEmails: [String],
        bccEmails: [String],
        subject: String?,
        body: String?,
        validateEmail: (String) -> Bool = defaultValidateEmail
    ) {
        func parseEmails(_ emails: [String]) -> [String] {
            return emails.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter(validateEmail)
        }
        let toEmails = parseEmails(toEmails)
        let ccEmails = parseEmails(ccEmails)
        let bccEmails = parseEmails(bccEmails)
        if toEmails.isEmpty {
            return nil
        }
        self.toEmails = toEmails
        self.ccEmails = ccEmails
        self.bccEmails = bccEmails
        self.subject = subject
        self.body = body
    }

    /// Returns `nil` if `scheme` is not `mailto`, or if it couldn't find any `to` email addresses
    /// `validateEmail`'s default implementation is `defaultValidateEmail`.
    /// Reference: https://tools.ietf.org/html/rfc2368
    init?(url: URL, validateEmail: (String) -> Bool = defaultValidateEmail) {
        guard let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
            return nil
        }
        let queryItems = urlComponents.queryItems ?? []
        func splitEmail(_ email: String) -> [String] {
            return email.split(separator: ",").map(String.init)
        }
        let initialParameters = (toEmails: urlComponents.path.isEmpty ? [] : splitEmail(urlComponents.path), subject: String?(nil), body: String?(nil), ccEmails: [String](), bccEmails: [String]())
        let emailParameters = queryItems.reduce(into: initialParameters) { emailParameters, queryItem in
            guard let value = queryItem.value else {
                return
            }
            switch queryItem.name {
            case "to":
                emailParameters.toEmails += splitEmail(value)
            case "cc":
                emailParameters.ccEmails += splitEmail(value)
            case "bcc":
                emailParameters.bccEmails += splitEmail(value)
            case "subject" where emailParameters.subject == nil:
                emailParameters.subject = value
            case "body" where emailParameters.body == nil:
                emailParameters.body = value
            default:
                break
            }
        }
        self.init(
            toEmails: emailParameters.toEmails,
            ccEmails: emailParameters.ccEmails,
            bccEmails: emailParameters.bccEmails,
            subject: emailParameters.subject,
            body: emailParameters.body,
            validateEmail: validateEmail
        )
    }
}

一旦包含在您的应用中,解析mailto链接就变得非常简单:

let mailToURL: URL(string: "mailto:test@example.com")!
if let emailParameters = EmailParameters(url: url) {
  // You can then access each of `emailParameters`'s fields
  // emailParameters.toEmails is guaranteed to have a non-empty email address (i.e accessing `emailParameters.toEmails[0]` will never crash)
  // Note it doesn't perform email validation by default, but you can specify
  // a custom `validateEmail` closure if need be in the `EmailParameters` initializer above
}

我还创建了一个要点,以提供更多here可用功能(主要用于很好地支持嵌入式HTML和Markdown内容中的链接)。