Sandbox - 访问带有副文件的主文件 Access sidecar files in a Mac sandboxed app

1. 访问带有副文件的主文件

比如访问视频 .mp4 文件时,同时应该有权限访问对应的字幕文件

参考:Access sidecar files in a Mac sandboxed app
Question:
I need to access sidecar XMP files in a document-based photo editor application. The image files are the documents, and I need to access the sidecar XMP file when the user open and save an image document.
Is it possible to access sidecar files (such as XMP) in a sandboxed document-based application?
I understand that it’s not possible by default, but what is the minimal temporary security exception that is needed to allow that?
Is there a workaround for this without using temporary exception?
Note that it’s impossible to guarantee the the image files document-scoped bookmarks to the side-cars (as they might created by other apps on different platforms), so this solution won’t work.

Answer:
While this question is old I thought I would share my solution. You can add an entry to your CFBundleDocumentTypes section
in your apps info.plist with the NSIsRelatedItemType set to true. Then your sandboxed app will be able to open any file the
user gives permission to with the same name but has the extensions that you list.
Here is an example for an xmp sidecar file:

<key>CFBundleDocumentTypeskey>
<array>
    <dict>
        <key>CFBundleTypeExtensionskey>
        <array>
            <string>xmpstring>
        array>
        <key>CFBundleTypeNamekey>
        <string>XMP sidecarstring>
        <key>CFBundleTypeRolekey>
        <string>Nonestring>
        <key>NSIsRelatedItemTypekey>
        <true/>
    dict>
array>

测试代码:

// 通过NSOpenPanel打开源文件: /Users/victor/Desktop/SanboxTestFolder_2/1.txt
// 可以访问到源文件的data
let contents = FileManager.default.contents(atPath: textField.stringValue)

logTextView.string += String.init(describing: contents) + "\n\n"

失败: 但是即使我在Info.plist 中添加了上面的内容,还是不能访问到 /Users/victor/Desktop/SanboxTestFolder_2/1.xmp文件的内容

继续搜索答案:“Related item” file not written due to Sandbox
翻译:自定义class 实现协议 NSFilePresenter

  • presentedItemURL: sidecar 文件路径,和主文件路径只是extension不一样
  • primaryPresentedItemURL: 主文件路径
  1. right after creating an istance of an object implementing the protocol NSFilePresenter I have to register it calling the class method “addFilePresenter” of NSFileCoordinator like this “NSFileCoordinator.addFilePresenter(filePresenter)”
  2. in the info.plist in the doc type flagged as NSIsRelatedItemType=true the key “CFBundleTypeRole” must be "Editor" (and not “None” as it was in my case)

代码:

import Foundation
class ZWFilePresenter: NSObject {
    private var queue: OperationQueue
    private var sourceURL: URL
    @available(*, unavailable)
    override init() {
        fatalError()
    }
    
    init(sourceURL: URL) {
        self.sourceURL = sourceURL
        self.queue = .init()
        super.init()
        NSFileCoordinator.addFilePresenter(self)
    }
    
    deinit {
        NSFileCoordinator.removeFilePresenter(self)
    }
    
    func saveSidecarFileTest(content: String) {
        guard let sidecarURL = self.presentedItemURL else {
            return
        }
        let coordinator = NSFileCoordinator.init(filePresenter: self)
        var error: NSError?
        coordinator.coordinate(writingItemAt: sidecarURL, error: &error) { url in
            print("--- url:\(url)")
            
            do {
                try content.write(to: sidecarURL, atomically: true, encoding: .unicode)
            } catch let writeErr {
                print(writeErr)
            }
        }
        
    }

    func loadSidecarFile() -> String? {
        guard let sidecarURL = self.presentedItemURL else {
            return nil
        }
        let coordinator = NSFileCoordinator.init(filePresenter: self)
        var error: NSError?
        var result: String?
        coordinator.coordinate(readingItemAt: sidecarURL, error: &error) { url in
            print("--- url:\(url)")
            do {
                try result = String.init(contentsOf: url, encoding: .unicode)
            } catch let doErr {
                print(doErr)
            }
        }
        return result
    }
    
    
}

extension ZWFilePresenter: NSFilePresenter {
    var presentedItemURL: URL? {
        let ret = sourceURL.deletingPathExtension().appendingPathExtension("xmp")
        return ret
       
    }
    var primaryPresentedItemURL: URL? {
        return sourceURL
    }
    var presentedItemOperationQueue: OperationQueue {
        return self.queue
    }
    
    
}

你可能感兴趣的:(macOS开发,macos,swift,开发语言)