Why Does CarPlay Crash In Real Car?

Viewed 292

I have an audio app and have implemented CarPlay, I've followed this guide to add CarPlay support: https://blog.fethica.com/add-carplay-support-to-swiftradio/#

The app uses the com.apple.developer.playable-content entitlement and Media Player framework, which as far as I know, has been the only way to add CarPlay to audio apps on iOS 13 and below, but is still backwards compatible with iOS 14 (despite there being a new carplay audio framework for iOS 14). All my CarPlay logic is written in an extension of my main AppDelegate (could this be problematic?)

In the simulator, everything has been working fine and the audio plays in the external simulated car display. But my team tested the app in a real car and the application crashes immediately when opened from the car display.

I have the crash log here when tested on iPhone 11 Pro on iOS 14.4:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001b88d13cc
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [27455]
Triggered by Thread:  5

Thread 0 name:
Thread 0:
0   libsystem_kernel.dylib          0x00000001d6aa6f5c __ulock_wait + 8
1   libdispatch.dylib               0x00000001a8746794 _dlock_wait + 56 (lock.c:326)
2   libdispatch.dylib               0x00000001a87466c0 _dispatch_once_wait + 124 (lock.c:382)
3   UIKitCore                       0x00000001ab1080f8 -[_UIApplicationConfigurationLoader _loadInitializationContext] + 152 (once.h:84)
4   UIKitCore                       0x00000001ab108444 -[_UIApplicationConfigurationLoader applicationInitializationContext] + 32 (_UIApplicationConfigurationLoader.m:161)
5   UIKitCore                       0x00000001ab0ef05c -[_UIScreenInitialDisplayConfigurationLoader initialDisplayContext] + 180 (UIScreen.m:371)
6   UIKitCore                       0x00000001ab0ef348 +[UIScreen initialize] + 128 (UIScreen.m:626)
7   libobjc.A.dylib                 0x00000001bdb67c58 CALLING_SOME_+initialize_METHOD + 24 (objc-initialize.mm:384)
8   libobjc.A.dylib                 0x00000001bdb6e318 initializeNonMetaClass + 716 (objc-initialize.mm:554)
9   libobjc.A.dylib                 0x00000001bdb6f910 initializeAndMaybeRelock(objc_class*, objc_object*, mutex_tt<false>&, bool) + 280 (objc-runtime-new.mm:2221)
10  libobjc.A.dylib                 0x00000001bdb7e498 lookUpImpOrForward + 956 (objc-runtime-new.mm:2237)
11  libobjc.A.dylib                 0x00000001bdb68524 _objc_msgSend_uncached + 68
12  UIKitCore                       0x00000001ab33ef48 -[_UIRemoteKeyboards keyboardWindow] + 52 (_UIRemoteKeyboards.m:2036)
13  UIKitCore                       0x00000001ab33cf6c -[_UIRemoteKeyboards allowedToShowKeyboard] + 96 (_UIRemoteKeyboards.m:1588)
14  UIKitCore                       0x00000001ab33bda8 -[_UIRemoteKeyboards checkConnection] + 64 (_UIRemoteKeyboards.m:1315)
15  UIKitCore                       0x00000001ab338b60 -[_UIRemoteKeyboards init] + 156 (_UIRemoteKeyboards.m:797)
16  UIKitCore                       0x00000001ab338ab4 __43+[_UIRemoteKeyboards sharedRemoteKeyboards]_block_invoke + 20 (_UIRemoteKeyboards.m:785)
17  libdispatch.dylib               0x00000001a8745db0 _dispatch_client_callout + 20 (object.m:559)
18  libdispatch.dylib               0x00000001a87475c8 _dispatch_once_callout + 32 (once.c:52)
19  UIKitCore                       0x00000001ab338a9c +[_UIRemoteKeyboards sharedRemoteKeyboards] + 176 (once.h:84)
20  UIKitCore                       0x00000001ab50ccac _UIApplicationMainPreparations + 1348 (UIApplication.m:4644)
21  UIKitCore                       0x00000001ab50c740 UIApplicationMain + 140 (UIApplication.m:4704)
22  MyAppName                       0x000000010458fb04 main + 68 (UITextField+Extension.swift:22)
23  libdyld.dylib                   0x00000001a87866b0 start + 4

