SwiftUI - Open a file via a fileURL

I am writing a SwiftUI-based app and have the following requirements:

  1. Use a file browser (such as UIDocumentPickerViewController) to find an arbitrary file (not one that the application knows how to open) which is external to the app bundle but local to the device the app is running on - either in local storage or on an iCloud drive.

  2. Save this location.

  3. At a later time, open this file. The file should open in an app that knows how to open it or in a browser.

  4. Do all of the above in a way that works with multiple devices (synced via CloudKit/SwiftData). For example, select a file on my iCloud drive on my Mac, then save it (using CloudKit/SwiftData) and open it on an iPad that has an app that can open it.

I am addressing requirement #1 using UIDocumentPickerViewController wrapped with a UIViewControllerRepresentable. It returns a security-scoped URL. (Note: this worries me because of requirement #4).

I use the Bookmark API to implement requirement #2.

For requirement #3, I load the bookmark data, convert it back to a security-scoped URL and either

	Link("Open", destination: url)

or

	@Environment(\.openURL) private var openURL
	if url.startAccessingSecurityScopedResource() {
		defer { url.stopAccessingSecurityScopedResource() }
		openURL(url) { accepted in 
			// do something here
		}
	}

Both of these implementations fail. The Link call responds with "invalid input parameters" (Error Domain=NSOSStatusErrorDomain, Code=-50), the openURL() call just returns false.

So, my questions are:

  • Since it appears the Link and openURL work for internet URLs, but not for security-scoped file URLs, how to I cause a document to be opened (using an application which knows how to open it or a browser).
  • Since UIDocumentPickerViewController is returning a security-scoped URL, how can I make this work on a different device than the one on which the user selected the document? (Assuming, of course, that we are talking about a document that is on an iCloud drive that both devices have access to).

Accepted Reply

I can’t help you with with the SwiftUI side of this (#3) but I don’t think it’s possible to achieve your cross-platform requirement (#4). iOS and macOS have a very different bookmark implementations. Notably, iOS doesn’t support security-scoped bookmarks per se [1]. Rather, iOS has a completely different approach for implementing the same functionality [2].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] The .withSecurityScope option is macOS only.

[2] My understanding is that the logical equivalent to macOS’s security scope is stored externally by the system.

Replies

I can’t help you with with the SwiftUI side of this (#3) but I don’t think it’s possible to achieve your cross-platform requirement (#4). iOS and macOS have a very different bookmark implementations. Notably, iOS doesn’t support security-scoped bookmarks per se [1]. Rather, iOS has a completely different approach for implementing the same functionality [2].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] The .withSecurityScope option is macOS only.

[2] My understanding is that the logical equivalent to macOS’s security scope is stored externally by the system.

Thank you, Quinn. I was sort of afraid of that, because the security-scoped URL includes device-specific information (a UUID-based directory name).

And it gets even worse, because it appears at openURL only works with external (https ??) URLs, not file URLs. (I'm going to file that as a bug report next...) So it looks like I'm going to have to re-evaluate the requirements of my app (and offer a less-capable product as a result).