Denis Kakačka
Denis Kakačka

Reputation: 727

WKWebView save pdf to ibooks, save pdf from link

I'm Junior and currently working on project where Im in WKWebView and there are links to open pdf. I can open it in Safari and then open in iBooks, but i want it to do it inside my app. Is it possible ?

Here are pics how it looks like:

picture where i can select pdf

description1

picture what it will open

description2 my webview class

class WebVC: UIViewController, WKUIDelegate {



var webView: WKWebView!

override func viewDidLoad() {
    super.viewDidLoad()
    let myURL = NSURL(string: "\(savedURL!)")
    let myRequest = URLRequest(url: myURL! as URL)
    webView.load(myRequest)
    webView.allowsBackForwardNavigationGestures = true
    webView.allowsLinkPreview = false
}

override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.toolbar.isHidden = false
}

override func loadView() {
    let webConfiguration = WKWebViewConfiguration()
    webView = WKWebView(frame: CGRect(x: 100, y: 100, width: 110, height: 110), configuration: webConfiguration)
    webView.uiDelegate = self
    view = webView

}

@IBAction func logoutPressed(_ sender: AnyObject) {
    defaults.set(false, forKey: "isLogged")
    defaults.set("EMPTY URL", forKey: "savedURL")
    _ = self.navigationController?.popToRootViewController(animated: true)
}


@IBAction func goBack(_ sender: Any?) {
    if (self.webView.canGoBack) {
        self.webView.goBack()
    }
}

}

Upvotes: 2

Views: 4356

Answers (2)

Malik Kulsoom
Malik Kulsoom

Reputation: 146

  • To open pdf in webview

    //step 1

    webview.uiDelegate = self
    

    //step 2 - implement delegate func (This function will let you open any clicked pdf in webview)

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    
         // open in current view
         webView.load(navigationAction.request)
         // don't return a new view to build a popup into (the default behavior).
         return nil;
     }
    
  • Download

In my case once i have opened pdf in webview, i have download button which i use to download the current opened pdf

//step 3 - delegate funcs

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        decisionHandler(WKNavigationActionPolicy.allow)
    }
    //find the mimeTime of the current url opened in webview, If it's pdf, we'll give option to download 
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        
        if let mimeType = navigationResponse.response.mimeType {
            //check if mime exists in our acceptable mimes list
            if self.isMimeTypeConfigured(mimeType) {
                self.mime = mimeType
                self.currentUrl = navigationResponse.response.url
                addDownloadButton()
            }
        }
        decisionHandler(.allow)
    }

//step 4 - Create a extension with helper functions

//=== PDF downloading ===
struct MimeType {
    var type:String
    var fileExtension:String
}
extension DownloadManual {
    //button
    private func addDownloadButton(){
        let btn = UIBarButtonItem(image: UIImage(systemName: "tray.and.arrow.down.fill"), style: .plain, target: nil, action: #selector(downloadTapped))
        self.navigationItem.rightBarButtonItem = btn
    }
    @objc func downloadTapped(){
        self.showActivityIndicator(show: true)
        if let url = currentUrl {
            print("download from: \(url)")
            let filename = getDefaultFileName(forMimeType: self.mime)
            
            downloadData(fromURL: url, fileName: filename) { success, destinationURL in
                if success, let destinationURL = destinationURL {
                    
                    self.showActivityIndicator(show: false)
                    print("download result: \(success), \(destinationURL)")
                    self.fileDownloadedAtURL(url: destinationURL)
                }
            }
        }
    }
    
    //helper funcs
    private func isMimeTypeConfigured(_ mimeType:String) -> Bool {
        for record in self.mimeTypes {
            if mimeType.contains(record.type) {
                return true
            }
        }
        return false
    }
    
    func fileDownloadedAtURL(url: URL) {
        print("downloaded at: \(url)")
        DispatchQueue.main.async {
            let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil)
            activityVC.popoverPresentationController?.sourceView = self.view
            activityVC.popoverPresentationController?.sourceRect = self.view.frame
            activityVC.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
            self.present(activityVC, animated: true, completion: nil)
        }
    }
    private func downloadData(fromURL url:URL,
                              fileName:String,
                              completion:@escaping (Bool, URL?) -> Void) {
        webview.configuration.websiteDataStore.httpCookieStore.getAllCookies() { cookies in
            let session = URLSession.shared
            print("downloading ....")
            session.configuration.httpCookieStorage?.setCookies(cookies, for: url, mainDocumentURL: nil)
            let task = session.downloadTask(with: url) { localURL, urlResponse, error in
                if let localURL = localURL {
                    let destinationURL = self.moveDownloadedFile(url: localURL, fileName: fileName)
                    completion(true, destinationURL)
                }
                else {
                    completion(false, nil)
                }
            }

            task.resume()
        }
    }
    private func getDefaultFileName(forMimeType mimeType:String) -> String {
        for record in self.mimeTypes {
            if mimeType.contains(record.type) {
                return "default." + record.fileExtension
            }
        }
        return "default"
    }
    
    private func moveDownloadedFile(url:URL, fileName:String) -> URL {
        let tempDir = NSTemporaryDirectory()
        let destinationPath = tempDir + fileName
        let destinationURL = URL(fileURLWithPath: destinationPath)
        try? FileManager.default.removeItem(at: destinationURL)
        try? FileManager.default.moveItem(at: url, to: destinationURL)
        return destinationURL
    }

HOPE this helps someone :)

Upvotes: 2

Denis Kakačka
Denis Kakačka

Reputation: 727

I solved it with UIDocumentInteractionController, add a button and when I push the button It will download whole page and then present DocumentController where "import to iBooks" option is. Hope it helps.

@IBAction func shareBtn(_ sender: AnyObject) {
    var localPath: NSURL?

    Alamofire.download(webView.url!, method: .get, parameters: nil, headers: nil) { (tempUrl, response)  in

        let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let pathComponent = response.suggestedFilename

        localPath = directoryURL.appendingPathComponent(pathComponent!) as NSURL?
        return (destinationURL: localPath as! URL, options: .removePreviousFile)


        }.response { response in
            if localPath != nil{


                self.docController = UIDocumentInteractionController(url: localPath! as URL)
                self.docController.presentOptionsMenu(from: sender as! UIBarButtonItem, animated: true)

            }
    }
}

Upvotes: 1

Related Questions