Más contenido relacionado Similar a 創作 MusicKit 告白情歌 (20) 創作 MusicKit 告白情歌5. 學習重點
• Apple Music API
• StoreKit & MediaPlayer framework
• Apple 官⽅方的 sample code
http://bit.ly/2BfKSVN
7. Apple Music API
• Developer Token
• 所有的 API 都需要,⽐比⽅方 search 周杰倫倫的歌
• User Token
• 和使⽤用者有關的 API,⽐比⽅方使⽤用者最近播放的專輯
• 利利⽤用 developer token ⽣生成
11. Apple Music API
• API 網⾴頁
• https://apple.co/2vW3MCt
• 以 https://api.music.apple.com/v1/ 開頭
• 存取某個國家的⾳音樂樂樂樂資料料
• https://api.music.apple.com/v1/catalog/{storefront}/albums/{id}
• catalog/{storefront}
• storefront: 國家代碼,ISO-Alpha2 country code
• ex: tw
• http://www.nationsonline.org/oneworld/country_code_list.htm
• 存取個⼈人的⾳音樂樂樂樂資料料
• https://api.music.apple.com/v1/me/ratings/albums/{id}
• me/
12. 從 iTunes 知道
歌⼿手,專輯,歌曲的 id
https://itunes.apple.com/tw/artist/jay-chou/300117743?l=en
https://api.music.apple.com/v1/catalog/tw/artists/300117743
13. 從 iTunes 知道
歌⼿手,專輯,歌曲的 id
https://itunes.apple.com/tw/album/%E5%91%8A%E7%99%BD%E6%B0%A3%E7%90%83/1118757859?i=1118757877&l=en
https://api.music.apple.com/v1/catalog/tw/songs/1118757877
16. search
curl -H 'Authorization: Bearer
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFDTjVIWjUzTk4ifQ.
eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0IjoxNTE2NDUwOTE1LCJleH
AiOjE1MTY0OTQxMTV9.zSdf73HMQcoAgSQqhHEA2xD7b2yz7z-
NsXK4PKsaGdbETsMAylAaMnq2-
GWdDSmKSdSSGZ8HZtnASvAr95ghUA' 'https://api.music.apple.com/
v1/catalog/tw/search?term=戴佩妮' | pbcopy
http://jsoneditoronline.org
18. search
指定 type
curl -H 'Authorization: Bearer
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFDTjVIWjUzTk4ifQ.
eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0IjoxNTE2NDUwOTE1LCJleH
AiOjE1MTY0OTQxMTV9.zSdf73HMQcoAgSQqhHEA2xD7b2yz7z-
NsXK4PKsaGdbETsMAylAaMnq2-
GWdDSmKSdSSGZ8HZtnASvAr95ghUA' 'https://api.music.apple.com/
v1/catalog/tw/search?types=songs&term=戴佩妮' | pbcopy
http://jsoneditoronline.org
20. 分⾴頁
next, limit, offset
limit 的上限 25
curl -H 'Authorization: Bearer
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFDTjVIWjUzTk4ifQ.
eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0IjoxNTE2NDUwOTE1LCJleH
AiOjE1MTY0OTQxMTV9.zSdf73HMQcoAgSQqhHEA2xD7b2yz7z-
NsXK4PKsaGdbETsMAylAaMnq2-
GWdDSmKSdSSGZ8HZtnASvAr95ghUA' 'https://api.music.apple.com/
v1/catalog/tw/search?types=songs&term=戴佩妮&limit=25' | pbcopy
21. 分⾴頁
curl -H 'Authorization: Bearer
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFDTjVIWjUzTk4ifQ.
eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0IjoxNTE2NDUwOTE1LCJleH
AiOjE1MTY0OTQxMTV9.zSdf73HMQcoAgSQqhHEA2xD7b2yz7z-
NsXK4PKsaGdbETsMAylAaMnq2-
GWdDSmKSdSSGZ8HZtnASvAr95ghUA' 'https://api.music.apple.com/
v1/catalog/tw/search?types=songs&term=戴佩妮&limit=25&offset=25' |
pbcopy
⽅方法1: 從 next 得到下⼀一⾴頁的網址
⽅方法2: ⾃自⼰己累加 offset
沒有下⼀一⾴頁: 沒有 next 欄欄位
25. 閃退
2018-01-20 23:34:54.867234+0800 MusicKitDemo[8440:3181243] [access] This app
has crashed because it attempted to access privacy-sensitive data without a usage
description. The app's Info.plist must contain an NSAppleMusicUsageDescription key
with a string value explaining to the user how the app uses this data.
SKCloudServiceController.requestAuthorization(_:)
抓取 Apple Music 的⾳音樂樂樂樂不不需要使⽤用者同意
但是播放⾳音樂樂樂樂需要
28. 權限取得步驟
• 取得 developer token
• StoreKit & SKCloudServiceController
• 徵求使⽤用者同意
SKCloudServiceController.requestAuthorization(_:)
• 如果 authorized,取得 Cloud Service Capabilities
35. 沒有更更多資料料了了
• 沒有 next 欄欄位
• search 告⽩白氣球 demo
func processMediaItems(from json: Data) throws -> ([MediaItem], String?) {
guard let jsonDictionary = try JSONSerialization.jsonObject(with:
json, options: []) as? [String: Any],
let results = jsonDictionary[ResponseRootJSONKeys.results] as?
[String: [String: Any]] else {
throw
SerializationError.missing(ResponseRootJSONKeys.results)
}
var songMediaItems = [MediaItem]()
var next: String?
if let songsDictionary = results[ResourceTypeJSONKeys.songs] {
next = songsDictionary[ResponseRootJSONKeys.next] as? String
37. search hint
curl -H 'Authorization: Bearer
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjVaOVgz
SFgyUkMifQ.eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0Ijox
NTE1OTI1MTYzLCJleHAiOjE1MzE2NDk5NjN9.7SCwUodMxi
p2NYOdkNy40vvj9YTRzHeyUcmLIovXV1jfDQbu9guzFLDqk
0dzNaXti_VrXYH8UbzxQbv8LqZr2Q' "https://
api.music.apple.com/v1/catalog/tw/search/hints?term=戴" |
pbcopy
42. 使⽤用者的 playlist
func getPlaylists() -> [MPMediaPlaylist] {
let playlistsQuery = MPMediaQuery.playlists()
if let playlists = playlistsQuery.collections as? [MPMediaPlaylist] {
return playlists
} else {
return [MPMediaPlaylist]()
}
}
43. add to playlist
func addItem(withProductID productID: String, completionHandler: ((Error?) ->
Swift.Void)? = nil)
48. JSONDecoder 解析 JSON
import PlaygroundSupport
import Foundation
PlaygroundPage.current.needsIndefiniteExecution = true
struct SearchResults: Codable {
struct Attribute: Codable {
var name: String
var artistName: String
var albumName: String
}
struct SongData: Codable {
var id: String
var attributes: Attribute
}
struct Songs: Codable {
var href: URL
var next: URL?
var data: [SongData]
}
struct Results: Codable {
var songs: Songs
}
var results: Results
}
49. JSONDecoder 解析 JSON
let appleMusicAPIBaseURLString = "api.music.apple.com"
let countryCode = "tw"
let developerToken =
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFDTjVIWjUzTk4ifQ.eyJpc3MiOiJHNEhMOThMWDZMIiwiaWF0IjoxNTE2NTAyMzU1LCJle
HAiOjE1MTY1NDU1NTV9.2d1W7lqX2g2AG3Pzbe-UJ6-yoCXhaAxsqssEE98hIipdB7BORIJUpzE9mKMmrwv5ibAq0HCnStfOzckhFMUXBw"
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = appleMusicAPIBaseURLString
urlComponents.path = "/v1/catalog/(countryCode)/search"
let urlParameters = ["term": "周杰倫倫", "types": "songs"]
var queryItems = [URLQueryItem]()
for (key, value) in urlParameters {
queryItems.append(URLQueryItem(name: key, value: value))
}
urlComponents.queryItems = queryItems
var urlRequest = URLRequest(url: urlComponents.url!)
urlRequest.httpMethod = "GET"
urlRequest.addValue("Bearer (developerToken)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
guard error == nil, let urlResponse = response as? HTTPURLResponse, urlResponse.statusCode == 200, let data =
data else {
print("task error")
return
}
let decoder = JSONDecoder()
if let songResults = try? decoder.decode(SearchResults.self, from: data) {
for song in songResults.results.songs.data {
print(song.attributes.name)
}
} else {
print("JSON error")
}
}
task.resume()