|
| 1 | +# 241220 MPNowPlayingInfoCenter, MPRemoteCommandCenter |
| 2 | + |
| 3 | +์๋ฆผ์ผํฐ์ ์ฑ์์ ์ฌ์์ค์ธ ์ค๋์ค ์ ๋ณด๋ฅผ ๋์๋ณด์~ |
| 4 | + |
| 5 | +12์ 20์ผ (๊ธ) |
| 6 | + |
| 7 | + |
| 8 | +# ํ์ต๋ด์ฉ |
| 9 | + |
| 10 | + |
| 11 | +- MPNowPlayingInfoCenter๋ฅผ ์ด๋ป๊ฒ ํ์ฉํ๋๊ฑฐ์ง? |
| 12 | +- MPRemoteCommandCenter์๋ ์ด๋ค ๊ธฐ๋ฅ๋ค์ด ์์ง? |
| 13 | +- ์ฌ์์๊ฐ ์์ด '์ค์๊ฐ'์ผ๋ก ํ๊ธฐํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ์ง? |
| 14 | +- ์ด๋ฏธ์ง๋ฅผ ๋คํธ์ํฌ๋ก ๋ค์ด๋ฐ์์ ํ์ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ์ง? |
| 15 | + |
| 16 | + |
| 17 | +# ๊ณ ๋ฏผํ ์ / ํด๊ฒฐ๋ฐฉ๋ฒ |
| 18 | + |
| 19 | +## MPNowPlayingInfoCenter |
| 20 | + |
| 21 | +* ์ฑ์ด ์ฌ์ํ๋ ๋ฏธ๋์ด์ ์ ๋ณด๋ฅผ ์ค์ ํ๊ธฐ ์ํ ๊ฐ์ฒด. |
| 22 | +* `nowPlayingInfo`๋ผ๋ ํ๋กํผํฐ์ dictionary๋ฅผ ํ์ฉํ์ฌ ์๋์ ๊ฐ์ ์ ๋ณด๋ฅผ ์ค์ ํ ์ ์๋ค. |
| 23 | + |
| 24 | +|**ํค ๊ฐ**|**์ค๋ช
**| |
| 25 | +|---|---| |
| 26 | +|`MPMediaItemPropertyAlbumTitle`|์จ๋ฒ์ ์ ๋ชฉ| |
| 27 | +|`MPMediaItemPropertyAlbumTrackCount`|์จ๋ฒ์ ํฌํจ๋ ์ด ํธ๋ ์| |
| 28 | +|`MPMediaItemPropertyAlbumTrackNumber`|ํ์ฌ ํธ๋์ ๋ฒํธ| |
| 29 | +|`MPMediaItemPropertyArtist`|์ํฐ์คํธ์ ์ด๋ฆ| |
| 30 | +|`MPMediaItemPropertyArtwork`|์จ๋ฒ ์ํธ์ํฌ ์ด๋ฏธ์ง. `MPMediaItemArtwork` ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ํ๋ค.| |
| 31 | +|`MPMediaItemPropertyComposer`|์๊ณก๊ฐ์ ์ด๋ฆ| |
| 32 | +|`MPMediaItemPropertyDiscCount`|์จ๋ฒ์ ์ด ๋์คํฌ ์| |
| 33 | +|`MPMediaItemPropertyDiscNumber`|ํ์ฌ ๋์คํฌ์ ๋ฒํธ| |
| 34 | +|`MPMediaItemPropertyGenre`|์ฅ๋ฅด| |
| 35 | +|`MPMediaItemPropertyPlaybackDuration`|์ฌ์ ์๊ฐ(์ด ๋จ์)| |
| 36 | +|`MPMediaItemPropertyTitle`|ํธ๋์ ์ ๋ชฉ| |
| 37 | +|`MPNowPlayingInfoPropertyElapsedPlaybackTime`|ํ์ฌ ์ฌ์๋ ์๊ฐ(์ด ๋จ์)| |
| 38 | +|`MPNowPlayingInfoPropertyPlaybackRate`|์ฌ์ ์๋. ์ผ๋ฐ์ ์ผ๋ก 1.0์ ์ ์ ์ฌ์, 0.0์ ์ผ์ ์ ์ง๋ฅผ ์๋ฏธํ๋ค.| |
| 39 | +|`MPNowPlayingInfoPropertyDefaultPlaybackRate`|๊ธฐ๋ณธ ์ฌ์ ์๋| |
| 40 | +|`MPNowPlayingInfoPropertyPlaybackQueueIndex`|ํ์ฌ ์ฌ์ ์ค์ธ ํญ๋ชฉ์ ์ฌ์ ๋ชฉ๋ก ์ธ๋ฑ์ค| |
| 41 | +|`MPNowPlayingInfoPropertyPlaybackQueueCount`|์ฌ์ ๋ชฉ๋ก์ ์ด ํญ๋ชฉ ์| |
| 42 | +|`MPNowPlayingInfoPropertyChapterNumber`|ํ์ฌ ์ฌ์ ์ค์ธ ์ฑํฐ ๋ฒํธ| |
| 43 | +|`MPNowPlayingInfoPropertyChapterCount`|์ด ์ฑํฐ ์| |
| 44 | +|`MPNowPlayingInfoPropertyIsLiveStream`|ํ์ฌ ์ฌ์ ์ค์ธ ํญ๋ชฉ์ด ๋ผ์ด๋ธ ์คํธ๋ฆผ์ธ์ง ์ฌ๋ถ (`true` ๋๋ `false`)| |
| 45 | +|`MPNowPlayingInfoPropertyMediaType`|ํ์ฌ ์ฌ์ ์ค์ธ ๋ฏธ๋์ด์ ์ ํ. `MPNowPlayingInfoMediaType` ๊ฐ์ ์ฌ์ฉ.| |
| 46 | + |
| 47 | +```swift |
| 48 | +import MediaPlayer |
| 49 | + |
| 50 | +func updateNowPlayingInfo(title: String, artist: String, albumTitle: String, duration: TimeInterval, currentTime: TimeInterval, artworkImage: UIImage?) { |
| 51 | + var nowPlayingInfo: [String: Any] = [ |
| 52 | + MPMediaItemPropertyTitle: title, |
| 53 | + MPMediaItemPropertyArtist: artist, |
| 54 | + MPMediaItemPropertyAlbumTitle: albumTitle, |
| 55 | + MPMediaItemPropertyPlaybackDuration: duration, |
| 56 | + MPNowPlayingInfoPropertyElapsedPlaybackTime: currentTime, |
| 57 | + MPNowPlayingInfoPropertyPlaybackRate: 1.0 // 1.0์ ์ฌ์ ์ค, 0.0์ ์ผ์ ์ ์ง ์ํ๋ฅผ ๋ํ๋ |
| 58 | + ] |
| 59 | + |
| 60 | + // ์จ๋ฒ ์ํธ์ํฌ๊ฐ ์์ ๊ฒฝ์ฐ ์ค์ |
| 61 | + if let artworkImage { |
| 62 | + let artwork = MPMediaItemArtwork(boundsSize: artworkImage.size) { size in |
| 63 | + return artworkImage |
| 64 | + } |
| 65 | + nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork |
| 66 | + } |
| 67 | + |
| 68 | + // MPNowPlayingInfoCenter์ ์ ๋ณด ์ค์ |
| 69 | + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +## ์ด๋ฏธ์ง๋ฅผ ๋น๋๊ธฐ๋ก ๋ฐ์ ์ค์ ํ๋ ๋ฐฉ๋ฒ |
| 74 | + |
| 75 | +Kingfisher ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํด์ ์ด๋ฏธ์ง๋ฅผ ๋น๋๊ธฐ๋ก ๋ค์ด๋ก๋ ๋ฐ์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. |
| 76 | + |
| 77 | +์ด๋ ๊ฒ ๋น๋๊ธฐ๋ก ์ด๋ฏธ์ง๋ฅผ ๋ค์ด๋ก๋ ๋ฐ๋ ๊ฒฝ์ฐ์๋, nowPlayingInfo ์ค์ ๋ํ ๋งจ ๋ง์ง๋ง์ ๋น๋๊ธฐ๋ก ์ค์ ํ๊ฒ ๋๋ค. |
| 78 | + |
| 79 | +```swift |
| 80 | +import MediaPlayer |
| 81 | +import Kingfisher |
| 82 | + |
| 83 | +func fetchArtwork(from url: URL) async -> MPMediaItemArtwork? { |
| 84 | + do { |
| 85 | + let result = try await KingfisherManager.shared.retrieveImage(with: url) |
| 86 | + let artwork = MPMediaItemArtwork(boundsSize: result.image.size) { _ in |
| 87 | + return result.image |
| 88 | + } |
| 89 | + return artwork |
| 90 | + } catch { |
| 91 | + print("์ด๋ฏธ์ง ๋ค์ด๋ก๋ ์คํจ: \(error)") |
| 92 | + return nil |
| 93 | + } |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +## MPRemoteCommandCenter |
| 98 | + |
| 99 | +* ์ธ๋ถ ์ก์ธ์๋ฆฌ ๋ฐ ์์คํ
์ปจํธ๋กค์ด ์ ์กํ๋ ์๊ฒฉ ์ ์ด ์ด๋ฒคํธ์ ์๋ตํ๋ ๊ฐ์ฒด. |
| 100 | +* ์ด ๊ฐ์ฒด๋ก '์ฌ์', '์ผ์์ ์ง' ๋ฒํผ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฑ ๋ด์์ ์์
์ ์ฒ๋ฆฌํ ์ ์๋ค. |
| 101 | + |
| 102 | +```swift |
| 103 | +private func setupRemoteCommandHandlers() { |
| 104 | + // ์ฌ์ ๋ฒํผ ์ฒ๋ฆฌ |
| 105 | + commandCenter.playCommand.addTarget { [weak self] event in |
| 106 | + guard let self = self else { return .commandFailed } |
| 107 | + |
| 108 | + if !self.isPlaying { |
| 109 | + self.play() |
| 110 | + return .success |
| 111 | + } |
| 112 | + return .commandFailed |
| 113 | + } |
| 114 | + |
| 115 | + // ์ผ์์ ์ง ๋ฒํผ ์ฒ๋ฆฌ |
| 116 | + commandCenter.pauseCommand.addTarget { [weak self] event in |
| 117 | + guard let self = self else { return .commandFailed } |
| 118 | + |
| 119 | + if self.isPlaying { |
| 120 | + self.pause() |
| 121 | + return .success |
| 122 | + } |
| 123 | + return .commandFailed |
| 124 | + } |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +> ์ด ์ธ์๋ ๋ค์ํ ๋ช
๋ น๋ค์ด ์กด์ฌํ๋ค. |
| 129 | +
|
| 130 | +|**Command**|**์ค๋ช
**| |
| 131 | +|---|---| |
| 132 | +|`playCommand`|์ฌ์ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 133 | +|`pauseCommand`|์ผ์ ์ ์ง ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 134 | +|`stopCommand`|์ ์ง ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 135 | +|`togglePlayPauseCommand`|์ฌ์/์ผ์ ์ ์ง ํ ๊ธ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 136 | +|`nextTrackCommand`|๋ค์ ํธ๋ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 137 | +|`previousTrackCommand`|์ด์ ํธ๋ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 138 | +|`seekForwardCommand`|์์ผ๋ก ํ์ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 139 | +|`seekBackwardCommand`|๋ค๋ก ํ์ ๋ฒํผ์ด ๋๋ ธ์ ๋| |
| 140 | +|`skipForwardCommand`|์ ํด์ง ์๊ฐ๋งํผ ์์ผ๋ก ๊ฑด๋๋| |
| 141 | +|`skipBackwardCommand`|์ ํด์ง ์๊ฐ๋งํผ ๋ค๋ก ๊ฑด๋๋| |
| 142 | +|`changePlaybackRateCommand`|์ฌ์ ์๋ ๋ณ๊ฒฝ| |
| 143 | +|`changeRepeatModeCommand`|๋ฐ๋ณต ๋ชจ๋ ๋ณ๊ฒฝ| |
| 144 | +|`changeShuffleModeCommand`|์
ํ ๋ชจ๋ ๋ณ๊ฒฝ| |
| 145 | +|`rateCommand`|๋ฏธ๋์ด ํ๊ฐ(๋ณ์ ๋ฑ)| |
| 146 | +|`likeCommand`|์ข์์ ๋ฒํผ| |
| 147 | +|`dislikeCommand`|์ซ์ด์ ๋ฒํผ| |
| 148 | +|`bookmarkCommand`|๋ถ๋งํฌ ์ถ๊ฐ ๋ฒํผ| |
| 149 | + |
| 150 | +## ์ฌ์์ด ๋ชจ๋ ๋๋ฌ์ ๋ ์๋ฆผ ๋ฐ๋ ๋ฐฉ๋ฒ |
| 151 | + |
| 152 | +์๋์ฒ๋ผ NotificationCenter๋ฅผ ํ์ฉํด์ AVPlayerItemDidPlayToEndTime์ ๊ตฌ๋
ํ๋ฉด ๋๋ค! |
| 153 | + |
| 154 | +```swift |
| 155 | +NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, |
| 156 | + object: item, |
| 157 | + queue: .main, |
| 158 | + using: { _ in |
| 159 | + // ์ฌ๊ธฐ์ ์ฑ ๋ด์์ ์ฌ์์ค์ธ AVPlayer์ ์ฌ์์ ๋ฉ์ถ๋๋ก ๊ตฌํํด๋ณด์. |
| 160 | +}) |
| 161 | +``` |
| 162 | + |
| 163 | + |
| 164 | +--- |
| 165 | + |
| 166 | + |
| 167 | +# ์ฐธ๊ณ ๋งํฌ |
| 168 | + |
| 169 | + |
| 170 | +- [https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter](https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter) |
| 171 | +- [https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter](https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter) |
| 172 | +- [https://developer.apple.com/documentation/avfoundation/avplayeritem/didplaytoendtimenotification](https://developer.apple.com/documentation/avfoundation/avplayeritem/didplaytoendtimenotification) |
0 commit comments