AVPlayer / AVAudioPlayer - 从 iCloud Drive 播放音频文件 URL(在模拟器上工作但不是 iPhone)+(OSStatus 错误 -54。)

AVPlayer / AVAudioPlayer - Play audio fileURL from iCloud Drive (work on simulator but not iPhone) + (OSStatus error -54.)

我正在制作音频播放器。 使用 .fileImporter.

从 iCloud Drive 导入文件

我得到的文件 URL 看起来像这样:file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/_Storage/Audio-books/%D0%91%D1%80%D0%B5%D0%BD%D0%B4%D1%8F%D1%82%D0%B8%D0%BD%D0%B0/Audiobook.mp3"

然后我将它传递给音频播放器(试过 AVPlayer 和 AVAudioPlayer)。 都适用于 iOS 模拟器 。 导入后在设备上出现错误:操作无法完成。 (OSStatus 错误 -54。)

我知道这是可能的,名为 Evermusic 的应用程序与设备上的文件完全相同。

非常感谢您的帮助,非常感谢任何建议,我真的被困住了。 为了将来参考该项目的回购:https://github.com/yaosamo/AudioPlayer

您需要使用 startAccessingSecurityScopedResource 才能获得对这些文件的读取权限。请参阅文档:

除了@jnpdx的回答还想补充一些细节,还有我的解决方案示例。

几个核心的东西

✅ 对于我的应用程序,如果您需要访问受保护的音频,则需要使用 startAccessingSecurityScopedResource()

❌ 你不能简单地存储 URL 并在以后使用它,事实上你根本不存储文件 URL。您需要在 URL 上使用所谓的 bookmarkData() 并存储它。所以稍后你可以恢复 URL

Watch Apple pres here

我是这样导入文件的:

        .fileImporter(isPresented: $presentImporter, allowedContentTypes: [.mp3]) { result in
        switch result {
        case .success(let url):
            // Start accessing secured url
            let StartAccess = url.startAccessingSecurityScopedResource()
            defer {
                // Must stop accessing once stop using
                if StartAccess {
                    url.stopAccessingSecurityScopedResource()
                }
            }
            // Creating new book
            let newBook = Book(context: viewContext)
            let _ = print("---- Access Granted?", url.startAccessingSecurityScopedResource())
            // Getting bookmarkData of the URL
            let bookmarkData = try? url.bookmarkData()
            newBook.name = "\(url.lastPathComponent)"
            // Save bookmarkURL into CoreData
            newBook.urldata = bookmarkData
            // Specifiying parent item in CoreData
            newBook.origin = playlist.self
            try? viewContext.save()
    
        case .failure(let error):
            print(error)
        }
    }

玩家检索 URL:

func Audioplayer(bookmarkData: Data) {

// Restore security scoped bookmark
var bookmarkDataIsStale = false
let playNow = try? URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &bookmarkDataIsStale)

do {
    player = try AVAudioPlayer(contentsOf: playNow!)
    // Delegate listen when audio is finished
    player?.delegate = del
    NotificationCenter.default.addObserver(forName: NSNotification.Name("ended"), object: nil, queue: .main) { (_) in
        player?.stop()
        ended = true
        let _ = print("---- Book has ended ----")
    }
} catch let error {
    print("Player Error", error.localizedDescription)
}
player?.prepareToPlay()
player?.play()
}

谢谢你,这里是repo on git.