MPMediaPickerController 黑屏,各种错误,正确的 Info.plist 文件(iOS 13.1.3)

MPMediaPickerController blank screen, various errors, proper Info.plist file (iOS 13.1.3)

我正在尝试让用户从他们的音乐库中选择一首歌曲。所以,问题是:MPMediaPickerController 显示白屏并在全新安装应用程序后且仅在用户授予权限后锁定应用程序。退出应用程序并重新启动它不会重现错误(可能是因为已经授予了权限)。删除应用程序并重新安装会重现错误。

这是我初始化选择器的方法(我也尝试在视图控制器上分配 属性):

let picker = MPMediaPickerController(mediaTypes: .music)
picker.allowsPickingMultipleItems = false               // I've tried commenting this out
picker.popoverPresentationController?.sourceView = cell // I've tried commenting this out
picker.delegate = self                                  // I've tried commenting this out
picker.prompt = "Choose a song"                         // I've tried commenting this out
self.present(picker, animated: true, completion: nil)

这是我的 Info.plist 文件中的相关行:

<key>NSAppleMusicUsageDescription</key>
    <string>Use tracks from your iTunes library as wakeup sounds</string>

在控制台中,我收到以下错误:

[MediaLibrary] SQLite error 14 detected while opening database '/var/mobile/Media/iTunes_Control/iTunes/MediaLibrary.sqlitedb'
[MediaLibrary] DISK IO ERROR: attempting to close and re-open connection for recovery.
[MediaLibrary] [_handleDiskIOError] checking database consistency
[Service] Failed to obtain service proxy to perform integrity check. err=Error Domain=NSCocoaErrorDomain Code=4097 "connection to service on pid 0 named com.apple.medialibraryd.xpc" UserInfo={NSDebugDescription=connection to service on pid 0 named com.apple.medialibraryd.xpc} There was an error waiting for a reply from the media library service. Error Domain=NSCocoaErrorDomain Code=4097 "connection to service on pid 0 named com.apple.medialibraryd.xpc" UserInfo={NSDebugDescription=connection to service on pid 0 named com.apple.medialibraryd.xpc}
[MediaLibrary] [_handleDiskIOError] failed to re-open database connection
[MediaLibrary] [_handleDiskIOError] FAILED TO HANDLE DISK IO ERROR
[MediaLibrary] [_handleDiskIOError] SHM file not found—unable to unlink
[MediaLibrary] [ML3DatabaseConnection] Unable to open database connection to path /var/mobile/Media/iTunes_Control/iTunes/MediaLibrary.sqlitedb. unable to open database file
[Service] Could not attempt recovery at path: /var/mobile/Media/iTunes_Control/iTunes/MediaLibrary.sqlitedb There was an error waiting for a reply from the media library service. Error Domain=NSCocoaErrorDomain Code=4097 "connection to service on pid 0 named com.apple.medialibraryd.xpc" UserInfo={NSDebugDescription=connection to service on pid 0 named com.apple.medialibraryd.xpc}
[xpc.exceptions] <NSXPCConnection: 0x281a5f3c0> connection to service on pid 466 named com.apple.Music.MediaPicker.viewservice: Exception caught during decoding of received selector remoteMediaPickerDidPickMediaItems:, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
<NSInvocation: 0x283203a00>
return value: {v} void
target: {@} 0x0
selector: {:} null
argument 2: {@} 0x0

Exception: Could not open database file at /var/mobile/Media/iTunes_Control/iTunes/MediaLibrary.sqlitedb (errno = 1)

我猜? SQLite 在不同的线程中存在一些竞争条件同步问题,这只是在等待用户授予权限时出现的问题。这甚至可以在我这边修复吗?

我希望不要白屏死机!有什么建议吗?

可能在过去,您可以在不首先请求用户并获得用户授权的情况下展示媒体选择器,但在 iOS13 中,情况已不再如此。在显示媒体选择器之前,您必须明确确保您已获得授权:

let status = MPMediaLibrary.authorizationStatus()
switch status {
case .authorized:
    // ok to present the picker
case .notDetermined:
    MPMediaLibrary.requestAuthorization() { status in
        if status == .authorized {
            // get on main thread, ok to present the picker
// ...

如果您在尚未获得授权的情况下展示选择器,它将如您所述那样冻结。

需要Info.plist条目,正如您所描述的,但仅此是不够的。在显示选择器之前,您需要 Info.plist 条目和用户的许可。没有前者,你会崩溃。如果没有后者,您将得到冻结的白屏。两者兼得,万事大吉。

对我来说,选择的答案不是问题,尽管肯定需要授权和 Info.plist。我最初在 ViewDidLoad 中设置了 MPMediaPickerController,然后在我的 IBAction 函数中显示了视图控制器。有时它会工作,其他时候我得到黑屏。

查看 Apple 文档后,所有代码实际上都应该在 IBAction 中,包括设置委托,否则将不会调用委托函数。

Displaying a Media Picker from Your App

@IBAction func selectSong(_ sender: UIButton) {

    let picker = MPMediaPickerController(mediaTypes: .music)
    picker.allowsPickingMultipleItems = false
    picker.popoverPresentationController?.sourceView = sender
    picker.delegate = self
    self.present(picker, animated: true, completion: nil)
}