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.
So I don't understand why the media controller works fine on iPhone iOS13 yet as soon as i run the same code on iPad the media controllers do not show up on the lock screen of the iPad.I hace search github to find an iPad radio station app that does show now playing information on iPad lock screens however it seems to be that there is none.I have made my code open source because I need you help to solve this issue. Apple wont approve of our app until we fix this bug - yet it's an Apple system bug i believe not a code issue bug.https://github.com/redimongo/DRN1https://stackoverflow.com/questions/59436760/ipad-media-controls/59462880#59462880