Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIWebView: ics and vcard-Links not handled

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
}
like image 973
swalkner Avatar asked Sep 20 '25 22:09

swalkner


1 Answers

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.

like image 102
Daniel Alexandrov Avatar answered Sep 23 '25 11:09

Daniel Alexandrov