如何在 Swift 3 中的 UIWebView 中显示没有基础 URL 的 PDF?

How to display a PDF without a base URL in a UIWebView in Swift 3?

我想在 UIWebView. 中显示 PDF 文件我已经将其作为 Data 对象,所以我不需要 (并且不能)提供 baseURL

在Objective-C ...

...对应的方法定义如下:

- (void)loadData:(NSData *)data 
        MIMEType:(NSString *)MIMEType 
textEncodingName:(NSString *)textEncodingName 
         baseURL:(NSURL *)baseURL;

所以我可以简单地将 nil 作为 baseURL 传递,如 Apple's Text Programming Guide.

中所述

在 Swift 2.0 ...

... baseURL 参数在 load(...) 函数中不是可选的(为什么?)所以我 不得不 传递一个有效的 NSURL 对象。幸运的是,另一个 Whosebug post 中描述了一个简单的解决方法:我只是创建了一个空的 NSURL 对象。

private func showPdf(data: NSData) {
    webView.loadData(data, 
           MIMEType: "application/pdf", 
   textEncodingName: "utf-8", 
            baseURL: NSURL())
}

现在 Swift 3.0 ...

...方法签名已更改,baseURL 参数必须是 Swift URL 而不是 NSURL:

open func load(_ data: Data, 
    mimeType MIMEType: String, 
     textEncodingName: String, 
              baseURL: URL)

这打破了解决方法,因为 URL 没有空的初始值设定项,并且不可能从空字符串创建 URL,如 Swift 文档中所述:

/// Returns `nil` if a `URL` cannot be formed with the string 
/// (for example, if the string contains characters that are illegal 
/// in a URL, or is an empty string).
public init?(string: String)

所以问题是:
如何在 Swift 3 中的 UIWebView 内提供 baseURL 而加载 PDF(或任何其他 Web 内容)?

通常,如果您有数据,它是通过 URL 开始的,所以只需使用 URL。

或者我想 您可以使用应用程序包中任何内容的文件 URL 作为基础 URL

或者您可以将 URL 构造为 NSURL 并使用 as.

转换为 URL

或者将数据保存到磁盘并调用loadRequest

首先,马特的回答是正确的。似乎您几乎可以将任何 URL 用作 baseURL,因为 webview 仅将其用于 HTML 文件中的内部链接,例如。如果您加载的是不包含任何内部链接的 PDF,则该参数将被忽略。您可以将 URL(string: "http://www.whosebug.com")! 作为 baseURL 传递,它仍然有效。我真的不明白为什么 Apple 没有首先将 baseURL 设为可选,但事实就是如此。

其次,我的UIWebView没有加载PDF的原因与我问这个问题时所想的baseURL无关。事实证明,我试图在 webview 中加载的 data 对象没有正确创建。


问题:

在 Swift 3 之前,可以像这样将数据写入上下文目标:

let mutableData = CFDataCreateMutable(nil, 0)

let dataConsumer = CGDataConsumerCreateWithCFData(mutableData)
let pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, nil)

if CGPDFDocumentGetNumberOfPages(document) > 0 {
    CGPDFContextBeginPage(pdfContext, nil)
    CGContextDrawPDFPage(pdfContext, page)
    CGPDFContextEndPage(pdfContext)
}

此时 mutableData 对象已经写入并包含 PDF 页面数据。翻译成 new Swift 3 语法 如下:

let mutableData = CFDataCreateMutable(nil, 0)

let dataConsumer = CGDataConsumer(data: mutableData!)
let pdfContext = CGContext(consumer: dataConsumer!, mediaBox: &pageRect!, nil)

if (document?.numberOfPages)! > 0 {
    pdfContext?.beginPDFPage(nil)
    pdfContext?.drawPDFPage(page!)
    pdfContext?.endPDFPage()
}

但是在 pdfContext(或其等效 CGPDFContextEndPage())上调用 endPDFPage()不再将任何数据写入目标


解决方案:

你需要打电话

pdfContext?.closePDF()

这最终会将 PDF 数据写入您的上下文目标。

之后,您可以简单地按照我的问题中的描述在 webview 中加载 PDF 数据 - 无论您提供什么 baseURL