Thread 1:
0   libsystem_pthread.dylib         0x00000001f4608764 start_wqthread + 0

Thread 2:
0   libsystem_pthread.dylib         0x00000001f4608764 start_wqthread + 0

Thread 3 name:
Thread 3:
0   libsystem_kernel.dylib          0x00000001d6a822d0 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x00000001d6a81660 mach_msg + 76 (mach_msg.c:103)
2   libdispatch.dylib               0x00000001a875e888 _dispatch_mach_send_and_wait_for_reply + 528 (mach.c:812)
3   libdispatch.dylib               0x00000001a875ec24 dispatch_mach_send_with_result_and_wait_for_reply + 56 (mach.c:1998)
4   libxpc.dylib                    0x00000001f4626e68 xpc_connection_send_message_with_reply_sync + 240 (connection.c:848)
5   BoardServices                   0x00000001c2599958 -[BSXPCServiceConnectionMessage _sendSynchronously:] + 332 (BSXPCServiceConnectionMessage.m:129)
6   BoardServices                   0x00000001c259a2cc -[BSXPCServiceConnectionMessage sendSynchronouslyWithError:] + 256 (BSXPCServiceConnectionMessage.m:182)
7   BoardServices                   0x00000001c2584afc __71+[BSXPCServiceConnectionProxy createImplementationOfProtocol:forClass:]_block_invoke + 824 (BSXPCServiceConnectionProxy.m:274)
8   UIKitServices                   0x00000001acb7fc6c -[UISApplicationSupportClient applicationInitializationContextWithParameters:] + 272 (UISApplicationSupportClient.m:77)
9   UIKitCore                       0x00000001ab108278 __63-[_UIApplicationConfigurationLoader _loadInitializationContext]_block_invoke_2 + 228 (_UIApplicationConfigurationLoader.m:135)
10  UIKitCore                       0x00000001ab108188 __UIAPPLICATION_IS_LOADING_INITIALIZATION_INFO_FROM_THE_SYSTEM__ + 28 (_UIApplicationConfigurationLoader.m:30)
11  UIKitCore                       0x00000001ab108160 __63-[_UIApplicationConfigurationLoader _loadInitializationContext]_block_invoke + 100 (_UIApplicationConfigurationLoader.m:106)
12  libdispatch.dylib               0x00000001a8745db0 _dispatch_client_callout + 20 (object.m:559)
13  libdispatch.dylib               0x00000001a87475c8 _dispatch_once_callout + 32 (once.c:52)
14  UIKitCore                       0x00000001ab1080f8 -[_UIApplicationConfigurationLoader _loadInitializationContext] + 152 (once.h:84)
15  UIKitCore                       0x00000001ab108408 __70-[_UIApplicationConfigurationLoader startPreloadInitializationContext]_block_invoke + 28 (_UIApplicationConfigurationLoader.m:154)
16  libdispatch.dylib               0x00000001a874424c _dispatch_call_block_and_release + 32 (init.c:1454)
17  libdispatch.dylib               0x00000001a8745db0 _dispatch_client_callout + 20 (object.m:559)
18  libdispatch.dylib               0x00000001a8756a68 _dispatch_root_queue_drain + 656 (inline_internal.h:2548)
19  libdispatch.dylib               0x00000001a8757120 _dispatch_worker_thread2 + 116 (queue.c:6777)
20  libsystem_pthread.dylib         0x00000001f46017d8 _pthread_wqthread + 216 (pthread.c:2223)
21  libsystem_pthread.dylib         0x00000001f460876c start_wqthread + 8

Thread 4:
0   libsystem_pthread.dylib         0x00000001f4608764 start_wqthread + 0

