Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
プロトコルを使って複数サービスを跨いだmusic playerを実装する
Search
Hiroki Kumamoto
September 02, 2018
2
520
プロトコルを使って複数サービスを跨いだmusic playerを実装する
Hiroki Kumamoto
September 02, 2018
Tweet
Share
More Decks by Hiroki Kumamoto
See All by Hiroki Kumamoto
How to implement timetable view on iOS
kumabook
0
86
Promiseを実装してみよう
kumabook
0
270
bff_tips.pdf
kumabook
0
59
Tips of server-side rendering with react + redux
kumabook
0
67
emacs helm likeな WebExtensions を作った話
kumabook
0
140
merges sort
kumabook
0
75
lightweight introducing with reactive cocoa
kumabook
0
53
basic_sort
kumabook
0
70
git_peco_tips
kumabook
0
26
Featured
See All Featured
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Product Roadmaps are Hard
iamctodd
PRO
49
11k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
810
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
17
2.2k
Side Projects
sachag
452
42k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Designing for humans not robots
tammielis
250
25k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
GraphQLとの向き合い方2022年版
quramy
44
13k
The Language of Interfaces
destraynor
154
24k
Transcript
ϓϩτίϧΛͬͯෳαʔ ϏεΛލ͍ͩmusic playerΛ ࣮͢Δ iOSDC 2018/09/02 Hiroki Kumamoto a.k.a kumabook
ࣗݾհ • Hiroki Kumamoto • a.k.a kumabook (twitter, github) •
Software engineer at Spincoaster, Inc. • swift, JavaScript, ruby, rust ...
ϦΞϧ ͳ Իָγʔϯͱ ग़ ѭ͏ M U S I C
C H A R T T OP 10 0
TYPICA • ԻָϙʔλϧΞϓϦ • @TYPICA_JP • Web: typica.mu • iOSΞϓϦ
• ʰϦΞϧͳԻָγʔϯͷՄࢹԽʱΛࢦͨ͠ԻָαʔϏε • Web্ͷԻָใΛΫϩʔϧͯ͠Ϩίϝϯυ • Իָʹؔ͢ΔهࣄԻָαʔϏεͷۂɺΞϧόϜɺϓϨΠϦετ • TYPICA Top 100 (https://typica.mu/ja/chart/top100) • ಠࣗͷϥϯΩϯάγεςϜ
ΞϓϦϓϨʔϠ • AppleMusic, Spotify, YouTube, SoundCloudʹର Ԡͨ͠ԻָϓϨʔϠ • αʔϏεؒΛލ͍Ͱ࿈ଓ࠶ੜՄೳ •
ԻָϓϨʔϠ։ൃͷࡍʹ࡞ͬͨϥΠϒϥϦɾಘ ͨݟʹ͍ͭͯͷ
None
Apple MusicSpotifyͳͲ ͷΑ͏ͳഭΓ্͕ΔϓϨʔϠ
YouTubeSpotifyͷۂ͕ ࠞࡏ͍ͯͯ͠ ಉ͡࿈ଓ࠶ੜ͕Մೳ ↑ ϝΠϯͷ͓
Agenda • iOSͰԻָΛ࠶ੜ͢Δํ๏ͷհ • ෳαʔϏεʹ·͕ͨͬͯ࠶ੜ͠Α͏ͱ͢Δͱ ग़ͯ͘Δ՝ • ࡞ͬͨϥΠϒϥϦʹ͍ͭͯ
iOSͰԻָΛ࠶ੜ͢Δ • AVFoundation.AVPlayer • MediaPlayer.MPMusicPlayerController • WebView • Spotify iOS
SDK • ϨΠϠͷAPIΛ͏ (ࠓճείʔϓ֎) • CoreAudio, AudioUnit, OpenAL …
AVFoundation.AV(Queue)Player • URLͰԻಈըϑΝΠϧΛࢦఆͯ͠࠶ੜ͢Δ • ಈըͷ߹viewͷlayerʹplayerΛηοτͯ͠ ө૾Λදࣔ • ࢀߟ: ಈըΞϓϦΛͳΊΒ͔ʹಈ͔ٕ͢ज़
MediaPlayer.MPMusicPlayerController • iTunesϥΠϒϥϦ or AppleMusic ͷۂΛ࠶ੜ • applicationMusicPlayer: ΞϓϦʹดͨ͡ϓ ϨʔϠ
• systemMusicPlayer: MusicΞϓϦΛૢ࡞
AppleMusicΛ࠶ੜ͢Δ • ϢʔβͷAppleMusicΞΧϯτͱଓ • AppleMusic APIͬͯۂͷIDΛऔಘ • MPMusicPlayerController#setQueue(with: descriptor) •
MPMusicPlayerController#play()
AppleMusicΞΧϯτଓͷखॱ 1. Info.plist ʹNSAppleMusicUsageDescriptionΛՃ 2. SKCloudServiceController.authorizationStatusͰݱࡏͷঢ়ଶΛ֬ ೝ 3. SKCloudServiceController.requestAuthorizationͰଓཁٻ 4.
SKCloudServiceController#requestCapabilities Ͱ࠶ੜՄೳ͔ΛνΣοΫ 5. SKCloudServiceController#requestStorefrontCountryCodeͰ StorefrontΛऔಘ
Apple Music API • AppleMusicͷใΛऔಘ͢ΔͨΊͷWebAPI • αʔόͰར༻Մೳ • StorefrontΛࢦఆ •
݁Ռͷݴޠ͕มΘΔ • ̎छྨͷtoken • developer token • user token
• Ϣʔβʹඥ͔ͮͳ͍σʔλ • ྫɿۂɾϓϨΠϦετΛݕࡧ • JSON Web Token (JWT) •
࠷6ϲ݄༗ޮͳͷΛੜՄೳ developer token
developer tokenͷੜ • https://developer.apple.com/ -> Certificates, Identifiers & Profiles •
Identities -> Music IDͷ࡞ • Keys -> MusicKit private key ͷ࡞ • JWTͷੜ • elauimagineering/apple-music-token-generator • key idɾteam idɾprivate key • ΫϥΠΞϯτʹprivate keyຒΊࠐ·ͳ͍ํ͕ྑ͍
• ϢʔβσʔλΞΫηεͰ͖Δ • ྫɿۙͷ࠶ੜཤྺɺϓϨΠϦετ࡞ɾۂ ΛՃ • MPMediaLibraryͰϓϨΠϦετ࡞ͳͲՄ ೳ • requestUserToken(forDeveloperToken:completion
Handler:) user token
Apple Music Client • Web APIͳͷͰެࣜͷΫϥΠΞϯτͳ͍ • Apple Music APIͷJSON݁ߏบ͕͋Δ
• Φεεϝɿscottrhoyt/Cider
WebView • UIWebView(WKWebView) Ͱ࠶ੜ • <video playsinline /> + UIWebView#allowsInlineMediaPlayback
• શը໘ʹͳΒͳ͘ͳΔ • iOS10͔ΒsafariͰ
WebView: YouTube࠶ੜ • youtube/youtube-ios-player-helper • ެࣜͷYouTubeͷWebView wrapperϓϨΠϠʔ • YTPlayerView: JavaScriptͳ͠ʹૢ࡞Մೳ
• نͰ͜ΕҎ֎ͷ࠶ੜํ๏ΛೝΊ͍ͯͳ͍ • ඇެࣜͳ࠶ੜํ๏…
Spotify iOS SDK • spotify/ios-sdk • SpotifyͷۂΛ࠶ੜͰ͖Δ • ϓϨϛΞϜΞΧϯτͳΒ࠶ੜͰ͖Δ͕ɺ ҰൠΞΧϯτͩͱࢼௌ͔͠Ͱ͖ͳ͍
• AppleMusicಉ༷
Spotify iOS SDK • Spotify accountͰOAuth ϩάΠϯ • SPTAudioStreamingControllerʹaccess tokenΛ
ηοτ • ࠶ੜ͢ΔTrackͷuriΛWeb APIͳͲͰऔಘ • SPTAudioStreamingController#playSpotifyURI
SpotifyͷOAuthೝূ • oauthೝূʹtoken refresh༻ͷαʔόΛཱͯΔඞཁ͕͋Δ • https://developer.spotify.com/documentation/ios-sdk/guides/ token-swap-and-refresh/ • refresh͠ͳ͍ͱ̍࣌ؒͰࣦޮ •
̎ͭͷྫ • railsͰͷ࣮ྫ • AWS lambda+API GatewayͰͷ࣮ྫ: kumabook/spotify- token-swap-lambda
όοΫάϥϯυ࠶ੜ • Capabilities -> Background Modes -> Audio ,... ʹνΣοΫ
• AVAudioSession#setCategory() • AVAudioSessionCategoryPlayback
ίϯτϩʔϧηϯλʔ • ίϯτϩʔϥ͔ΒͷΠϕϯτ • MPRemoteCommandCenter • playCommand.addTarget • ίϯτϩʔϥͷදࣔ •
MPNowPlayingInfoCenter#nowPlayingInfo
αʔϏεؒΛލ͍ͩϓϨʔϠΛ࣮ ͠Α͏ͱͨ࣌͠ʹग़͖ͯͨ՝
αʔϏεͱϓϨʔϠʔ • SoundCloud • YouTube • Spotify • AppleMusic ←
AVPlayer ← WebView ← spotify/ios-sdk ← MediaPlayer
AVPlayer YouTubePlayer SpotifyPlayer AppleMusicPlayer ̐ͭͷϓϨʔϠΛཧ + ͦΕͧΕPlayer UIͱ࿈ܞ
Πϕϯτͷ௨APIόϥόϥ • εςʔλε௨Πϕϯτ • ݱࡏͷ࠶ੜҐஔͷ௨Πϕϯτ
εςʔλε௨Πϕϯτ AVPlayer NotificationCenter + KVO YTPlayerView YTPlayerViewDelegate MPMusicPlayerController NotificationCenter SPTAudioStreamingController
SPTAudioStreamingPlaybackDelegate
ݱࡏͷ࠶ੜҐஔͷ௨Πϕϯτ AVPlayer AVPlayer#addPeriodicTimeObserver YTPlayerView YTPlayerViewDelegate MPMusicPlayerController ͳ͍ʁ(ࣗલλΠϚʔ) SPTAudioStreamingController SPTAudioStreamingPlaybackDelegate
ঢ়ଶཧ • ࠶ੜഉଞత • ϓϨʔϠΛࢭΊ͔ͯΒ࣍ͷϓϨʔϠΛ࠶ੜ • Ωϡʔͷཧʴ࣌ؒͷཧ • ผͷϓϨʔϠΛ࠶ੜͯͬͨ͠ͱ͖ʹલͷۂ ͕࠶ੜ͞Εͳ͍Α͏ʹঢ়ଶΛΫϦΞ
ϥΠϒϥϦԽ • kumabook/PlayerKit • Example • APIࠩΛٵऩͯ͠γϯϓϧͳIFΛఏڙ • ෦తʹPlayerΛҰ୴protocolͰදݱͯ͠ɺ αʔϏεؒͷΓସ͑Λڞ௨࣮
• Player UI
PlayerKit.QueuePlayer AVPlayer YouTubePlayer SpotifyPlayer AppleMusic Player
QueuePlayer Player AVPlayer YouTubePlayer SpotifyPlayer AppleMusicPlayer QueuePlayerObserver Playlist
Player protocol • ୯ҰͷτϥοΫΛ࠶ੜ͢ΔϓϨʔϠͷϓϩτίϧ • ϝϦοτɿίʔυ͕γϯϓϧʹ • σϝϦοτ: ͦΕͧΕͷϓϨʔϠ͕͍࣋ͬͯΔʮ࣍ͷۂͷϓϦϩʔυػೳʯ ͳͲ͕͑ͳ͘ͳΔ
init load loadTo Play play pause play(_: Track) prepare(_: Track)
[complete loading] [complete loading] pause() play() [end to play] Playerͷঢ়ଶભҠ: PlayerState
Player • var state: PlayerState { get } • func
clearPlayer() : Πϕϯτࢹͷղ์ɺλΠ ϚʔͷΫϦΞ • func preparePlayer(): ΠϕϯτࢹɺλΠϚʔε λʔτɺঢ়ଶΛॳظঢ়ଶ
MPMusicPlayerControllerͷόʔ δϣϯ͝ͱͷڍಈͷࠩҟ • iOS11 ͔Βۂͷ࠶ੜ͕ऴΘͬͯ MPMusicPlayerControllerNowPlayingItemDidChan ge Πϕϯτ͕ඈΜͰ͜ͳ͘ͳͬͨ • →ۂͷऴྃΛײͰ͖ͳ͘ͳͬͨ
• issues/12 • ࣗಈͰ࣍ͷۂʹߦ͔ͳ͘ͳͬͯ͠·ͬͨͷͰସ ҊΛࡧத
QueuePlayer • PlaylistͷதͷTrackΛ֘͢ΔPlayerʹσΟεύον ͍ͯ͘͠ • Track#playerType Ͱผ • Playerͷ෦ͷ࣮ʹґଘ͠ͳ͍ •
ݸʑͷPlayerΛಈతʹՃ͢Δ • queuePlayer.addPlayer(YouTubePlayer())
init load loadTo Play play pause play(_: Track) prepare(_: Track)
[complete loading] [complete loading] pause() play() [end (queue is empty)] QueuePlayerͷঢ়ଶભҠ next() previous() [end]
ࢼௌͱࢹௌ • SpotifyɾAppleMusic༗ྉձһͰͳ͍ͱ֎෦Ξ ϓϦͰ࠶ੜͰ͖ͳ͍ • ࢼௌͷURL • AppleMusic: Song previews[].url
• Spotify: Track preview_url
ࢼௌͱࢹௌΛΓସ͑Δ • ಉ͡TrackͰϢʔβͷঢ়ଶʹΑͬͯ͏Player ͕ಈతʹม͑Δඞཁ͕͋Δ • Ϣʔβͷঢ়ଶཧΞϓϦͷ • Track#playerTypeͷฦ͢Λಈతʹ
public var playerType: PlayerType { If SpotifyAPIClient.isPremiumUser { return .spotify
} return .avPlayer }
• AppleMusicSpotifyͷΑ͏ͳഭΓ্͕ΔϓϨʔ Ϡʔ • ࢀߟ: 8/31ͷηογϣϯ MusicΞϓϦͷ TransitionΛ࠶ݱ͢Δ • ࡉ੍͔͍ޚ͕͔ͨͬͨͨ͠Ί
UIPresentationControllerΘͣࣗલͰ࣮ Player UIͷ࣮
YTPlayerViewͷΓସ͑ τϥϯδγϣϯ͕ऴΘͬͨ࣌ʹ YTPlayerViewΛҠಈͤͯ͞ϦαΠζ
·ͱΊ • iOSͰԻָΛ࠶ੜ͢Δํ๏ͷհ • ෳͷϓϨʔϠʔΛΈ߹Θͤ͏ͨΊͷϥΠϒϥ ϦΛ࡞ • ΠϯλϑΣʔεͱঢ়ଶભҠΛఆ͓͔ٛͨ͛͠Ͱϓ ϨʔϠಉ࢜ΛΓସ͑Δ෦ڞ௨ԽͰ͖ͨ •
MPMusicPlayerControllerͷΠϕϯτAPIपΓʹ՝ ͋Γ
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
ࢀߟϦϯΫ • AVFoundation.AVQueuePlayer • MediaPlayer.MPMusicPlayerController • youtube/youtube-ios-player-helper • spotify/ios-sdk
ࢀߟϦϯΫ • Introducing MusicKit