1

How to get a display folder name and an App icon for an URL returned by UIDocumentPickerViewController?

Here is an example of my Swift playground code and some debug print output below:

if let newUrl = urlFromPicker {

    // 1 
    print("[DEBUG] newUrl: [\(newUrl)]")

    // 2 
    let res = try! newUrl.promisedItemResourceValues(forKeys: [.ubiquitousItemContainerDisplayNameKey])
    if let displayName1 = res.ubiquitousItemContainerDisplayName {
        print("[DEBUG] newUrl displayName1: [\(displayName1)]")
    }

    // 3 
    if let displayName2 = FileManager.default.displayName(atPath: newUrl.absoluteString).removingPercentEncoding {
        print("[DEBUG] newUrl displayName2: [\(displayName2)]")
    }
}

CASE 1: Open a document folder of some App from iCloud Drive (for this example PDF Viewer):

[DEBUG] newUrl: [file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~pspdfkit~viewer/Documents/]
[DEBUG] newUrl displayName1: [PDF Viewer]
[DEBUG] newUrl displayName2: [Documents]

CASE 2: Open a sub-folder Dir of the same document directory from iCloud Drive:

[DEBUG] newUrl: [file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~pspdfkit~viewer/Documents/Dir/]
[DEBUG] newUrl displayName1: [PDF Viewer]
[DEBUG] newUrl displayName2: [Dir]

As I have few documents form the same PDF Viewer App also on my device in On My iPhone, here are same two cases (directory/sub-directory) for local documents:

CASE 3: Open a local document folder of PDF Viewer from On My iPhone:

[DEBUG] newUrl: [file:///private/var/mobile/Containers/Data/Application/XXXXXXXX-YYYY-ZZZZ-AAAA-BBBBBBBBBBBB/Documents/]
[DEBUG] newUrl displayName2: [Documents]

CASE 4: Local sub-folder:

[DEBUG] newUrl: [file:///private/var/mobile/Containers/Data/Application/XXXXXXXX-YYYY-ZZZZ-AAAA-BBBBBBBBBBBB/Documents/Subdir/]
[DEBUG] newUrl displayName2: [Subdir]

QUESTIONS:

  • As it is possible to see URL's method promisedItemResourceValues(forKeys:) with .ubiquitousItemContainerDisplayNameKey doesn't work for the local files. How to get a name of the App which Documents folder is in use for local files (same result as displayName1 output in case 1/2 for iCloud)?
  • Is it possible to get an App's icon same as it shows the UIDocumentPickerViewController?

P.S. I know that by using a private API as LSApplicationWorkspace I can use an extracted bundle Id of the App (XXXXXXXX-YYYY-ZZZZ-AAAA-BBBBBBBBBBBB from the URL) in order to get App's name and icon, but a need a public way to do it in order to submit my App to the AppStore later.

Thanks in advance for your attention and help.

vaa
  • 164
  • 15

1 Answers1

0

Answering the second part of the question: the following fetches the app icon (iOS 15 and earlier):

func documentPicker(_ controller: UIViewControllerType, didPickDocumentsAt urls: [URL]) {
    guard let url = urls.first else { return }
    guard url.startAccessingSecurityScopedResource() else {
        print("unable to access security scoped resource: \(url.absoluteString)")
        return
    }
    defer { url.stopAccessingSecurityScopedResource() }

    let fileCoord = NSFileCoordinator.init()
    fileCoord.coordinate(readingItemAt: url, 
                         options: .immediatelyAvailableMetadataOnly, 
                         error: nil) { (url) in

        if let res = try? url.resourceValues(forKeys: [.thumbnailDictionaryKey]),
           let dict = res.thumbnailDictionary,
           let image = dict[.NSThumbnail1024x1024SizeKey] {
               print("\(String(describing: image))")
           } else {
               print("no image found")
           }
    }
}

An image result is conditional on an association with an app (in iCloud Drive or On My iPad/iPhone).

MichaelR
  • 1,681
  • 15
  • 28
  • MichaelR's suggestion is great and still works on iOS 16. However, reliance on deprecated features is worrisome. Does anyone know how to do the same using QuickLook (as suggested by the rather unhelpful warning " 'thumbnailDictionaryKey' was deprecated in iOS 15.0: Use the QuickLookThumbnailing framework and extension point instead"). I am somewhat familiar with that framework, but I have no idea of how to go about it or if it is indeed possible. Can anyone offer any pointers? – Torrontés Aug 02 '23 at 17:32