Thread 5 name:
Thread 5 Crashed:
0   FrontBoardServices              0x00000001b88d13cc -[FBSSceneParameters initWithSpecification:] + 228 (FBSSceneParameters.m:34)
1   FrontBoardServices              0x00000001b88d1320 -[FBSSceneParameters initWithSpecification:] + 56 (FBSSceneParameters.m:34)
2   FrontBoardServices              0x00000001b88d1dd8 -[FBSSceneParameters initWithXPCDictionary:] + 128 (FBSSceneParameters.m:150)
3   BaseBoard                       0x00000001ad165af4 _BSXPCDecodeObject + 1892 (BSXPCCoder.m:583)
4   BaseBoard                       0x00000001ad1639c0 _BSXPCDecodeObjectForKey + 268 (BSXPCCoder.m:459)
5   BoardServices                   0x00000001c2585f30 +[BSXPCServiceConnectionProxy decodeArguments:outArgs:fromMessage:forConnection:] + 1608 (BSXPCServiceConnectionProxy.m:592)
6   BoardServices                   0x00000001c2583ab0 -[BSXPCServiceConnectionProxy invokeMessage:onTarget:] + 276 (BSXPCServiceConnectionProxy.m:342)
7   BoardServices                   0x00000001c258a994 __63-[BSXPCServiceConnectionEventHandler connection:handleMessage:]_block_invoke + 536 (BSXPCServiceConnectionEventHandler.m:261)
8   BoardServices                   0x00000001c25a0284 BSXPCServiceConnectionExecuteCallOut + 316 (BSXPCServiceConnection.m:1049)
9   BoardServices                   0x00000001c258a708 -[BSXPCServiceConnectionEventHandler connection:handleMessage:] + 172 (BSXPCServiceConnectionEventHandler.m:250)
10  BoardServices                   0x00000001c259f668 -[BSXPCServiceConnection _connection_handleMessage:fromPeer:withHandoff:] + 572 (BSXPCServiceConnection.m:834)
11  libdispatch.dylib               0x00000001a874424c _dispatch_call_block_and_release + 32 (init.c:1454)
12  libdispatch.dylib               0x00000001a8745db0 _dispatch_client_callout + 20 (object.m:559)
13  libdispatch.dylib               0x00000001a874d10c _dispatch_lane_serial_drain + 580 (inline_internal.h:2548)
14  libdispatch.dylib               0x00000001a874dc90 _dispatch_lane_invoke + 460 (queue.c:3862)
15  libdispatch.dylib               0x00000001a874cfd8 _dispatch_lane_serial_drain + 272 (inline_internal.h:2589)
16  libdispatch.dylib               0x00000001a874dc90 _dispatch_lane_invoke + 460 (queue.c:3862)
17  libdispatch.dylib               0x00000001a8757d78 _dispatch_workloop_worker_thread + 708 (queue.c:6601)
18  libsystem_pthread.dylib         0x00000001f4601814 _pthread_wqthread + 276 (pthread.c:2210)
19  libsystem_pthread.dylib         0x00000001f460876c start_wqthread + 8

Thread 6 name:
Thread 6:
0   libsystem_kernel.dylib          0x00000001d6a822d0 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x00000001d6a81660 mach_msg + 76 (mach_msg.c:103)
2   IOKit                           0x00000001b3b68340 io_hideventsystem_copy_property + 172 (IOHIDEventSystemMIGUser.c:3056)
3   IOKit                           0x00000001b3b22c60 IOHIDEventSystemClientCopyProperty + 128 (IOHIDEventSystemClient.c:1097)
4   IOKit                           0x00000001b3b22354 __IOHIDEventSystemClientRefresh + 1148 (IOHIDEventSystemClient.c:539)
5   IOKit                           0x00000001b3b230cc IOHIDEventSystemClientCreateWithType + 856 (IOHIDEventSystemClient.c:749)
6   BackBoardServices               0x00000001ac0dda88 ___getHIDEventSystemClient_block_invoke + 288 (BKSHIDEvent.m:93)
7   libdispatch.dylib               0x00000001a8745db0 _dispatch_client_callout + 20 (object.m:559)
8   libdispatch.dylib               0x00000001a87475c8 _dispatch_once_callout + 32 (once.c:52)
9   BackBoardServices               0x00000001ac0dd964 BKSHIDEventRegisterEventCallbackOnRunLoop + 152 (once.h:84)
10  UIKitCore                       0x00000001ab5babe4 -[UIEventFetcher threadMain] + 416 (UIEventFetcher.m:720)
11  Foundation                      0x00000001a9ee7a34 __NSThread__start__ + 864 (NSThread.m:724)
12  libsystem_pthread.dylib         0x00000001f45ffcb0 _pthread_start + 320 (pthread.c:881)
13  libsystem_pthread.dylib         0x00000001f4608778 thread_start + 8

