2

编辑:在底部添加了附加信息

我有一个基于文档的沙盒应用程序,可以将用户选择的 quicktime 电影加载到 AVPlayer 中,并且一切正常。

现在我正在升级代码,以便它将使用安全范围的书签来获取 URL,而不仅仅是存储 URL 字符串,以便持久存储将允许在重新启动应用程序时加载电影。创建书签时,它存储在托管对象的数据变量中。

出于某种原因,这破坏了 AVPlayer。虽然我已经从用户选择的 URL 创建了一个书签,并且可以在应用程序重新启动时从书签中解析 URL,但电影没有正确加载到 AVPlayer 中,我不知道为什么......我已经确认从书签解析的 URL 确实指向电影文件。

我还为项目添加了适当的权利。

这是我的代码:

用户选择要加载的电影并创建书签的功能

 @IBAction func loadMovie(_ sender: Any) {

    let openPanel = NSOpenPanel()
    openPanel.title = "Select Video File To Import"
    openPanel.allowedFileTypes = ["mov", "avi", "mp4"]

    openPanel.begin { (result: NSApplication.ModalResponse) -> Void in
        if result == NSApplication.ModalResponse.OK {

            self.movieURL = openPanel.url
            self.player = AVPlayer.init(url: self.movieURL!)

            self.setupMovie()

            if self.loadedMovieDatabase.count > 0 {
                print("Movie Object Exists. Adding URL String")
                self.loadedMovieDatabase[0].urlString = String(describing: self.movieURL!)
            } else {
                print("No Movie Object Exists Yet.  Creating one and adding URL String")
                let document = NSDocumentController.shared.currentDocument as! NSPersistentDocument
                let myManagedObjectContext = document.managedObjectContext!
                let newMovie = NSEntityDescription.insertNewObject(forEntityName: "Movie", into: myManagedObjectContext) as! MovieMO
                self.loadedMovieDatabase.append(newMovie)
                self.loadedMovieDatabase[0].urlString = String(describing: self.movieURL!)
            }

            // create Security-Scoped bookmark - Added 2/1/18
            do {
                try self.loadedMovieDatabase[0].bookmark = (self.movieURL?.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil))!
            } catch {
                print("Can't create security bookmark!")
            }

        }
    }

}

将书签解析为 URL 并加载电影的功能

       // initialize AVPlayer with URL stored in coreData movie object if it exists and is a valid path
    if loadedMovieDatabase.count > 0 {
        // initialize with saved movie path if it is valid (from security bookmark data)
        // let myURL = URL(string: loadedMovieDatabase[0].urlString!) <- replaced with new code below
        print("Loading URL from Bookmark")
        var urlResult = false
        var myURL : URL
        do {
            try myURL = URL.init(resolvingBookmarkData: loadedMovieDatabase[0].bookmark, bookmarkDataIsStale: &urlResult)!
            print("URL Loaded from Bookmark")
            print("URL is", myURL)
            let isSecuredURL = myURL.startAccessingSecurityScopedResource()
            print("IsSecured = ", isSecuredURL)
            player = AVPlayer.init(url: myURL)
            print("Setting Up Movie")
            setupMovie()
        } catch {
            // No Data in bookmark so load default ColorBars movie instead
            print("No Security Bookmark Available. Reverting to Default Color Bars")
            let myURL = URL(string: initialMoviePath)
            player = AVPlayer.init(url: myURL!)
            setupMovie()
        }
    } else {
        // load default ColorBars movie instead
        print("Nothing was loaded so just set up a new document.")
        let myURL = URL(string: initialMoviePath)
        player = AVPlayer.init(url: myURL!)
        setupMovie()
    }

我是安全范围书签的新手,所以我希望这对于以前使用过它们的任何人来说都是显而易见的。

我想知道这是否有问题:

let isSecuredURL = myURL.startAccessingSecurityScopedResource()

也许我叫错了?有时我发现 Apple 的文档含糊不清……任何见解都将不胜感激!

编辑:

我相信我知道为什么会这样,但我不知道如何解决它......

myURL.startAccessingSecurityScopedResource()

总是返回 FALSE... 根据文档,这意味着它不起作用。此外,虽然电影文件位于我的桌面上,但已解决的 URL 如下所示(这可能是正常的,我不知道。):

file:///Users/me/Library/Containers/myapp/Data/Desktop/sample_on_desktop.mov

苹果文档提到了文档范围不能使用系统中的文件(又名“/Library”)的事实,但是我的权利设置为使用应用程序范围的书签,并且我的书签是使用 relativeURL 的 nil 标志创建的: 所以这应该不是问题。

4

1 回答 1

6

I just stumbled upon the answer accidentally...

For starters, when I was resolving the URL, I was not using the method which allows you to include OPTIONS, so my URL was resolved WITHOUT the security-scope. My original code to resolve was:

try myURL = URL.init(resolvingBookmarkData: loadedMovieDatabase[0].bookmark, bookmarkDataIsStable: &urlResult)!

When I should have been using the version with options here:

try myURL = URL.init(resolvingBookmarkData: loadedMovieDatabase[0].bookmark, Options: URL.bookmarkResolutionOptions.withSecurityScope, relativeTo: nil, bookmarkDataIsStable: &urlResult)!

Basically, I used the first init option Xcode presented in the predictive list with the words "resolvingBookmarkData:" when I should have looked further down the list. (This is how I found my error.)

NOTE also that it's important to use...

URL.bookmarkResolutionOptions.withSecurityScope

and not

URL.bookmarkCreationOptions.withSecurityScope

...when you're resolving your URL or it doesn't appear to work correctly.

Thus ends my frustration with this problem :) I hope this explanation might help others facing this problem!

于 2018-02-03T16:18:38.040 回答