1

I am implementing a custom WKWebViewClass. The init() is settings the navigationDelegate to self, and starting the load. However, didFinish is never called. I am getting a didFailProvisionalNavigation error

didFailProvisionalNavigation The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 1.)

let pdf = generatePDF(frame: view.bounds)
view.addSubview(pdf)

pdf.startGenerating(){

}



public class generatePDF: WKWebView, WKUIDelegate, WKNavigationDelegate {
static var observer: NSObjectProtocol!

public override init(frame: CGRect, configuration: WKWebViewConfiguration = WKWebViewConfiguration()) {
    super.init(frame: frame, configuration: configuration)
    doInit()
}

func doInit() {
    DocMakerInfo.isDoneLoading = false
    self.navigationDelegate = self
    self.uiDelegate = self
    print("didInit")
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

public func startGenerating(completion: @escaping () -> Void) {
    openDocument(fileName: DocMakerInfo.fileName, extenstion: DocMakerInfo.extenstion)
    completion()
}

private func openDocument(fileName:String, extenstion:String){
    do {
        #if targetEnvironment(macCatalyst)
            let homeDirURL = (NSSearchPathForDirectoriesInDomains(.downloadsDirectory, .userDomainMask, true) as [String]).first!
            let docURL = URL(string: "file://\(homeDirURL)/")!
        #else
            let docURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        #endif
        let contents = try FileManager.default.contentsOfDirectory(at: docURL, includingPropertiesForKeys: [.fileResourceTypeKey], options: .skipsHiddenFiles)
        for url in contents {
            #if targetEnvironment(macCatalyst)
                if url.description.contains("/\(fileName)\(extenstion)") {
                    webView.frame = view.bounds
                    let fileURL = docURL.appendingPathComponent("\(fileName)\(extenstion)")
                    let dataFileMimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                    do {
                        let fileContent = try Data(contentsOf: url)
                        self.load(fileContent, mimeType: dataFileMimeType, characterEncodingName: "", baseURL: url)
                        //self.view = self.webView
                        Dynamic.NSWorkspace.sharedWorkspace.activateFileViewerSelectingURLs([url])
                    } catch let error {
                        print(error.localizedDescription)
                    }
                }
            #else
                if url.description.contains("\(fileName)\(extenstion)") {
                    self.bounds = CGRect(x: 0, y: 0, width: 700.00, height: 1000.00)
                    let fileURL = docURL.appendingPathComponent("\(fileName)\(extenstion)")
                    let fileURL = docURL.appendingPathComponent("\(fileName)\(extenstion)")
                    self.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
                    self.load(URLRequest(url: fileURL))
                    print("startedLoading")
                }
            #endif
        }
    } catch {
        Swift.print(#file, #function, "could not locate \(extenstion) file !!!!!!!")
    }
}

public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    print("didStartProvisionalNavigation")
}

public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    decisionHandler(.allow)
}

public func webView(_ webView: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError error: Error) {
    print("didFailProvisionalNavigation", error.localizedDescription)
}

public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    print("didFail", error.localizedDescription)
}

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    print("doneloading")
    let config = WKPDFConfiguration()
    webView.createPDF(configuration: config) { result in
        switch result {
        case .success(let data):
            #if targetEnvironment(macCatalyst)
                
            #else
            let destURL = FileManager.default.temporaryDirectory.appendingPathComponent("\(DocMakerInfo.fileName).pdf")
            do {
                try data.write(to: destURL)
                print("createpdf")
                DocMakerInfo.isDoneLoading = true
            } catch {
                print("didFinish", error)
            }
            #endif
        case .failure(let error):
            print("create pdf failure: \(error)")
        }
    }
}
}
DarkDust
  • 90,870
  • 19
  • 190
  • 224
Will
  • 11
  • 2
  • Please format your code to make it more readable – Joakim Danielson Mar 25 '22 at 15:40
  • You probably want generatePDF to be a UIView or a WKWebView ? Because you have a webView within a webview. Does anything print in the console and does anything load ? – Shawn Frank Mar 25 '22 at 15:44
  • @ShawnFrank It does print the didInit, and startedLoading, but not the doneLoading – Will Mar 25 '22 at 15:50
  • Well start loading is called from the init so that can't be counted as a notification. Does the file load in the webview and you can see it on screen ? – Shawn Frank Mar 25 '22 at 17:51
  • Nothing is loaded in the web view – Will Mar 25 '22 at 17:59
  • Please can you add the code for the following 1. How to you instantiate `generatePDF` and add it to your view controller 2. How is `fileURL` set and assigned and possible share the value of it. The reasons I ask for this as there could be issues ranging from how `generatePDF` was created, added to the view hierarchy or issues with the file url - there could be several reasons. – Shawn Frank Mar 25 '22 at 18:09
  • @ShawnFrank Like I said, this works fine from the UIViewController just not the generatePDF class. So I know the file url is correct. – Will Mar 25 '22 at 18:33

1 Answers1

0

Few things I can note:

  1. Give your PDFView a frame

What you have:

let pdf = generatePDF()

