Add 'PDF Services' symlink in ~/Library directory in SwiftUI macOS Catalyst application

I am trying to port my sandboxed macOS app completely over to iOS using a Catalyst target. In my macOS app, I use 'SwiftySandboxFileAccess' package to add a symlink to '~/Library/PDF Services' so that the 'share to my app' menuItem shows up in the macOS Print Panel (in the PDF menu). It is critical for the function of my app to have this work on macOS.

In the Catalyst target, I am having problems gaining access to '~/Library'. I have tried having the user select the folder, but the picker always returns 'canceled'. I have a test app that illustrates this.

The test app tries to coax the user into selecting the library folder and then it is supposed to bookmark the location, but I am unable to get this far.

As an aside, macOS should probably automatically add an entry to the Print Panel when the app includes PDF as a document type in XCode; it would save a lot of hassle and avoid having to go outside of the sandbox. However, I cannot wait for that. Hopefully someone can help.

Download Test App from iCloud

(If you have problems downloading the file, it might be because of some iCloud share setting that I am not aware of. Just tell me and I'll figure something out.)

Answered by DTS Engineer in 870183022

As an aside, macOS should probably automatically add an entry to the Print Panel when the app includes PDF as a document type in Xcode; it would save a lot of hassle and avoid having to go outside of the sandbox. However, I cannot wait for that. Hopefully, someone can help.

So, I took a look at your sample and found two different problems:

(1)
As originally configured, your project had "User Selected File" to "Read", which caused UIDocumentPickerViewController to always cancel. Changing that to "Read/Write" got it working.

(2)
You're checking for the correct folder by comparing the value the user selected to the value returned by:

guard var libraryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first else {

The problem is that, in a sandboxed app, that API returns the app container path, NOT the user’s actual directories. So your check ends up comparing this:

~/Library/Containers/<bundle id>/Data/Library/

To the user’s true selection:

~/Library/

...inadvertently failing the correct path.

As a bonus note, the open panel automatically converts the container path you originally passed in into the ~/Library/ path, further confusing the entire process. FYI, you can get the user’s true home directory path using getpwuid as described here, which you'd then need to manually append "/Library/" onto for the final check.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

As an aside, macOS should probably automatically add an entry to the Print Panel when the app includes PDF as a document type in Xcode; it would save a lot of hassle and avoid having to go outside of the sandbox. However, I cannot wait for that. Hopefully, someone can help.

So, I took a look at your sample and found two different problems:

(1)
As originally configured, your project had "User Selected File" to "Read", which caused UIDocumentPickerViewController to always cancel. Changing that to "Read/Write" got it working.

(2)
You're checking for the correct folder by comparing the value the user selected to the value returned by:

guard var libraryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first else {

The problem is that, in a sandboxed app, that API returns the app container path, NOT the user’s actual directories. So your check ends up comparing this:

~/Library/Containers/<bundle id>/Data/Library/

To the user’s true selection:

~/Library/

...inadvertently failing the correct path.

As a bonus note, the open panel automatically converts the container path you originally passed in into the ~/Library/ path, further confusing the entire process. FYI, you can get the user’s true home directory path using getpwuid as described here, which you'd then need to manually append "/Library/" onto for the final check.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Add 'PDF Services' symlink in ~/Library directory in SwiftUI macOS Catalyst application
 
 
Q