Link app object to file on disk with metadata

373 Views Asked by At

Following this topic : iOS PDFkit cannot add custom attribute to pdf document

My app is using PDFKit to save files I'm trying to set custom key metadata to PDFDocument I save on the device. The object in my app ('Test') has two important properties :

  • id: a UUID to be able to retrieve the file on disk (the linked file on disk URL is this_UUID.jpg).
  • name: a human-readable string set by the user.

This cause some problems :

  1. the file name is a UUID not human readable, so it's bad user experience.
  2. If the user renames the file, the app won't be able to get the file.

So the id is to have a human-readable label for the file. So when the user opens the File app he can find it easily. And add metadata with the id so my app can retrieve it even if renamed. Looks like a nice solution right?

// First I create my own attribute
fileprivate extension PDFDocumentAttribute {
    static let testId = PDFDocumentAttribute(rawValue: "com.sc.testID")
}

// Then I set the news attributes before saving the file, in the 'test' class
func setDocument(pdf: PDFDocument) {
        let fileURL = self.getPDFDocumentURL()
        print("the metadata is \(pdf.documentAttributes)") // print an empty dictionary 
        pdf.documentAttributes?[PDFDocumentAttribute.testId] = self.id
        pdf.documentAttributes?[PDFDocumentAttribute.titleAttribute] = self.name // I suppose the ddisplay name of the document ? It's not, so what is that ?
        print("the metadata is now \(pdf.documentAttributes)") // both are printed, it looks ok

        //pdf.write(to: fileURL) // I tested this one too, same issues
        
        let data = pdf.dataRepresentation()
        do {
            try data?.write(to: fileURL, options: .completeFileProtection)
        } catch {
            print(error.localizedDescription)
        }
    }

From here it looks ok, when I want to retrieve the pdf document I will check in the folder the id of each doc and return the doc when id match. But the problem is when I get the documentAttributes the attribute 'testId' isn't in. Note the native title, is set correctly. So I could get the id from there but that looks pretty inappropriate

//still in 'Test' class
 func getPDFDocument() -> PDFDocument? {
        // get all docs in the folder ad check metadata for each
        let fileManager = FileManager.default
        let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
        do {
            let fileURLs = try fileManager.contentsOfDirectory(at: SchoolTest.getSubjectFolderURL(subject: self.subject!), includingPropertiesForKeys: nil)
            for url in fileURLs {
                print("the doc attributes are : \(PDFDocument(url: url)?.documentAttributes)") // contain title and others preset by Apple but not my custom 'testId'
                if let doc = PDFDocument(url: url), doc.documentAttributes?[PDFDocumentAttribute.titleAttribute/*testId*/] as? String == self.documentName {
                    return doc // this work temporary
                }
            }
        } catch {
            print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
        }
        return nil
    }

Display name: Currently, the display name/label displayed in the File app is the file name (from URL). This can cause problems too because if two 'Test' have the same name, their linked file gonna have the same URL. So when the most recent one will be saved on disk it will overwrite the other. That's a problem I don't have when using the 'Test' id property for the file URL. If I could set a display name for the file and keep the URL with the UUID that should resolve the problem. Directories have the same localizing issue, I have named them with English but Apple native directories are localized. A localized name could be nice for user experience. After hours of research, I can't find a way to localize or apply a display name to my files/directories.

// I tried that without positive result
var url = fileURL as NSURL
try url.setResourceValue("localized label", forKey: .localizedLabelKey)
print("localized name is \(try url.resourceValues(forKeys: [.localizedLabelKey]))")
let newURL = url as URL
try data?.write(to: newURL, options: .completeFileProtection)

Am I doing something badly? How should we do when adding custom metada to a file?

0

There are 0 best solutions below