4

I do have a UIWebView included where a public URL is loaded; unfortunately, vcard and ical-Links are not handled, i.e. nothing happens when I click on them.

I tried to set all data detectors, no luck unfortunately.

In the Xcode-log, I get this here when clicking on such a link:

2017-07-14 13:43:00.982413+0200 xxx[2208:967973] WF: _userSettingsForUser mobile: {
    filterBlacklist =     (
    );
    filterWhitelist =     (
    );
    restrictWeb = 1;
    useContentFilter = 0;
    useContentFilterOverrides = 0;
    whitelistEnabled = 0;
}

In Safari, the same stuff works as expected.

If I use UIApplication.shared.openURL(icsOrVcardUrl) Safari gets opened and from there everything works as expected again, but I don't want the user to leave the app...

EDIT This doesn't work either:

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    if let url = request.url {
        if url.absoluteString.contains("=vcard&") || url.absoluteString.contains("/ical/") {
            let sessionConfig = URLSessionConfiguration.default
            let session = URLSession(configuration: sessionConfig)
            let request = URLRequest(url:url)
            let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
                if let tempLocalUrl = tempLocalUrl, error == nil {
                    DispatchQueue.main.async {
                        self.documentController.url = tempLocalUrl
                        self.documentController.presentPreview(animated: true)
                    }
                }
            }
            task.resume()
            return false
        }
    }
    return true
}
swalkner
  • 16,679
  • 31
  • 123
  • 210
  • Have you tried the accepted answer here https://stackoverflow.com/a/4442594/2141666 to have the OS handle any links of certain types? That answer has the OS try to handle anything that's not http/https; maybe you could change it to try to have the OS handle any URL that contains .vcard or .ics. – Kdawg Jul 22 '17 at 21:55
  • but those links are https-links starting a download... – swalkner Jul 23 '17 at 06:02
  • The code in your edit won't work, because of the extension of the saved file. See the edit of my answer for more information. – Daniel Alexandrov Jul 23 '17 at 22:17

1 Answers1

2

Use a UIDocumentInteractionController to preview without leaving your app. I tested it quickly with an .ics file and it works fine.

Implement the UIDocumentInteractionControllerDelegate protocol

extension MainViewController: UIDocumentInteractionControllerDelegate {
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        return self;
    }
}

Create an instance of the interaction controller:

let documentController = UIDocumentInteractionController()

Intercept the clicks in your UIWebView in shouldStartLoadWithRequest, return false for links you want to handle with the in-app preview and true for all the rest. And finally:

func previewDocument(_ url: URL) {
    documentController.url = url
    documentController.presentPreview(animated: true)
}

Here it is in the simulator

enter image description here

EDIT:

In response to the comment to this answer: The reason it doesn't work for you is because the UIDocumentInteractionController depends on the file extension. The extension of the temp file is .tmp

Renaming the file after the download solves the problem. Quick and dirty example:

let task = session.downloadTask(with: url!) { (tempLocalUrl, response, error) in
    if let tempLocalUrl = tempLocalUrl, error == nil {
        do {
            let filemgr = FileManager.default
            let newUrl = tempLocalUrl.appendingPathExtension("ics")
            try filemgr.moveItem(at: tempLocalUrl, to: newUrl)
            DispatchQueue.main.async {
                self.documentController.url = newUrl
                self.documentController.presentPreview(animated: true)
            }
        } catch let error {
            print("Error!!!: \(error.localizedDescription)")
        }

    }
}
task.resume()

In this case it is advisable to clean after yourself, because the file won't be deleted after the task completes although the OS will delete it eventually, when space is needed. If you often access the same urls, Library/Caches/ may be a better place for this files, just come up with good naming schema, and check if the file doesn't exist already.

Daniel Alexandrov
  • 1,299
  • 8
  • 13
  • please see my comment, this didn't work for me (I do have `https` links not local ones, therefore I do a download first) – swalkner Jul 23 '17 at 19:55
  • 1
    where Add to calendar or Delete Event option in documentController? why its not showing? – Pankaj Battise Sep 27 '21 at 11:18
  • I'm having the same problem as Pankaj - I don't see buttons to "Add to Calendar" or take any action on this. It's just a preview of the event. – Trev14 Jul 17 '23 at 22:30