swiftsimulatorios14uttype

Swift: Can not get mime type form UTType from file extension .pkpass


I am writing a method to get the MIME type from given file extension:

    private class func mime(from utType: UTType) -> String? {
        let mimeType: String

        if let preferredMIMEType = utType.preferredMIMEType {
            mimeType = preferredMIMEType
        } else {
           return nil
        }

        return mimeType
    }

    public class func convertToMime(fileExtension: String) -> String? {
        var utType: UTType? = UTType(filenameExtension: fileExtension)

            
        var mimeType: String?
        if let utType = utType {
            mimeType = mime(from: utType)
        }
                        
        return mimeType
    }

The test passes for txt and mp4 types, but not pkpass.

    func testThatConvertToMimeConvertsFileExtensions() {
        XCTAssertEqual(UTIHelper.convertToMime(fileExtension: "pkpass"), "application/vnd.apple.pkpass")
        XCTAssertEqual(UTIHelper.convertToMime(fileExtension: "txt"), "text/plain")
        XCTAssertEqual(UTIHelper.convertToMime(fileExtension: "mp4"), "video/mp4")
    }

I tried to print the info of UTType and got these:

print(utType.description)
print(utType.tags)
print(utType.preferredMIMEType)


com.apple.pkpass-data
[public.filename-extension: ["pkpass"]]
nil

Solution

  • The default argument for the second parameter of the UTType initialiser that you are using is .data:

    init?(filenameExtension: String, conformingTo supertype: UTType = .data)
    

    So this finds a UTType that is a subtype of public.data. However, The UTType that you want (com.apple.pkpass) does not have public.data as a super type (i.e. does not conform to public.data). In fact, a .pkpass file is sort of like a .framework file - it's a bundle/package of things. (Try extracting its contents with The Unarchiver!) This is why the initialiser does not find the correct UTType.

    Learn more about the hierarchies of UTTypes here.

    You can use this other initialiser, and pass nil to the conformingTo argument. This will find you any UTType that has the specified file name:

    let type = UTType(tag: "pkpass", tagClass: .filenameExtension, conformingTo: nil)
    print(type.preferredMIMEType ?? "nil") // application/vnd.apple.pkpass
    

    Also note the warning in the docs:

    Don’t attempt to derive the type of a file system object based solely on its filename extension.