AVURLAsset not playable

Hi.


I'm programming an app (MacOS, not iOS) in which I want to play external mp3 files. The path to the file and some information I need are stocked in a tableView. When I add the file to the tableView, through a NSOpenPanel, there is no problem, I can play my mp3 without any problem. If I close the app, and open it again, the tableView has its content, with the paths to the files, but, then, the AVURLAsset is classified not playable. I can't have any information about the length of the sound, etc, and can't play it...


let url = URL.init(fileURLWithPath: filePath, isDirectory: false)
let fileManager = FileManager.default
let soundAsset: AVURLAsset = AVURLAsset(url: url)
print("Path : \(soundAsset.url.path)")
print("Sound is playable : \(soundAsset.isPlayable)")
print("File at this path exists : \(fileManager.fileExists(atPath: sound.fileUrl))")

The path is correct, the soundAsset is not playable, the file exists...

What am I missing? Any suggestion? Thanks...

Accepted Reply

The problem is (I presume from your description) that your app is sandboxed, which means you can't just access any file you want. For files in arbitrary places, you can only access them when the user gives your app "permission" via a NSOpenPanel or a NSSavePanel.


To begin with, you should stop using all APIs based on paths, and use only URL-based APIs. That's because the "permission" given to you by the user is associated with the URLs that you get after the NSOpenPanel or NSSavePanel returns a result.


Those URLs are called "security scoped", which means they enable access to the files they point to. This security scoping lasts only as long as your app is running. If you need to access the files again after your app relaunches, you must save "security scoped bookmarks", which you create from security scoped URLs. You can store these bookmarks somewhere, then resolve them when your app relaunches (or, in your case, perhaps when they're chosen from the table view).


Information about creating security scoped bookmarks is in the documentation page for URLs:


https://developer.apple.com/documentation/foundation/url


(Look for the "Creating Bookmarks" section.) Once you've resolved a bookmark into a security scoped bookmark, you can re-activate the scoping with this:


https://developer.apple.com/documentation/foundation/url/1779698-startaccessingsecurityscopedreso


Keep in mind that you don't have to do any resolution or start accessing during the original execution where you get the URLs, only when relaunched.


Also — very important — do not try to create a new security scoped bookmark from a reconstituted URL. You can only create the bookmark successfully from the original URL. So, save the bookmark once, then reconstitute multiple times.

Replies

The problem is (I presume from your description) that your app is sandboxed, which means you can't just access any file you want. For files in arbitrary places, you can only access them when the user gives your app "permission" via a NSOpenPanel or a NSSavePanel.


To begin with, you should stop using all APIs based on paths, and use only URL-based APIs. That's because the "permission" given to you by the user is associated with the URLs that you get after the NSOpenPanel or NSSavePanel returns a result.


Those URLs are called "security scoped", which means they enable access to the files they point to. This security scoping lasts only as long as your app is running. If you need to access the files again after your app relaunches, you must save "security scoped bookmarks", which you create from security scoped URLs. You can store these bookmarks somewhere, then resolve them when your app relaunches (or, in your case, perhaps when they're chosen from the table view).


Information about creating security scoped bookmarks is in the documentation page for URLs:


https://developer.apple.com/documentation/foundation/url


(Look for the "Creating Bookmarks" section.) Once you've resolved a bookmark into a security scoped bookmark, you can re-activate the scoping with this:


https://developer.apple.com/documentation/foundation/url/1779698-startaccessingsecurityscopedreso


Keep in mind that you don't have to do any resolution or start accessing during the original execution where you get the URLs, only when relaunched.


Also — very important — do not try to create a new security scoped bookmark from a reconstituted URL. You can only create the bookmark successfully from the original URL. So, save the bookmark once, then reconstitute multiple times.

Thanks a lot. This soved my problem.