英文:
Swift code to retrieve audio file metadata is not working on some iOS devices
问题
以下是Swift代码的中文翻译:
考虑以下的Swift代码,用于检索iOS上音频文件的元数据(标题、专辑名称、艺术家、封面)。它通过给定目录中的文件进行迭代,并使用 AVAsset
提取元数据。
这段代码在运行iOS v16.3或更低版本的物理和虚拟设备上按预期工作。然而,在我的iPhone 13 Pro Max上运行iOS v16.3.1时,所有元数据都返回null。不过,歌曲的URI(songURI)正常工作(证明是我可以使用AVAudioPlayer正常播放这些歌曲的)。
我不知道是什么原因导致了这个问题。我无法在任何其他物理设备上进行测试(我没有其他设备),而且我的MacBook有点过时,所以无法运行更新的iOS版本(如16.5),因为受到Xcode和无法升级的macOS Monterey的限制。
可能的原因是什么?
do {
// 获取目录内容的URL(包括子目录的URL)
let directoryContents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
for songurl in directoryContents {
print(songurl.localizedName ?? songurl.lastPathComponent)
if isValidAudioFileExtension(songurl.pathExtension) {
let shouldStopAccessing = songurl.startAccessingSecurityScopedResource()
defer {
if shouldStopAccessing {
songurl.stopAccessingSecurityScopedResource()
}
}
let asset = AVAsset(url: songurl)
let metaData = asset.metadata
let title = metaData.first(where: {$0.commonKey == .commonKeyTitle})?.value as? String
let artist = metaData.first(where: {$0.commonKey == .commonKeyArtist})?.value as? String
let album = metaData.first(where: {$0.commonKey == .commonKeyAlbumName})?.value as? String
let playbackDuration: Double? = CMTimeGetSeconds(asset.duration)
var artwork: MPMediaItemArtwork? = nil
if let artworkdata = metaData.first(where: {$0.commonKey == .commonKeyArtwork}), let value = artworkdata.value as? Data {
artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 60, height: 60), requestHandler: { (size) -> UIImage in
return UIImage(data: value)!
})
}
do {
let bookmarkData = try songurl.bookmarkData(options: .minimalBookmark, includingResourceValuesForKeys: nil, relativeTo: nil)
var isStale = false
let bookmarkedURL = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &isStale)
print(bookmarkedURL)
let song = SongItem(
url: bookmarkedURL,
title: title ?? "Undefined Song",
artist: artist,
albumTitle: album,
playbackDuration: Int(playbackDuration ?? 0),
artwork: artwork
)
self.tracklist.append(song)
} catch {
print("Failed to create bookmark data for URL: \(error.localizedDescription)")
showToast(message: "\(error.localizedDescription)")
}
}
}
} catch {
print(error)
}
注意:我也尝试过移除安全范围访问块(startAccessingSecurityScopedResource
),但没有任何区别。
英文:
Consider the following Swift code to retrieve audio file metadata (title, album name, artist, artwork) on iOS. It iterates through files in a given directory and extracts metadata using AVAsset
This code works as expected on physical and virtual devices running iOS v16.3 or lower. However, on my iPhone 13 Pro Max running iOS v16.3.1, all metadata returns null. The songURI however, works just fine (and the proof to that is that I can play the songs normally using AVAudioPlayer using songuri
I have no idea what could be causing this. I cannot test this on any other physical device (I do not own any other devices) and also, my MacBook is a bit outdated so I cannot run newer iOS versions (such as 16.5) due to the limitation of Xcode and macOS Monterey which I cannot upgrade)
What could be the reason ?
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory(at: url,includingPropertiesForKeys: nil)
for songurl in directoryContents {
print(songurl.localizedName ?? songurl.lastPathComponent)
if isValidAudioFileExtension(songurl.pathExtension) {
let shouldStopAccessing = songurl.startAccessingSecurityScopedResource()
defer {
if shouldStopAccessing {
songurl.stopAccessingSecurityScopedResource()
}
}
let asset = AVAsset(url: songurl)
let metaData = asset.metadata
let title = metaData.first(where: {$0.commonKey == .commonKeyTitle})?.value as? String
let artist = metaData.first(where: {$0.commonKey == .commonKeyArtist})?.value as? String
let album = metaData.first(where: {$0.commonKey == .commonKeyAlbumName})?.value as? String
let playbackDuration: Double? = CMTimeGetSeconds(asset.duration)
var artwork: MPMediaItemArtwork? = nil
if let artworkdata = metaData.first(where: {$0.commonKey == .commonKeyArtwork}), let value = artworkdata.value as? Data {
artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 60, height: 60), requestHandler: { (size) -> UIImage in
return UIImage(data: value)!
})
}
do {
let bookmarkData = try songurl.bookmarkData(options: .minimalBookmark, includingResourceValuesForKeys: nil, relativeTo: nil)
var isStale = false
let bookmarkedURL = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &isStale)
print(bookmarkedURL)
let song = SongItem(
url: bookmarkedURL,
title: title ?? "Undefined Song",
artist: artist,
albumTitle: album,
playbackDuration: Int(playbackDuration ?? 0),
artwork: artwork
)
self.tracklist.append(song)
} catch {
print("Failed to create bookmark data for URL: \(error.localizedDescription)")
showToast(message: "\(error.localizedDescription)")
}
}
}
} catch {
print(error)
}
NOTE: I also tried removing the security-scoped access block (```startAccessingSecurityScopedResource``) but no difference.
答案1
得分: 0
是设备特定的错误导致了意外行为,不仅影响了媒体元数据的检索,还影响了整个AV框架。在将设备升级到iOS 16.5后,代码开始按预期工作。
英文:
Turns out that it's a device-specific bug leading to unexpected behavior, which not only affected media metadata retrieval but also the entirety of AV framework. Code began to work as expected after upgrading device to iOS 16.5.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论