Thread 7:
0   libsystem_pthread.dylib         0x00000001f4608764 start_wqthread + 0

Thread 5 crashed with ARM Thread State (64-bit):
    x0: 0x000000020ba16880   x1: 0x000000020ba16880   x2: 0x0000000000000000   x3: 0x00000000000008fd
    x4: 0x0000000000000000   x5: 0x00000001bdb9873e   x6: 0x000000000000006e   x7: 0x0000000000000fb0
    x8: 0x85f836c8121c001f   x9: 0x85f836c8121c001f  x10: 0x0000000000005403  x11: 0x0000000281a71540
   x12: 0x00000000000000aa  x13: 0x0000000000000001  x14: 0x00000000000000ac  x15: 0x0000000000000182
   x16: 0x00000002c6d90f88  x17: 0x0000000208ac3dc8  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x0000000281472eb0  x21: 0x0000000000000000  x22: 0x0000000000000000  x23: 0x00000001f75f31f5
   x24: 0x000000020ba160d8  x25: 0x0000000000000000  x26: 0x00000001f7ff3288  x27: 0x000000020ba160b0
   x28: 0x0000000000000000   fp: 0x000000016bb2e130   lr: 0x86106081b88d1320
    sp: 0x000000016bb2e100   pc: 0x00000001b88d13cc cpsr: 0x60000000
   esr: 0xf2000000  Address size fault

What could be causing the app to crash in a real car but work fine in the simulator? Here is part of my AppDelegate where I call a function to setup carplay:

import UIKit
import AVFoundation
import AVKit
import GoogleInteractiveMediaAds
import MediaPlayer
import GoogleMobileAds
import UserNotifications
import WebKit
import SafariServices
import Hero
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    static let reachable = "Reachable"
    static let unReachable = "UnReachable"
    let reachability = try! Reachability()
    var iOSStream: String?
    var preRolladUrl: String?
    var window: UIWindow?
    var adType: String?
    var adServer: String?
    var adFeed: String?
    var miniPlayer: PlayerPopupControlViewController?
    var selectedStation: Players!
    
    // CarPlay
    var playableContentManager: MPPlayableContentManager?
    let carplayPlaylist = CarPlayPlaylist()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        UINavigationBar.appearance().barTintColor = UIColor.black
        UINavigationBar.appearance().tintColor = UIColor.black
        UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
        UINavigationBar.appearance().isTranslucent = false
        
        if UserDefaults.standard.object(forKey: UserDefaultsConstants.resumeRadioInBackground) == nil {
            UserDefaults.standard.set(true, forKey: UserDefaultsConstants.resumeRadioInBackground)
            UserDefaults.standard.synchronize()
        }
        self.setupBaseURL()
        // Override point for customization after application launch.
        self.startObservingReachability()
        
        UIApplication.shared.beginReceivingRemoteControlEvents()
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            
        } catch  {
            AppLogger.error(error)
        }
        UNUserNotificationCenter.current().delegate = self
        UserDefaults.standard.set(false, forKey: UserDefaultsConstants.isMiniPlayerDisplayed)
        UserDefaults.standard.synchronize()
        SettingsDataManager.sharedInstance.selectedStation = SettingsDataManager.sharedInstance.getSelectedStationFromUserDefaults()
        registerForPushNotifications()
        
        setupCarPlay()
        
        FirebaseApp.configure()
        
        return true
    }
    

AppDelegate+CarPlay.swift