What you should do is give it a frame using autolayout or frames because even if it does load something, without a frame you cannot see anything

So for example:

// View is the container the pdf view will be in
let pdf = generatePDF(frame: view.bounds)
  1. Probably the most important one, add your pdf view to the view hierarchy or nothing will happen
let pdf = generatePDF(frame: view.bounds)

// Add this
view.addSubview(pdf)

pdf.startGenerating(){
    
}
  1. I am assuming everything in your openDocument works well as it cannot be tested at my end, however, I just used my local PDF and this worked fine with all the notifications working

Give this a try and see if you have any better results on your end

Update to include the full source code

This is the same as your PDF class, I have only changed the openDocument function to open a local PDF file so this is the only difference

public class generatePDF: WKWebView, WKUIDelegate, WKNavigationDelegate {
    static var observer: NSObjectProtocol!
    
    public override init(frame: CGRect, configuration: WKWebViewConfiguration = WKWebViewConfiguration()) {
        super.init(frame: frame, configuration: configuration)
        doInit()
    }
    
    func doInit() {
        self.navigationDelegate = self
        self.uiDelegate = self
        print("didInit")
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func startGenerating(completion: @escaping () -> Void) {
        openDocument(fileName: "test", extension: "pdf")
        completion()
    }
    
    private func openDocument(fileName: String, extension: String) {
        
        // I have replaced your file with a local PDF file in my bundle
        
        if let pdfURL = Bundle.main.url(forResource: "test",
                                        withExtension: "pdf",
                                        subdirectory: nil,
                                        localization: nil)  {
            do {
                let data = try Data(contentsOf: pdfURL)
                self.load(data, mimeType: "application/pdf", characterEncodingName:"", baseURL: pdfURL.deletingLastPathComponent())
                print("started loading")
            }
            catch {
                // catch errors here
            }
            
        }
        
        
    }
    
    public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("didStartProvisionalNavigation")
    }
    
    public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        decisionHandler(.allow)
    }
    
    public func webView(_ webView: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError error: Error) {
        print("didFailProvisionalNavigation", error.localizedDescription)
    }
    
    public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("didFail", error.localizedDescription)
    }
    
    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("doneloading")
    }
}

Then I have a ViewController

class WebViewTestVC: UIViewController {
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        let pdf = generatePDF(frame: view.bounds)
        
        // Add this
        view.addSubview(pdf)
        
        pdf.startGenerating(){
            
        }
    }
}

The result is a webview loading the PDF:

PDF loaded in a WKWebView swift iOS

The print out on my console:

didInit
started loading
didStartProvisionalNavigation
doneloading

Update based on Will's comments

I am now getting this error. didFailProvisionalNavigation The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 1.)

This could be a file permission error based on what I read here and here

Instead of what you do here

let fileContent = try Data(contentsOf: url)
self.load(fileContent, mimeType: dataFileMimeType, characterEncodingName: "", baseURL: url)

I changed this to, so give that a try:

loadFileURL(url, allowingReadAccessTo: url)

I have added an excel file to my documents directory and tried to load it in the webview, here are my changes in the generatePDF class:

public func startGenerating(completion: @escaping () -> Void) {
    openDocument(fileName: "Products", ext: "xlsx")
    completion()
}


private func openDocument(fileName: String, ext: String) {
    
    do {
        let docURL = try FileManager.default.url(for: .documentDirectory,
                                                 in: .userDomainMask,
                                                 appropriateFor: nil,
                                                 create: false)
        
        let contents
            = try FileManager.default.contentsOfDirectory(at: docURL,
                                                          includingPropertiesForKeys: [.fileResourceTypeKey],
                                                          options: .skipsHiddenFiles)
        
        for url in contents {
            if url.description.contains("/\(fileName).\(ext)") {
                
                loadFileURL(url, allowingReadAccessTo: url)
            }
        }
    }
    catch {
        print(error)
    }
}

The excel loads fine and also the notifications of done loading is called properly

Load Excel xlsx in WKWebView swift iOS

Shawn Frank
  • 4,381
  • 2
  • 19
  • 29
  • Unfortunate I am still getting the same issue. This does print the didInit, and startedLoading, but not the doneLoading. And the web view is still white blank – Will Mar 25 '22 at 18:57
  • Where do you add the code in part 2 of my answer ? I add this on `viewDidAppear` and I could see a file loading. – Shawn Frank Mar 25 '22 at 19:00
  • Yes, I added this to my viewDidAppear in my viewController and it is not loading still – Will Mar 25 '22 at 19:12
  • @Will - I have updated the answer to include my full example of code. The only difference is the logic from your `openDocument` function and `DocMakerInfo`. If this still does not work, is there a way you can share a small version of your project with just this bit so I can reproduce this portion of code at my end and debug it ? – Shawn Frank Mar 25 '22 at 19:15
  • That got me further. I am now getting this error. didFailProvisionalNavigation The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 1.) – Will Mar 25 '22 at 19:23
  • @Will - please see my updated answer. – Shawn Frank Mar 26 '22 at 05:22