3

How to create a Swift URL object from Data (byte array) without writing the bytes to disk?

Background:

I need to use a file viewer (such as QuickLook) to view secure files in my iOS (Swift) application but I do not want to write the files to disk. I know Apple does disk encryption but that is not an option for us. Is there any way to use a file viewer (such as QuickLook) with a file that is purely in memory?

Alec
  • 666
  • 8
  • 23
  • Have you tried a data URL? – zneak Feb 12 '19 at 01:29
  • Whats wrong about using a file url located your app temporary directory? – Leo Dabus Feb 12 '19 at 02:17
  • possible duplicate of https://stackoverflow.com/a/47141577/2303865 – Leo Dabus Feb 12 '19 at 02:19
  • You can't point an URL to memory. You can only have URL pointed to local or remote file resources. – Leo Dabus Feb 12 '19 at 02:24
  • @LeoDabus We don't want the user to be able to get at these files and take them outside the app. I believe that is possible if we use the app temporary directory. – Alec Feb 12 '19 at 02:42
  • @zneak I don't think I am familiar with a data URL. Can you provide more information? – Alec Feb 12 '19 at 02:43
  • https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy/encrypting_your_app_s_files and about where to put your files https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW2 – Leo Dabus Feb 12 '19 at 02:46

4 Answers4

1

There's a way using URI scheme (data:MIME;base64):
(there's no safety in this code sample, force unwrap and such).

let data = //... get image data
let base64String = data!.base64EncodedString()

let imgURIPath = "data:application/octet-stream;base64,\(base64String)"

// More clear with format?
//let imgURIPath = String(format: "data:application/octet-stream;base64,%@", base64String)


// We need a dummy base URL since URL(string:) is validating the URL
// and will return nil if there's no valid base
let baseURL = URL(string: "https://www.dummyURL.com")!

let uri = URL(string: imgURIPath, relativeTo: baseURL)!

// Test
let imageFromURI = try? UIImage(contentsOf: uri)
bauerMusic
  • 5,470
  • 5
  • 38
  • 53
0

If your document is a PDF, you can initialize a PDFDocument directly from Data and display it in a PDFView, but I can't guarantee that PDFDocument doesn't ultimately write the data to disk temporarily. However, I don't think you can get a URL without writing to disk.

  • that is a good solution for PDFs but ideally we would like to be able to handle all the basic file types (office documents, text, image, mac office). That is why we were initially looking into QuickLook – Alec Feb 12 '19 at 02:40
0

That is not possible with the standard iOS Quick Look. Store your files in some temporary directory with class A encryption, and if you do not want them to exit your app, use a managed enterprise app, which lets you make sure your data doesn’t exit the managed world. File a bug if you want Quick Look to support NSItemProvider.

Thomas Deniau
  • 2,488
  • 1
  • 15
  • 15
0

The solution that we decided to go with was UIWebView. We were able to use this call:

webView.load(data: Data, mimeType: String, textEncodingName: String, baseURL: URL)

to display pdf, docx, xlsx, pptx, pdf, jpeg, png,... in a UIView within our app. This call allowed us to pass the Data directly in without having to save it to disk first.

Note: UIWebView is deprecated and we tried to use WKWebViewKit. It has the same method signature but we could not get the files to display properly. Every time the result was just a bunch of random nonsense characters.

Alec
  • 666
  • 8
  • 23