I have a question about WKWebview.
First, I have a UITabbarViewController(tab1, tab2), and two ViewControllers.
In ViewController1 have two button (button1, button2) which action is click the tabbar tab2 to present the ViewController2 and bring different url string.
In ViewController2 have a WKWebView, and load the request of url string.
I work fine in simulator, but build in device and work fine at first time and the then I tap the tabbar tab1 and back to ViewController1.
I click the button2 and present the ViewController2.
And I also set breakpoint, the WKWebview have run the load request function.
But the WKWebview also show me the button1 url content, not button2 url content. When I back and click button2 again, it's work. Why the WKWebView don't refresh at first time?
Thanks.
Xcode 9.4.1, device iOS 12.0.1(16A404)
class ViewController1: UIViewController {
#objc func btnTapped(sender: UIButton) {
if let vc = self.navigationController?.parent as? ViewController {
if let number = item?.number {
let domainPath = “\(customURL!.absoluteString)"
let extPath = "detail/\(number)/&topPageBack=list"
let encodestr = extPath.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let finalPath = domainPath.appending("/").appending(encodestr!)
if let url = URL(string: finalPath) {
vc.loadSpecificURL = url
}
vc.tabBarView.buttonClick(tag: 1)
}
}
}
}
class ViewController2: UIViewController {
lazy var webViewController: CustomWKWebViewController = {
let controller = CustomWKWebViewController()
controller.wKWebViewPage = .searchPage
return controller
}()
var loadURL: URL?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let url = loadURL {
webViewController.reloadWebView(url: url)
loadURL = nil
}
}
}
class CustomWKWebViewController: UIViewController {
private func settingWebView() -> WKWebView {
let userScript = WKUserScript(source: source, injectionTime: .atDocumentStart, forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.add(self, name: "Login")
userContentController.add(self, name: "Other")
userContentController.add(self, name: “LD”)
userContentController.addUserScript(userScript)
let config = WKWebViewConfiguration()
config.userContentController = userContentController
webView = WKWebView(frame: .zero, configuration: config)
webView!.navigationDelegate = self
webView!.uiDelegate = self
webView!.scrollView.bounces = false
webView!.allowsBackForwardNavigationGestures = true
webView!.backgroundColor = .clear
webView!.scrollView.backgroundColor = .clear
if let request = getRequest() {
webView!.load(request)
}
return webView!
}
func reloadWebView(url: URL?) {
if let url = url, let webView = self.webView {
var requestForBlank = URLRequest(url: URL(string: "about:blank")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3)
requestForBlank.httpMethod = "POST"
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3)
request.httpMethod = "POST"
webView.load(requestForBlank)
webView.load(request)//breakpoint always break here, but the view don't load request.
}
}
}
First you check if web url not nil, then also call the else part of if.
if let url = webview.url {
webview.reload()
} else {
webview.load(URLRequest(url: originalURL))
}
Rather than loading a WebView from a URL like this
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: imageUrl.urlString)
let request = URLRequest(url: url!)
webView.load(request)
}
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
How can I load a UIImage onto the WebView in Swift 4?
Try Something like this.
let html = "<html><img src=\"datadb/DestinationGuide/Images/YourImage.png\"/> </html>"
//Save this html in `DocumentDirectory`
let saveHTML = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("temp.html")
try? html.data(using: .utf8)!.write(to: saveHTML)
//Now load this `temp.html` file in webView
webView.loadRequest(URLRequest(url: saveHTML))
I am having an issue with WKWebView I init like this
let configuration = WKWebViewConfiguration()
configuration.applicationNameForUserAgent = "Browser"
configuration.ignoresViewportScaleLimits = true
configuration.allowsInlineMediaPlayback = true
configuration.allowsAirPlayForMediaPlayback = true
configuration.allowsPictureInPictureMediaPlayback = true
configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.audio
configuration.selectionGranularity = WKSelectionGranularity.character
configuration.dataDetectorTypes = WKDataDetectorTypes.link
let webview = WKWebView(frame: .zero, configuration: configuration)
webview.allowsBackForwardNavigationGestures = true
webview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webview.uiDelegate = self
webview.navigationDelegate = self
let url = URL(string: "https://www.google.com")!
let request = URLRequest(url: url)
webview.load(request)
self.view = webview
everytime I enter a search box on a website for example "Google" I get this log in the debugger... I can't seem to understand why it is throwing constraint issues while I did not set any... and this view is contained in UINavigationController that has a UIToolbar
Screenshot of Storyboard.
I am using MarkDonwView Library : https://github.com/keitaoouchi/MarkdownView
Which is converting MD String to show as a webview. Rendering is taking too long as it loads everything and then shows the view. Is it possible to make image loading async while showing text body ASAP so it will not look like its too slow ?
This is how it is loading the html file.
if bundle.bundleIdentifier?.hasPrefix("org.cocoapods") == true {
htmlURL = bundle.url(forResource: "index",
withExtension: "html",
subdirectory: "MarkdownView.bundle")
} else {
htmlURL = bundle.url(forResource: "index",
withExtension: "html")
}
if let url = htmlURL {
let templateRequest = URLRequest.init(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 60) //URLRequest(url: url)
let escapedMarkdown = self.escape(markdown: markdown) ?? ""
let imageOption = enableImage ? "true" : "false"
let script = "window.showMarkdown('\(escapedMarkdown)', \(imageOption));"
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let controller = WKUserContentController()
controller.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
let wv = WKWebView(frame: self.bounds, configuration: configuration)
wv.scrollView.isScrollEnabled = self.isScrollEnabled
wv.translatesAutoresizingMaskIntoConstraints = false
wv.navigationDelegate = self
addSubview(wv)
wv.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
wv.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
wv.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
wv.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
wv.backgroundColor = self.backgroundColor
self.webView = wv
wv.load(templateRequest)
} else {
// TODO: raise error
}
How can I add a PDF file for an app , where you click on a button to view the file & when you're done you get back to screen you were at?
If you simply want to view a PDF file you can load it into a UIWebView.
let url : NSURL! = NSURL(string: "http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIWebView_Class/UIWebView_Class.pdf")
webView.loadRequest(NSURLRequest(URL: url))
Swift 4.1 :
let url: URL! = URL(string: "http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIWebView_Class/UIWebView_Class.pdf")
webView.loadRequest(URLRequest(url: url))
If you'd like to achieve more, a good framework is PSPDFKit.
Apple added PDFKit framework in iOS 11
Add a UIView to your view controller and make it's class to PDFView
import UIKit
import PDFKit
class ViewController: UIViewController {
#IBOutlet var pdfView: PDFView!
override func viewDidLoad() {
super.viewDidLoad()
if let path = Bundle.main.path(forResource: "sample", ofType: "pdf") {
if let pdfDocument = PDFDocument(url: URL(fileURLWithPath: path)) {
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
pdfView.displayDirection = .vertical
pdfView.document = pdfDocument
}
}
}
}
There are 4 display modes : singlePage, singlePageContinuous, twoUp, twoUpContinuous .
SWIFT 4+
If has to open file from local cache/Documentdiectory which has file path
Method 1: using UIDocumentInteractionController
class ViewController: UIViewController,UIDocumentInteractionControllerDelegate {
//let path = Bundle.main.path(forResource: "Guide", ofType: ".pdf")!
let dc = UIDocumentInteractionController(url: URL(fileURLWithPath: path))
dc.delegate = self
dc.presentPreview(animated: true)
}
//MARK: UIDocumentInteractionController delegates
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self//or use return self.navigationController for fetching app navigation bar colour
}
Method 2: using WebView
let webview = WKWebView(frame: UIScreen.main.bounds)
view.addSubview(webview)
webview.navigationDelegate = self
webview.load(URLRequest(url: URL(fileURLWithPath: path)))//URL(string: "http://") for web URL
For Xcode 8.1 and Swift 3.0
Save the PDF file in any folder of your xcode.
Suppose the file name is 'Filename.pdf'
if let pdf = Bundle.main.url(forResource: "Filename", withExtension: "pdf", subdirectory: nil, localization: nil) {
let req = NSURLRequest(url: pdf)
yourWebViewOutletName.loadRequest(req as URLRequest)
}
Same will apply if you want to open any html file.
you can use UIDocumentInteractionController to preview file in IOS.
In the view controller's file, add a property of type UIDocumentInteractionController
and implement a simple delegate method of it
self.documentInteractionController = UIDocumentInteractionController.init(URL: url)
self.documentInteractionController?.delegate = self
self.documentInteractionController?.presentPreviewAnimated(true)
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController {
return self
}
don't forget to add UIDocumentInteractionControllerDelegate in view controller's class
Check out PDFKit from IOS11
Here is an example of a view controller which implements PDFView from PDFKit.
import UIKit
import PDFKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Add PDFView to view controller.
let pdfView = PDFView(frame: self.view.bounds)
self.view.addSubview(pdfView)
// Fit content in PDFView.
pdfView.autoScales = true
// Load Sample.pdf file.
let fileURL = Bundle.main.url(forResource: "Sample", withExtension: "pdf")
pdfView.document = PDFDocument(url: fileURL!)
}
}
SWIFT 5
An update to open the file from the Document directory (device) and present preview:
let urlFile = URL(string: pathToFile)
var documentInteractionController: UIDocumentInteractionController!
documentInteractionController = UIDocumentInteractionController.init(url: urlFile!)
documentInteractionController?.delegate = self
documentInteractionController?.presentPreview(animated: true)
And UIDocumentInteractionControllerDelegate:
extension ViewController: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}
}
If you want to dismiss the document preview you can use:
documentInteractionController?.dismissPreview(animated: true)
You can use this code in Swift 4
Import PDFKit
Copy this code
let pdfView = PDFView()
pdfView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pdfView)
pdfView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
pdfView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
guard let path = Bundle.main.url(forResource: "test", withExtension: "pdf") else { return }
if let document = PDFDocument(url: path) {
pdfView.document = document
}
You can use this UIViewController. It contains the share button for free:
import UIKit
import PDFKit
class PDFWebViewController: UIViewController {
var pdfURL: URL!
private var pdfView: PDFView!
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = []
self.setPDFView()
self.fetchPDF()
}
private func setPDFView() {
DispatchQueue.main.async {
self.pdfView = PDFView(frame: self.view.bounds)
self.pdfView.maxScaleFactor = 3;
self.pdfView.minScaleFactor = self.pdfView.scaleFactorForSizeToFit;
self.pdfView.autoScales = true;
self.pdfView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.view.addSubview(self.pdfView)
}
}
private func fetchPDF() {
DispatchQueue.global(qos: .userInitiated).async {
if let data = try? Data(contentsOf: self.pdfURL), let document = PDFDocument(data: data) {
DispatchQueue.main.async {
self.pdfView.document = document
self.addShareBarButton()
}
}
}
}
private func addShareBarButton() {
let barButtonItem = UIBarButtonItem(barButtonSystemItem: .action,
target: self,
action: #selector(self.presentShare))
barButtonItem.tintColor = .white
self.navigationItem.rightBarButtonItem = barButtonItem
}
#objc private func presentShare() {
guard let pdfDocument = self.pdfView.document?.dataRepresentation() else { return }
let activityViewController = UIActivityViewController(activityItems: [pdfDocument], applicationActivities: nil)
activityViewController.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
self.present(activityViewController, animated: true)
}
}
To use it:
let viewController = PDFWebViewController()
// the url can be a web url or a file url
viewController.pdfURL = url
self.navigationController?.pushViewController(viewController, animated: true)
You can also use Quick Look Framework from Apple.
It is very flexible.
You can show your PDF file with zoom feature.
Also you have support for all other types (like png, jpg, docx, txt, rtf, xlsx, zip, mov, etc) of files and it is very easy to use.
Please refer
this answer if you want detail description of using QuickLook.framework
A modernized version of Akila's answer, with the benefit that it is a drop in, ready to use UIViewController that you can integrate into your app.
import UIKit
import PDFKit
final class PDFViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let pdfView = PDFView(frame: view.frame)
title = "Your_title_here"
if let url = Bundle.main.url(forResource: "document_name_here", withExtension: "pdf"),
let pdfDocument = PDFDocument(url: url) {
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
pdfView.displayDirection = .vertical
pdfView.document = pdfDocument
view.addSubview(pdfView)
}
}
}
It creates the PDFView during viewDidLoad and sets it to use the view's frame
The URL for the PDF file is safely unwrapped from the bundle and then a PDFDocument is created, if possible
Some common settings are used. Adjust as needed
Finally, it adds the PDFView as a subview of the controller's view
//In Swift 5
class PDFBookViewController: UIViewController, PDFViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
addPDFView()
}
private func addPDFView() {
let pdfView = PDFView()
pdfView.translatesAutoresizingMaskIntoConstraints = false
pdfContenerView.addSubview(pdfView)
pdfView.leadingAnchor.constraint(equalTo: pdfContenerView.safeAreaLayoutGuide.leadingAnchor).isActive = true
pdfView.trailingAnchor.constraint(equalTo: pdfContenerView.safeAreaLayoutGuide.trailingAnchor).isActive = true
pdfView.topAnchor.constraint(equalTo: pdfContenerView.safeAreaLayoutGuide.topAnchor).isActive = true
pdfView.bottomAnchor.constraint(equalTo: pdfContenerView.safeAreaLayoutGuide.bottomAnchor).isActive = true
pdfView.autoScales = true
pdfView.displayMode = .singlePageContinuous
pdfView.displayDirection = .vertical
///Open pdf with help of FileManager URL
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let bookWithPdf = "\(bookname).pdf"
let fileURL = dir.appendingPathComponent(bookWithPdf)
let document = PDFDocument(url: fileURL)
pdfView.document = document
}
#IBAction func backButtonPressed(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
}
if let url: URL = URL(string: "http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIWebView_Class/UIWebView_Class.pdf") {
webView.loadRequest(URLRequest(url: url)) }
let openLink = NSURL(string : OtherContactorProfileVview.Result.CertificateList[index].CertificateFileLink)
if #available(iOS 9.0, *) {
let svc = SFSafariViewController(url: openLink! as URL)
present(svc, animated: true, completion: nil)
} else {
let port = UIStoryboard(
name: "Main",
bundle: nil
).instantiateViewController(withIdentifier: "PDFViewer") as! PDFViewer
port.strUrl = OtherContactorProfileVview.Result.CertificateList[index].CertificateFileLink
navigationController?.pushViewController(port, animated: true)
}