Swift: 在锁定屏幕上添加 forward/backward 15 秒按钮

Swift: add forward/backward 15 seconds buttons on lock screen

我有AVAudioPlayer。我想在锁定屏幕上添加 15 秒倒带按钮,如下图所示:

但我得到的结果就像这张图片:

我的代码:

var audioPlayer: AVAudioPlayer!

override func viewDidLoad() {
    super.viewDidLoad()

    try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
    try? AVAudioSession.sharedInstance().setActive(true)
    UIApplication.shared.beginReceivingRemoteControlEvents()

    ...

    audioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
    audioPlayer.delegate = self
    audioPlayer.prepareToPlay()
    play(sender:AnyObject.self as AnyObject)
    restorePlayerCurrentTime()
}

override func remoteControlReceived(with event: UIEvent?) {
        guard let event = event else {
            print("no event\n")
            return
        }
        guard event.type == UIEventType.remoteControl else {
            print("received other event type\n")
            return
        }
        
        switch event.subtype {
        
        case UIEventSubtype.remoteControlBeginSeekingBackward:
            audioPlayer.play()
        
        case UIEventSubtype.remoteControlBeginSeekingForward:
            audioPlayer.pause()
        
        case UIEventSubtype.remoteControlPlay:
            print("received remote play\n")
            audioPlayer.play()
        case UIEventSubtype.remoteControlPause:
            print("received remote pause\n")
            audioPlayer.pause()
        
        /*case UIEventSubtype.remoteControlTogglePlayPause:
            print("received toggle\n")*/
            
        default:
            print("received \(event.subtype) which we did not process\n")
        }
    }

如何解决?

播放和停止按钮工作正常,但倒带不起作用。

我是这样做的

import MediaPlayer

func setupMediaPlayerNotificationView()  {
   
    let commandCenter = MPRemoteCommandCenter.shared()
    
commandCenter.skipForwardCommand.addTarget { [weak self] event in
    print("You Pressed skipForward")
    return .success
}

commandCenter.skipBackwardCommand.addTarget { [weak self] event in
    print("You Pressed skipBackward")
    return .success
}

}

这将为您提供跳过按钮。

调用它
    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupMediaPlayerNotificationView()
}

回答你的问题2;

您需要更新 MPNowPlayingInfoPropertyElapsedPlaybackTime 以匹配 CMTimeGetSeconds(player.currentTime() ),更新此值的最佳位置是为 KeyPath 添加观察者:“timeControlStatus”并更新 .waitingToPlaySpecifieldRate / .paused 和.playing

创建一个名为 nowPlayingInfo 的全局字典 https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter/1615903-nowplayinginfo

示例:

    nowPlayingInfo = nil
    
    nowPlayingInfo = [String: Any]()
    
    self.nowPlayingInfo?[MPMediaItemPropertyTitle] = data[0].currentTrackTitle
    self.nowPlayingInfo?[MPMediaItemPropertyArtist] = data[0].currentArtist
    self.nowPlayingInfo?[MPMediaItemPropertyAlbumTitle] = data[0].currentAlbumName
    self.nowPlayingInfo?[MPNowPlayingInfoPropertyDefaultPlaybackRate] =  NSNumber(value: 1)
    self.nowPlayingInfo?[MPMediaItemPropertyPlaybackDuration] =  CMTimeGetSeconds((player!.currentItem?.asset.duration)!)
    self.nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentTime() )
    let image = data[0].currentArtwork
    self.nowPlayingInfo?[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { (size) -> UIImage in
        return image
    })
  
    
    MPNowPlayingInfoCenter.default().nowPlayingInfo = self.nowPlayingInfo

在 timeControlStatus oberver 中更新 nowPlayingInfo 全局字典的`self.nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentTime() )

您还需要在搜索(15 秒)之前将 MPNowPlayingInfoPropertyDefaultPlaybackRate 更新为 0,然后在搜索完成后将此值设置回 1。

示例;

override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?) {
        
        guard context == &playerItemContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
        
        if keyPath == "timeControlStatus" {

            let statusNumber = change?[.newKey] as? NSNumber
                // Switch over status value
                switch statusNumber {
                case 0:
                        //print("paused")
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyDefaultPlaybackRate] =  NSNumber(value: 0)
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentTime() )
                        MPNowPlayingInfoCenter.default().nowPlayingInfo = self.nowPlayingInfo
                case 1:
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyDefaultPlaybackRate] =  NSNumber(value: 0)
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentTime() )
                        MPNowPlayingInfoCenter.default().nowPlayingInfo = self.nowPlayingInfo
                case 2:
                        //print("playing")
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyDefaultPlaybackRate] =  NSNumber(value: 1)
                        self.nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentTime() )
                        MPNowPlayingInfoCenter.default().nowPlayingInfo = self.nowPlayingInfo
    
                        }
                default:
                        fatalError() //this is never called in this scenario
                }
        }

    }