So we have a media player in our SwiftUI app, and all the buttons go to the media function to play, pause , rewind etc.
One feature people are requesting is the ability to airplay to other devices. I know they can do this via the Lock Screen and the notification bar, but wondering what function do I need to add to the media-player function to allow me to add a button to my swiftUI.
I am wondering what function code do I need to add to my core mediaplayer.swift file that I can link a button too.
Post
Replies
Boosts
Views
Activity
So I am trying to add two buttons to the view of my SwiftUI app that will allow a user to fast forward and rewind the audio clip.
I already have it working on the Lock Screen and notification bar, but in the app I can't figure out how to link two buttons to these actions.
I am wondering if anyone is able to assist.
In the MusicCore.swift I have the following
func setupRemoteTransportControls() {
// Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared()
let changePlaybackPositionCommand = commandCenter.changePlaybackPositionCommand
changePlaybackPositionCommand.isEnabled = true
changePlaybackPositionCommand.addTarget { event in
let seconds = (event as? MPChangePlaybackPositionCommandEvent)?.positionTime ?? 0
let time = CMTime(seconds: seconds, preferredTimescale: 1)
self.player?.seek(to: time)
return .success
}
let skipBackwardCommand = commandCenter.skipBackwardCommand
if(MusicPlayer.mediatype == "podcast")
{
skipBackwardCommand.isEnabled = true
skipBackwardCommand.preferredIntervals = [NSNumber(value: 10)]
skipBackwardCommand.addTarget(handler: skipBackward)
}
else{
skipBackwardCommand.isEnabled = false
}
let skipForwardCommand = commandCenter.skipForwardCommand
if(MusicPlayer.mediatype == "podcast")
{
skipForwardCommand.isEnabled = true
skipForwardCommand.preferredIntervals = [NSNumber(value: 30)]
}
else{
skipForwardCommand.isEnabled = false
}
skipForwardCommand.addTarget(handler: skipForward)
// Add handler for Play Command
commandCenter.playCommand.addTarget { [unowned self] event in
if self.player?.rate == 0.0 {
self.player?.play()
return .success
}
return .commandFailed
}
// Add handler for Pause Command
commandCenter.pauseCommand.addTarget { [unowned self] event in
if self.player?.rate == 1.0 {
self.player?.pause()
MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Int(Double((self.player?.currentTime().seconds)!))
return .success
}
return .commandFailed
}
func skipBackward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
//self.player?.seek(to: CMTimeMakeWithSeconds(CMTimeGetSeconds((self.player?.currentTime())!).advanced(by: -30), preferredTimescale: 1))
// print(CMTimeGetSeconds((self.player?.currentTime())!)) //Output: 42
//print(event.interval)
//self.player!.seek(to: CMTimeMakeWithSeconds(CMTimeGetSeconds((self.player?.currentTime())!).advanced(by: -30), preferredTimescale: 1))
let currentTime = self.player?.currentTime()
self.player?.seek(to: CMTime(seconds: currentTime!.seconds - 10, preferredTimescale: 1), completionHandler: { isCompleted in
if isCompleted {
MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Int(Double((self.player?.currentTime().seconds)!))
}
})
return .success
}
func skipForward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
//self.player?.seek(to: CMTimeMakeWithSeconds(CMTimeGetSeconds((self.player?.currentTime())!).advanced(by: 30), preferredTimescale: 1))
let currentTime = self.player?.currentTime()
self.player?.seek(to: CMTime(seconds: currentTime!.seconds + 30, preferredTimescale: 1), completionHandler: { isCompleted in
if isCompleted {
MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Int(Double((self.player?.currentTime().seconds)!))
}
})
return .success
}
}
But how can I call that from inside a View?
So I was able to get my list to work, and it changes the station a user is listening to.
However I am wondering how do I get it so that it moves the screen to a now playing screen. As when I go to the CarPlay Dashboard and click now playing I can see it does get the now playing information from my app.
I have included my CarPlaySceneDelegate.swift file so people can see how I got it to work. As there is not a lot of documentation around how to get CarPlay apps to work.
I tried
let nowplayingTemplate = CPNowPlayingTemplate.shared
interfaceController.pushTemplate(nowplayingTemplate, animated: true, completion: true)
But that produced an error, wondering how do I get it to transition to the now playing template once a list is clicked/pressed
CarPlaySceneDelegate.swift - https://developer.apple.com/forums/content/attachment/c88f48d7-d54b-4865-bad6-aefbb3cf5a2f
So I am using the sample code that was provided by Apple in 2020, however it seems that the code is no longer correct.
As I am getting the following error:
Cannot call value of non-function type 'CPNowPlayingTemplate'
Remove '()'
However when I do remove it the app fires up fine, minus the now playing information.
I am wondering what do I need to do to get the now playing information which my iOS app does display, to send over to the CarPlay screen.
I was told - "All you need is this template and then apple does everything in the background."
Clearly that's wrong, because Apple would never make something be so easy.
So I know I am going to have to add buttons, album art extra extra. But I don't know how to go about this, as I normally use SwiftUI.
import Foundation
import CarPlay
class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController) {
if #available(iOS 14.0, *) {
let nowPlayingTemplate = CPNowPlayingTemplate.shared
let rateButton = CPNowPlayingPlaybackRateButton() {_ in
// Change the playback rate!
}
nowPlayingTemplate.updateNowPlayingButtons([rateButton])
} else {
// Fallback on earlier versions
}
}
}
Side note: the sooner Apple allows SwiftUI to take over this the better.
So key questions:
How to print song information on this screen
How to add pause and play button.
I have included my MediaPlayer.swift file so you can see I use MPNowPlayingInfoCenter
MediaPlayer.swift - https://developer.apple.com/forums/content/attachment/0caa76cd-53d3-439c-9a86-37703dc20348
First time trying to get CarPlay added to my app, we are a radio/podcast app, and while on the developer provisioning I have the necessary permissions. I can't seem to get my entitlements.plist to be valid.
?xml version="1.0" encoding="UTF-8"?
!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"
plist version="1.0"
dict
keycom.apple.developer.carplay-audio/key
true/
dict/
/plist
Is their something I am missing?
The error I am getting is
"/Users/russellharrower/Apps/vscroll/DRN1.xcodeproj Entitlements file is not a plist or corrupt in target DRN1: "/Users/russellharrower/Apps/vscroll/Entitlements.plist"
"
Hi I am wondering what do I need to do, to allow my TVML app to continue playing music in the background?
I have tried to add background mode in info.plist but that has not work.
Any ideas would help.