25

So I am currently trying to display a local PDF I have in UIWebview and this is the code I'm using:

@IBOutlet weak var webView:UIWebView!
override func viewDidLoad() {
    super.viewDidLoad()    

var pdfLoc = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("Sample", ofType:"pdf")!) 
var request = NSURLRequest(URL: pdfLoc);
self.webView.loadRequest(request);
}

The code will successfully build, but when I run the app, it will crash with the error: Thread 1: EXC_BAD_INSTRUCTION(code=EXC-I386_INVOP,subcode=0x0)

I have found a few tutorials on how to do this, but they are all very outdated or in Objective-C.

dannysandler
  • 1,881
  • 4
  • 16
  • 14

5 Answers5

55

Here you go:

if let pdf = NSBundle.mainBundle().URLForResource("myPDF", withExtension: "pdf", subdirectory: nil, localization: nil)  {
            let req = NSURLRequest(URL: pdf)
            let webView = UIWebView(frame: CGRectMake(20,20,self.view.frame.size.width-40,self.view.frame.size.height-40))
            webView.loadRequest(req)
            self.view.addSubview(webView)
        }

Edit

The alternative is via NSData:

if let pdfURL = NSBundle.mainBundle().URLForResource("myPDF", withExtension: "pdf", subdirectory: nil, localization: nil),data = NSData(contentsOfURL: pdfURL), baseURL = pdfURL.URLByDeletingLastPathComponent  {
    let webView = UIWebView(frame: CGRectMake(20,20,self.view.frame.size.width-40,self.view.frame.size.height-40))
    webView.loadData(data, MIMEType: "application/pdf", textEncodingName:"", baseURL: baseURL)
    self.view.addSubview(webView)
}

Apple make a point of advising you to not use .loadRequest for local HTML files, while not clearly extending this to other data types. So I've provided the NSData route above. If you wish to specify a textEncodingName it can be "utf-8", "utf-16", etc.

Edit: Swift 3

Here's a Swift 3 version of the code using, as Apple advise, WKWebView in place of UIWebView.

import UIKit
import WebKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        if let pdfURL = Bundle.main.url(forResource: "myPDF", withExtension: "pdf", subdirectory: nil, localization: nil)  {
            do {
                let data = try Data(contentsOf: pdfURL)
                let webView = WKWebView(frame: CGRect(x:20,y:20,width:view.frame.size.width-40, height:view.frame.size.height-40))
                webView.load(data, mimeType: "application/pdf", characterEncodingName:"", baseURL: pdfURL.deletingLastPathComponent())
               view.addSubview(webView)

            }
            catch {
                // catch errors here
            }

        }
    }

}

Accessing the PDF from Asset.xcassets (Swift 4)

if let asset = NSDataAsset(name: "myPDF") {
            let url = Bundle.main.bundleURL
            let webView = WKWebView(frame: CGRect(x:20,y:20,width:view.frame.size.width-40, height:view.frame.size.height-40))
            webView.load(asset.data, mimeType: "application/pdf", characterEncodingName:"", baseURL:url)
            view.addSubview(webView)
       }
sketchyTech
  • 5,746
  • 1
  • 33
  • 56
  • The ViewController will now load with out crashing, but the PDF is not loading. I think the app may be having trouble finding the file – dannysandler Apr 16 '15 at 18:00
  • Works for me, check name of pdf – sketchyTech Apr 16 '15 at 18:02
  • Would it be possible to load the pdf file into an array, page by page, and have a page curl between the pages? – Jorgen May 27 '15 at 14:48
  • @Jorgen in OS X there's PDFKit - http://sketchytech.blogspot.co.uk/2015/05/adventures-in-pdf-swift-and-pdfkit.html - which is easy to use, but in iOS you need to look into PDF document parsing https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_pdf_scan/dq_pdf_scan.html#//apple_ref/doc/uid/TP30001066-CH220-TPXREF101 and combine it with UIPageViewController - https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPageViewControllerClassReferenceClassRef/index.html#//apple_ref/c/tdef/UIPageViewControllerTransitionStyle – sketchyTech May 27 '15 at 15:09
  • Thanks a million. At last someone that could point me in the right direction. I found a tutorial out there that made a nice page turning webView, but using html strings to fill the pages. I wanted to put a pdf document in there, but could not find a way to split the pages into an array. Now I have it! – Jorgen May 27 '15 at 15:22
  • Your both answers are correct. I check with execution time for both solution and found that the first one (using loadRequest) is faster as compared to the second one (loadData). – Jayprakash Dubey Nov 21 '16 at 07:50
  • thats pretty sweet. but how does one close the view then? – David Seek Nov 27 '16 at 01:52
  • @DavidSeek to close the view you can either remove the subview or use [about:blank](https://stackoverflow.com/a/6576304/1694526) approach – sketchyTech Jul 31 '17 at 15:23
  • Any one know how above NSData part can be done in objective c with WKWebView? – Renascent Oct 01 '20 at 12:48
5

Updated for Swift 3

import UIKit
import WebKit

class ViewController: UIViewController {

    let webView = WKWebView()

    override func viewDidLoad() {
        super.viewDidLoad()

        loadPdf()
        setupViews()
    }

    func loadPdf() {

        if let pdfUrl = Bundle.main.url(forResource: "YourPdfFileName", withExtension: "pdf", subdirectory: nil, localization: nil) {

            do {
                let data = try Data(contentsOf: pdfUrl)
                webView.load(data, mimeType: "application/pdf", characterEncodingName:"", baseURL: pdfUrl.deletingLastPathComponent())
                print("pdf file loading...")
            }
            catch {
                print("failed to open pdf")
            }
            return
        }

        print("pdf file doesn't exist")
    }

    func setupViews() {

        title = "View PDF Demo"
        view.backgroundColor = .white
        view.addSubview(webView)

        // setup AutoLayout...
        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
}

enter image description here

iAj
  • 3,787
  • 1
  • 31
  • 34
3

import WebKit

here you can load your pdf in your application

 override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.

      if let pdfURL = Bundle.main.url(forResource: "food-and-drink-menu-trafalgar-tavern", withExtension: "pdf", subdirectory: nil, localization: nil)  {
           do {
                let data = try Data(contentsOf: pdfURL)
                let webView = WKWebView(frame: CGRect(x:0,y:NavigationView.frame.size.height,width:view.frame.size.width, height:view.frame.size.height-NavigationView.frame.size.height))
                webView.load(data, mimeType: "application/pdf", characterEncodingName:"", baseURL: pdfURL.deletingLastPathComponent())
                view.addSubview(webView)

           }
           catch {
                // catch errors here
           }

      }
 }
Azharhussain Shaikh
  • 1,654
  • 14
  • 17
2

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)
    webViewPresentation.loadRequest(req as URLRequest)        
  }

Same will apply if you want to open any html file.

Anil shukla
  • 277
  • 3
  • 10
0

For Swift 3 use this code:

let url = URL(fileURLWithPath: filePath)

let urlRequest = URLRequest(url: url)

webView?.loadRequest(urlRequest)
AkBombe
  • 638
  • 4
  • 10