import Foundation
import MediaPlayer

extension AppDelegate{
    func setupCarPlay() {
        playableContentManager = MPPlayableContentManager.shared()
        
        playableContentManager?.delegate = self
        playableContentManager?.dataSource = self
        
        self.carplayPlaylist.setupCommandCenter()
    }
}

extension AppDelegate: MPPlayableContentDelegate {
    
    // This is called when user selects a 'playable' item (MPContentItem)
    func playableContentManager(_ contentManager: MPPlayableContentManager, initiatePlaybackOfContentItemAt indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void) {
        
        self.carplayPlaylist.playerData = SettingsDataManager.sharedInstance.playerData ?? []
//        guard let miniPlayer = self.miniPlayer else {return}
        
        DispatchQueue.main.async {
            // App should play music either from the radio stream or podcasts
            if indexPath.count == 2 {
                
                if(indexPath[0] == 0) {
                    // When user selects playable item within Radio tab
                    if (self.carplayPlaylist.playerData.count > 0) {
                        if let stationURL = URL(string: self.carplayPlaylist.playerData[indexPath[1]].streams?.iOS ?? "") {
                            self.carplayPlaylist.play(playURL: stationURL)
                            SettingsDataManager.sharedInstance.selectedStation = self.carplayPlaylist.playerData[indexPath[1]]
                        }
                    }
                }
                
            }
            
            completionHandler(nil)
            
            // Workaround to make the Now Playing working on the simulator:
            #if targetEnvironment(simulator)
                UIApplication.shared.endReceivingRemoteControlEvents()
                UIApplication.shared.beginReceivingRemoteControlEvents()
            #endif
        }
    }
    
    func beginLoadingChildItems(at indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void) {
        carplayPlaylist.load { error in
            completionHandler(error)
        }
    }
}

extension AppDelegate: MPPlayableContentDataSource {
    
    func numberOfChildItems(at indexPath: IndexPath) -> Int {
        if indexPath.indices.count == 0 {
            // This returns the number of tabs at the top of the CarPlay display
            return 1 // changed to 1 to allow only radio streams
            
        } else if indexPath.indices.count == 1 {
            // This returns the number of rows within each tab
            if indexPath[0] == 0 {
                // Radio Stations rows
                return carplayPlaylist.playerData.count
            } else {
                // Podcasts feed rows
         
                return 0 // Return 0 while podcasts are disabled
            }
            

        } else {
            return 0
        }
        
    }
    
    func contentItem(at indexPath: IndexPath) -> MPContentItem? {
        let playerData = carplayPlaylist.playerData
//        let podCastsFeeds = carplayPlaylist.podCastSettings?.podcasts_feeds

        if indexPath.count == 1 {
            // Tab section
            let item: MPContentItem
            if (indexPath[0] == 0) {
                // Radio Stations Tab Section
                
                item = MPContentItem(identifier: "Radio")
                item.title = "Radio"
                item.artwork = MPMediaItemArtwork(boundsSize: #imageLiteral(resourceName: "NavIcon-Broadcast").size, requestHandler: { _ -> UIImage in
                    return #imageLiteral(resourceName: "NavIcon-Broadcast")
                })
            } else {
                // Podcast Tab Section
                
                item = MPContentItem(identifier: "Podcasts")
                item.title = "Podcasts"
                item.artwork = MPMediaItemArtwork(boundsSize: #imageLiteral(resourceName: "NavIcon-Podcasts").size, requestHandler: { _ -> UIImage in
                    return #imageLiteral(resourceName: "NavIcon-Podcasts")
                })
            }
            item.isContainer = true
            item.isPlayable = false
            
            return item
            
        } else if indexPath.count == 2, indexPath.item < playerData.count, indexPath[0] == 0 {
            // Radio station items section
            
            let station = playerData[indexPath.item]
            let item = MPContentItem(identifier: "\(station.name)")
            item.title = station.name
            item.subtitle = station.call_letters
            item.isPlayable = true
            item.isStreamingContent = true
            item.downloadImageAndSetArtwork(from: station.logo ?? "", completion: {})
            
            return item
            
        } else {
            return nil
        }
    }
    
}

