Merge pull request #106 from rasmuslos/master

Show "now playing" on lock screen & in control center
This commit is contained in:
advplyr 2022-03-06 09:25:09 -06:00 committed by GitHub
commit f5088d0384
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 42 deletions

View file

@ -7,6 +7,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.beginReceivingRemoteControlEvents()
// Override point for customization after application launch. // Override point for customization after application launch.
return true return true
} }

View file

@ -3,18 +3,13 @@ import Capacitor
import MediaPlayer import MediaPlayer
import AVKit import AVKit
extension UIImage {
extension UIImageView { func imageWith(newSize: CGSize) -> UIImage {
public func imageFromUrl(urlString: String) { let renderer = UIGraphicsImageRenderer(size: newSize)
if let url = NSURL(string: urlString) { let image = renderer.image { _ in
let request = NSURLRequest(url: url as URL) self.draw(in: CGRect.init(origin: CGPoint.zero, size: newSize))
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main) {
(response: URLResponse?, data: Data?, error: Error?) -> Void in
if let imageData = data as Data? {
self.image = UIImage(data: imageData)
}
}
} }
return image.withRenderingMode(self.renderingMode)
} }
} }
@ -24,7 +19,7 @@ struct Audiobook {
var title = "No Title" var title = "No Title"
var author = "Unknown" var author = "Unknown"
var playWhenReady = false var playWhenReady = false
var startTime = 0 var startTime = 0.0
var cover = "" var cover = ""
var duration = 0 var duration = 0
var series = "" var series = ""
@ -74,7 +69,7 @@ public class MyNativeAudio: CAPPlugin {
title: call.getString("title") ?? "No Title", title: call.getString("title") ?? "No Title",
author: call.getString("author") ?? "Unknown", author: call.getString("author") ?? "Unknown",
playWhenReady: call.getBool("playWhenReady", false), playWhenReady: call.getBool("playWhenReady", false),
startTime: call.getInt("startTime") ?? 0, startTime: Double(call.getString("startTime") ?? "0") ?? 0.0,
cover: call.getString("cover") ?? "", cover: call.getString("cover") ?? "",
duration: call.getInt("duration") ?? 0, duration: call.getInt("duration") ?? 0,
series: call.getString("series") ?? "", series: call.getString("series") ?? "",
@ -98,7 +93,7 @@ public class MyNativeAudio: CAPPlugin {
// For play in background // For play in background
do { do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay]) try AVAudioSession.sharedInstance().setCategory(.playback, mode: .spokenAudio, options: [.allowAirPlay])
NSLog("[TEST] Playback OK") NSLog("[TEST] Playback OK")
try AVAudioSession.sharedInstance().setActive(true) try AVAudioSession.sharedInstance().setActive(true)
NSLog("[TEST] Session is Active") NSLog("[TEST] Session is Active")
@ -116,8 +111,11 @@ public class MyNativeAudio: CAPPlugin {
context: &playerItemContext) context: &playerItemContext)
self.audioPlayer = AVPlayer(playerItem: playerItem) self.audioPlayer = AVPlayer(playerItem: playerItem)
let time = self.audioPlayer.currentItem?.currentTime()
let startTime = CMTime(seconds: (audiobook?.startTime ?? 0.0) / 1000, preferredTimescale: 1000)
self.audioPlayer.seek(to: startTime)
let time = self.audioPlayer.currentItem?.currentTime()
print("Audio Player Initialized \(String(describing: time))") print("Audio Player Initialized \(String(describing: time))")
call.resolve(["success": true]) call.resolve(["success": true])
@ -206,9 +204,10 @@ public class MyNativeAudio: CAPPlugin {
self.notifyListeners("onPlayingUpdate", data: [ self.notifyListeners("onPlayingUpdate", data: [
"value": true "value": true
]) ])
sendMetadata()
playerState = .playing playerState = .playing
setupNowPlaying() updateNowPlaying()
} }
func pause() { func pause() {
@ -216,6 +215,7 @@ public class MyNativeAudio: CAPPlugin {
self.notifyListeners("onPlayingUpdate", data: [ self.notifyListeners("onPlayingUpdate", data: [
"value": false "value": false
]) ])
sendMetadata()
playerState = .paused playerState = .paused
} }
@ -271,8 +271,10 @@ public class MyNativeAudio: CAPPlugin {
case .readyToPlay: case .readyToPlay:
// Player item is ready to play. // Player item is ready to play.
NSLog("AVPlayer ready to play") NSLog("AVPlayer ready to play")
setNowPlayingMetadata() setNowPlayingMetadata()
sendMetadata() sendMetadata()
if (audiobook?.playWhenReady == true) { if (audiobook?.playWhenReady == true) {
NSLog("AVPlayer playWhenReady == true") NSLog("AVPlayer playWhenReady == true")
play() play()
@ -291,7 +293,7 @@ public class MyNativeAudio: CAPPlugin {
} }
@objc func appDidEnterBackground() { @objc func appDidEnterBackground() {
setupNowPlaying() updateNowPlaying()
NSLog("[TEST] App Enter Backround") NSLog("[TEST] App Enter Backround")
} }
@ -304,52 +306,88 @@ public class MyNativeAudio: CAPPlugin {
// Get the shared MPRemoteCommandCenter // Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared() let commandCenter = MPRemoteCommandCenter.shared()
// Add handler for Play Command commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.addTarget { [unowned self] event in commandCenter.playCommand.addTarget { [unowned self] event in
NSLog("[TEST] Play Command \(playbackRate())") play()
if playbackRate() == 0.0 { return .success
play() }
return .success commandCenter.pauseCommand.isEnabled = true
} commandCenter.pauseCommand.addTarget { [unowned self] event in
return .commandFailed pause()
return .success
} }
// Add handler for Pause Command commandCenter.skipForwardCommand.isEnabled = true
commandCenter.pauseCommand.addTarget { [unowned self] event in commandCenter.skipForwardCommand.preferredIntervals = [30]
NSLog("[TEST] Pause Command \(playbackRate())") commandCenter.skipForwardCommand.addTarget { [unowned self] event in
if playbackRate() == 1.0 { guard let command = event.command as? MPSkipIntervalCommand else {
pause() return .noSuchContent
return .success
} }
return .commandFailed
self.audioPlayer.seek(to: CMTime(seconds: currentTime() + command.preferredIntervals[0].doubleValue, preferredTimescale: 1000))
updateNowPlaying()
return .success
}
commandCenter.skipBackwardCommand.isEnabled = true
commandCenter.skipBackwardCommand.preferredIntervals = [30]
commandCenter.skipBackwardCommand.addTarget { [unowned self] event in
guard let command = event.command as? MPSkipIntervalCommand else {
return .noSuchContent
}
self.audioPlayer.seek(to: CMTime(seconds: currentTime() - command.preferredIntervals[0].doubleValue, preferredTimescale: 1000))
updateNowPlaying()
return .success
} }
} }
func getData(from url: URL, completion: @escaping (UIImage?) -> Void) {
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
if let data = data {
completion(UIImage(data:data))
}
})
.resume()
}
func setNowPlayingMetadata() { func setNowPlayingMetadata() {
if (audiobook?.cover != nil) {
guard let url = URL(string: audiobook!.cover) else { return }
getData(from: url) { [weak self] image in
guard let self = self,
let downloadedImage = image else {
return
}
let artwork = MPMediaItemArtwork.init(boundsSize: downloadedImage.size, requestHandler: { _ -> UIImage in
return downloadedImage
})
self.setNowPlayingMetadataWithImage(artwork)
}
} else {
setNowPlayingMetadataWithImage(nil)
}
}
func setNowPlayingMetadataWithImage(_ artwork: MPMediaItemArtwork?) {
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = [String: Any]() var nowPlayingInfo = [String: Any]()
NSLog("%@", "**** Set track metadata: title \(audiobook?.title ?? "")") NSLog("%@", "**** Set track metadata: title \(audiobook?.title ?? "")")
nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = audiobook?.playlistUrl ?? "" nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = audiobook?.playlistUrl != nil ? URL(string: audiobook!.playlistUrl) : nil
nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = "hls" nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = "hls"
nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = false nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = false
nowPlayingInfo[MPMediaItemPropertyTitle] = audiobook?.title ?? "" nowPlayingInfo[MPMediaItemPropertyTitle] = audiobook?.title ?? ""
nowPlayingInfo[MPMediaItemPropertyArtist] = audiobook?.author ?? "" nowPlayingInfo[MPMediaItemPropertyArtist] = audiobook?.author ?? ""
if (audiobook?.cover != nil) { if (artwork != nil) {
let myImageView = UIImageView() nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
myImageView.imageFromUrl(urlString: audiobook?.cover ?? "")
nowPlayingInfo[MPMediaItemPropertyArtwork] = myImageView.image
} }
nowPlayingInfo[MPMediaItemPropertyAlbumArtist] = audiobook?.author ?? ""
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = audiobook?.title ?? ""
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
} }
func setupNowPlaying() { func updateNowPlaying() {
if (playerState != .playing) { if (playerState != .playing) {
NSLog("[TEST] Not current playing so not updating now playing info") NSLog("[TEST] Not current playing so not updating now playing info")