WKWebView mailto:

Building an app, iOS 11.0, XCode 9.0, Swift 4.0.


Would like to build an info page, in the past I've used UIWebKit and was able to take advantage of html.


The latest Apple docs recommend WKWebView


I've got it to work with the exception of the mailto://me@example.com//me@example.com mail tag. Would like to stay with Swift 4.0 if possible.


Thank you for ideas or pointers to Tutorials, etc.

Accepted Reply

Wow, that's kind of disappointing about WKWebView.

Personally I think this a bug not a feature. In-app email, as implemented by the MessageUI framework, is a lot nicer than just bouncing out to Mail. However, if you want to bounce out to mail, you can do that by call

openURL(_:)
on UIApplication (actually it’s successor,
open(_:options:completionHandler:)
).

Can I switch to UIWebView or is that ill advised?

That would be ill advised; while

UIWebView
has not been formally deprecated,
WKWebView
is the future of web views on our platforms.

Tried your code with print statements. Upon clicking the mailto: link, I did not see the print statements. Am I not doing something correctly?

Did you set the navigation delegate on the

WKWebView
? Specifically:
  • Your view controller should conform to the

    WKNavigationDelegate
    protocol
  • When your view controller creates the web view, it should set the

    navigationDelegate
    property to
    self

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I've got it to work with the exception of the

mailto://me@example.com//me@example.com

Please describe how that fails.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Quinn:


Thank you for responding.


Here is my code:


    var webView: WKWebView!
/

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self as? WKUIDelegate
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let localfilePath = Bundle.main.url(forResource: "index", withExtension: "html");
/
        let myRequest = URLRequest(url: localfilePath!)
        webView.load(myRequest)
    }


In index.html, this is my mailto: tag:

        <center>
         
               <a href="mailto://me@example.com?subject=MPG%%20Judge%%20Questmg//me@example.com?subject=MPG%%20Judge%%20Questmg src="questions_comments_600.png" width="600" height="37"></a>
        </center>


When I tap on the mailto: tag image, it flashes but Mail does not open with the email ready to go.


I've seen solutions for Swift 3.2, but I'd like to stay with Swift 4.o.


Thank you for your help.

My understanding is that

WKWebView
does not handle
mailto
URLs out of the box. Rather, you should catch the attempt to navigate to such a URL and then display a mail compose interface via the MessageUI framework.

You can do the former using this code:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    switch navigationAction.request.url?.scheme {
    case "mailto"?:
        … your code here …
        decisionHandler(.cancel)
    default:
        decisionHandler(.allow)
    }
}

Two things:

  • The

    mailto
    URL in your example is malformed.
    mailto
    URLs don’t use the leading
    //
    . The official format is specified in RFC 6068 and Apple URL Scheme Reference has the Apple-specific details.
  • When you get the

    mailto
    URL and you want to pull it apart, use
    URLComponents
    rather than string parsing.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Quinn:


Wow, that's kind of disappointing about WKWebView. Can I switch to UIWebView or is that ill advised?


Tried your code with print statements. Upon clicking the mailto: link, I did not see the print statements. Am I not doing something correctly? Tried with Swift 3.2 and 4.0.


    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        switch navigationAction.request.url?.scheme {
        case "mailto"?:
            print("mailto")
                decisionHandler(.cancel)
        default:
            decisionHandler(.allow)
            print("decisionHandler(.allow)")
        }
    }

>> The

mailto
URL in your example is malformed.
mailto
URLs don’t use the leading
//
.

I know, that was something I tried (saw it somewhere on the web) but did not continue. I've since removed the slashes.


Thank you for your assistance!

Wow, that's kind of disappointing about WKWebView.

Personally I think this a bug not a feature. In-app email, as implemented by the MessageUI framework, is a lot nicer than just bouncing out to Mail. However, if you want to bounce out to mail, you can do that by call

openURL(_:)
on UIApplication (actually it’s successor,
open(_:options:completionHandler:)
).

Can I switch to UIWebView or is that ill advised?

That would be ill advised; while

UIWebView
has not been formally deprecated,
WKWebView
is the future of web views on our platforms.

Tried your code with print statements. Upon clicking the mailto: link, I did not see the print statements. Am I not doing something correctly?

Did you set the navigation delegate on the

WKWebView
? Specifically:
  • Your view controller should conform to the

    WKNavigationDelegate
    protocol
  • When your view controller creates the web view, it should set the

    navigationDelegate
    property to
    self

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Eskimo:


Thank you for the help. I am all set now, works on device and simulator.


If it helps anyone, here is my code.

import UIKit
import WebKit
import MessageUI
class SecondViewController: UIViewController, WKNavigationDelegate, MFMailComposeViewControllerDelegate {
    var webView: WKWebView?

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView?.uiDelegate = self as? WKUIDelegate
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        webView?.navigationDelegate = self
        let localfilePath = Bundle.main.url(forResource: "index", withExtension: "html");
     
        let myRequest = URLRequest(url: localfilePath!)
        webView?.load(myRequest)
    }

    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        // Dismiss the mail compose view controller.
        controller.dismiss(animated: true, completion: nil)
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        switch navigationAction.request.url?.scheme {
        case "mailto"?:
            let composeVC = MFMailComposeViewController()
            composeVC.mailComposeDelegate = self
           
            composeVC.setToRecipients(["me@example.com"])
            composeVC.setSubject("Subject Here")
            composeVC.setMessageBody("Message Body", isHTML: false)
         
            if MFMessageComposeViewController.canSendText() {
            // Present the view controller modally.
            self.present(composeVC, animated: true, completion: nil)
            }
            decisionHandler(.cancel)
        default:
            decisionHandler(.allow)
        }
    }
}

Thank you for information.

I immediately incorporated the code in the application and checked it with the actual machine.

The working environment is Xcode 9.1, the actual machine is iPhone 6 with OS 11.0.3.

By clicking mailto:, standard mail application will start up,

me@example.com, Subject Here, Message Body

Will not be reflected in the mail at all.

Is something, is there a heart?

However, if you want to bounce out to mail, you can do that by call 
openURL(_:)
on UIApplication (actually it’s successor,
open(_:options:completionHandler:)
).

Which delegate method do you think is the best place to call this?

Which delegate method do you think is the best place to call this?

The ‘decidePolicyFor’ delegate callback.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"