0

I'm using a UIWebView in my app, I want to detect when the user clicks on a link that leads to a file (pdf, doc, docx....) and not to another HTML page. This will allow me to download the file and open it by presenting options menu.

I tried to use the following function:

webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest,  navigationType: UIWebViewNavigationType) -> Bool

In this function I get the URL, send the HEAD request in order to get the content-type of the response and if it does not contain text/html I download it and present the options menu.

This is not a perfect solution since I need to make Sync request in order to get the content-type.

Did anyone encounter this issue before? How can I solve it?

I tried to search all over the internet but couldn't find anything similar to this issue

Jack
  • 13,571
  • 6
  • 76
  • 98
Oday
  • 141
  • 8

2 Answers2

0

Try this

override func viewDidLoad() {
        super.viewDidLoad()
        self.myWebview.delegate = self;

        // Do any additional setup after loading the view, typically from a nib.
        let url = URL(string: "YOUR_URL_STRING")
        debugPrint(url!)
        myWebview.loadRequest(URLRequest(url: url!))
    }

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        debugPrint("func myWebView has been called")
        debugPrint(request.url!)
        if navigationType == UIWebViewNavigationType.linkClicked {
            if (request.url!.host! == "stackoverflow.com"){
                return true
            } else {
                //UIApplication.sharedApplication().openURL(request.URL!)
                UIApplication.shared.open(request.url!)
                return false
            }
        }
        return true
    }

Hope this will helps you.

Kamlesh Shingarakhiya
  • 2,757
  • 2
  • 16
  • 34
  • Thank you for you'r answer, but no, this is not what I'm looking for. I'm looking to know the type of the URL the webview trying to load, pdf, doc, docx or just an html page.. – Oday Aug 09 '17 at 10:28
  • 1
    UIDocumentInteractionController will help you https://code.tutsplus.com/tutorials/ios-sdk-previewing-and-opening-documents--mobile-15130 or Please check this https://stackoverflow.com/q/28279463/3515115 – Kamlesh Shingarakhiya Aug 09 '17 at 11:02
0

Finally, I figured out the perfect solution.

In the shouldStartLoadWith:

   var checkingProcesses: [URL:CheckingProcess] = [:]

   func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

    Logger.log("WebviewViewController", "shouldStartLoadWith", "with url: \(String(describing: request.url?.absoluteString))")
    self.loadingViewLogic(hide: false)

    if let currentURL = request.url {

        if let process = self.checkingProcesses[currentURL]{

            Logger.log("WebviewViewController", "shouldStartLoadWith", "Known process: \(String(describing: process))")

            if(process.status == CheckingStatus.finished){

                if(process.filePath != nil){
                    self.openFileByPresentingOptions(pathURL: process.filePath!)
                    return false

                }else if(process.errorMessage != nil){

                    //error
                    Util.showAlert(context: self, title: "Error getting URL type", message: process.errorMessage!, alertActions: nil)
                    process.clearResults()//In order to try the next time the user asks.
                    self.loadingViewLogic(hide: true)
                    return false

                }else{

                    //link - open it
                    return true
                }

            }else if(process.status == CheckingStatus.processing){

                Util.showAlert(context: self, title: "Processing...", message: "Please wait...", alertActions: nil)
                return false

            }else{//inactive

                self.checkingProcesses[currentURL]?.startCheck()
                return false
            }

        }else{// did not create the process yet

            Logger.log("WebviewViewController", "shouldStartLoadWith", "Creating new process for URL: \(currentURL.absoluteString)")

            self.checkingProcesses[currentURL] = CheckingProcess(url: currentURL, webView: self.webView)
            self.checkingProcesses[currentURL]?.startCheck()
            return false
        }

    }else{

        Logger.log("WebviewViewController", "shouldStartLoadWith", "Couldn't get the currentURL")
        self.loadingViewLogic(hide: true)
        return false
    }

}

I created a class "CheckingProcess.swift":

import UIKit

public enum CheckingStatus {
    case inactive
    case processing
    case finished
}

class CheckingProcess: CustomStringConvertible {

    var status : CheckingStatus;
    var url: URL;
    var filePath: URL? = nil;
    var errorMessage: String? = nil;
    let webView: UIWebView?

    init(url: URL, webView: UIWebView) {

        Logger.log("CheckingProcess", "init", "with url: \(url.absoluteString)")
        self.status = CheckingStatus.inactive;
        self.url = url;
        self.webView = webView
    }

    func startCheck(){

        Logger.log("CheckingProcess", "startCheck", "with url: \(self.url.absoluteString), START")
        self.status = CheckingStatus.processing

        let destinationUrl = Util.generateLocalFileURL(remoteURL: self.url)

        DownloadManager.downloadFileAndSaveIfNotHTML(url: url, to: destinationUrl, completion: {(finalLocalURL, errorMessage) in

            Logger.log("CheckingProcess", "startCheck callback block", "url: \(self.url.absoluteString), FinalLocalURL: \(String(describing: finalLocalURL)), errorMessage: \(String(describing: errorMessage))")
            self.filePath = finalLocalURL
            self.errorMessage = errorMessage

            self.status = CheckingStatus.finished

            self.webView?.loadRequest(NSURLRequest(url: self.url as URL) as URLRequest)
        })
    }

    func clearResults(){
        self.status = CheckingStatus.inactive
        self.filePath = nil
        self.errorMessage = nil
    }

    public var description: String {

        return "URL: \(self.url), Status: \(self.status), filePath: \(String(describing: self.filePath)), errorMessage: \(String(describing: self.errorMessage))"
    }

}

Enjoy!

Oday
  • 141
  • 8