///extension to downlaod the image from the api
extension MPContentItem {
    func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
        URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
    }
    
    func downloadImageAndSetArtwork(from address: String, completion: @escaping () -> Void) {
        let defaultImage = #imageLiteral(resourceName: "NavIcon-Music")
        let defaultArtwork = MPMediaItemArtwork(boundsSize: defaultImage.size, requestHandler: { _ -> UIImage in
            return defaultImage
        })
        
        guard let url = URL(string: address) else {
            self.artwork = defaultArtwork
            return
        }
        getData(from: url) {
            data, response, error in
            guard let data = data, error == nil else {
                AppLogger.error("Image Error")
                self.artwork = defaultArtwork
                return
            }
            DispatchQueue.main.async() {
                guard let image = UIImage(data: data) else {
                    self.artwork = defaultArtwork
                    return
                }
                
                self.artwork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { _ -> UIImage in
                    return image
                })

                completion()
            }
        }
        
    }
    
}

CarPlayPlaylist.swift

import Foundation
//import UIKit
import AVKit
import MediaPlayer


class CarPlayPlaylist {

    let radioPlayer = FRadioPlayer.shared
    var playerData: [Players] = []
    var podCastItemsArray: [[Item]] = []
    var podCastSettings: Podcast_settings?
    var podCastFeedNameArray:[String] = []
    var isFromCarPlay: Bool = false
    var playButtonStatus: Bool = false
    var currentPodcastItem: Item?
    
    func load(_ completion: @escaping (Error?) -> Void) {

//        if (self.podCastFeedNameArray.count == 0 && self.podCastItemsArray.count == 0) {
//            getPodcastDataFromSettingsDataManager()
//
//            let podcastFeedsCount = self.podCastSettings?.podcasts_feeds?.count ?? 0
//            podCastItemsArray = [[Item]](repeating: [], count: podcastFeedsCount)
//        }
        
        self.playerData = SettingsDataManager.sharedInstance.playerData ?? []
        completion(nil)
    }
    
    
    func play (playURL: URL) {
            isFromCarPlay = true
            self.radioPlayer.radioURL = playURL
            self.radioPlayer.play()
    }
    
    func setupCommandCenter () {

        MPNowPlayingInfoCenter.default().nowPlayingInfo = [MPMediaItemPropertyTitle: "Current Playing song"]
        MPNowPlayingInfoCenter.default().nowPlayingInfo![MPNowPlayingInfoPropertyPlaybackRate] = 0.0

        let commandCenter = MPRemoteCommandCenter.shared()
        commandCenter.playCommand.isEnabled = true
        commandCenter.pauseCommand.isEnabled = true
        commandCenter.playCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
            self?.radioPlayer.play()
//            NotificationCenter.default.post(name: NSNotification.Name(rawValue: NotificationCenterConstants.carPlayDidPlay), object: nil, userInfo: nil)
            
            return .success
        }
        commandCenter.pauseCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
            self?.radioPlayer.pause()
//            NotificationCenter.default.post(name: NSNotification.Name(rawValue: NotificationCenterConstants.carPlayDidPause), object: nil, userInfo: nil)

            return .success
        }
    }
    
}

extension CarPlayPlaylist {
    func addCommandCenterNotificationObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(commandCenterDidPlay), name: NSNotification.Name(rawValue: NotificationCenterConstants.commandCenterDidPlay), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(commandCenterDidPause), name: NSNotification.Name(rawValue: NotificationCenterConstants.commandCenterDidPause), object: nil)
    }
    
    func removeCommandCenterObservers() {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationCenterConstants.commandCenterDidPlay), object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationCenterConstants.commandCenterDidPause), object: nil)
    }
    
    @objc func commandCenterDidPlay() {
        // Playback rate should change the playback status
        MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 0.0

    }
    
    @objc func commandCenterDidPause() {
        // Playback rate should change the playback status
        MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 1.0

    }
}
0 Answers
Related