串接多種 API 製作Lady Gaga App(Spotify篇)
1.畫面截圖:
2.App操作GIF:
3.GitHub連結:
4.程式解說:
取得Spotify的OAuth Access Token
如果你是高手高手高高手,可以直接看Spotify的教學文章
不是高手的朋友也別擔心,我已經幫你們讀完了,跟著以下步驟就可以取得Spotify的OAuth Access Token
可謂知己知彼,百戰百勝,我們先看申請OAuth Access Token的指令
curl -H "Authorization: Basic ZjM...zE=" -d grant_type=authorization_code -d code=MQCbtKe...44KN -d redirect_uri=https%3A%2F%2Fwww.foo.com%2Fauth https://accounts.spotify.com/api/token
依序下步驟,滿足上面的指令
第一步:
請先到下方網址登入
建立一個App
基本資料隨便填一填後,就會有以下畫面,記錄好Client ID和Client Secret後
第二步:
請點擊EDIT SETTINGS
在Redirect URIs這欄填入隨便一個網址(我是用我的github),並儲存
再把你的網址到以下的網站轉換一下,並且記錄結果
第三步:
再來請到以下網址,閱讀你想要哪種範圍(Scopes)
我用的是playlist-read-private
第四步:
還記得Client ID和Client Secret嗎?請用以下格式
你的Client ID:你的Client Secret
再到以下網址轉成 base64,並且記錄結果
第五步:
有了前四步的東西後,請填入以下網址
https://accounts.spotify.com/authorize?client_id=第一步的Client ID&response_type=code&redirect_uri=第二步轉換後的網址&scope=第三步你選的範圍
再把這個網址在新的分頁打開,結果如下:
按下同意後,會回到你之前第二步填的Redirect URIs
但仔細一看,網址後面多了 code=**你要記錄的code*****
p.s. 上圖的code並不是完整的
第六步:
我們蒐集好了申請Token需要的東西,就到終端機輸入指令吧
curl -H "Authorization: Basic 第四步的結果" -d grant_type=authorization_code -d code=第五步的code -d redirect_uri=第二步轉換後的網址 https://accounts.spotify.com/api/token
把紅框這段複製到jsoneditoronline來看
有了Bearer Token,我們可以利用Postman來獲得Json,再利用Postman的幫我們寫的Code串接
p.s. 不知道Postman的朋友,可以去看看我之前寫的Twitter篇
串接Json資料
我的App用到了lady gaga的profile,專輯,熱門歌曲,相關歌手
這些resource url可詳見spotify的網站
我們以熱門歌曲為例,用到以下項目
struct spotifyTrackData: Identifiable {
var id: String
var name: String
var artists: String
var imgurl: String
var external_urls: String
}
雖然Json有preview_url可以試聽30秒,但是Lady Gaga的歌曲在這一欄都是null,我就退而求其次,使用external_urls
接著利用Postman的幫我們寫的Code串接
class getspotifyTrackData: ObservableObject {
@Published var data = [spotifyTrackData]()
init(){
let token = test()
var request = URLRequest(url: URL(string: "https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/top-tracks?country=TW")!,timeoutInterval: Double.infinity)
request.addValue("Bearer 你的token", forHTTPHeaderField: "Authorization")request.httpMethod = "GET"
let session = URLSession(configuration: .default)
session.dataTask(with: request){(data, _, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
let json = try! JSON(data: data!)
let tracks = json["tracks"].array!
for i in tracks{
let id = i["id"].stringValue
let name = i["name"].stringValue
let imgurl = i["album"]["images"][0]["url"].stringValue
let artistArr = i["artists"].array!
var artists = ""
for j in artistArr{
if artists == ""{
artists = j["name"].stringValue
}
else {
artists = artists + "," + j["name"].stringValue
}
}
let external_urls = i["external_urls"]["spotify"].stringValue
DispatchQueue.main.async {
self.data.append(spotifyTrackData(id: id, name: name, artists: artists, imgurl: imgurl, external_urls: external_urls))
}
}
}.resume()
}
}
此時我眉頭一皺,發現事情並不單純
回頭看看Bearer Token,發現使用期限只有3600秒,也就是1小時
token過期可是拿不到資料的,所以需要refresh token幫你拿到新的token
curl -H "Authorization: Basic 第四步的結果" -d grant_type=refresh_token -d refresh_token=你的refresh token https://accounts.spotify.com/api/token
可以用以上指令到終端機獲得新的指令,但每一個小時就要換一次太麻煩了,我們直接把指令寫在App裡,每次開啟就會獲得新的token
至於怎麼寫,又要請Postman幫忙了
Username是Client ID,Password是Client Secret
除了Authorization,Body也要加入項目
按下send後就會有新的token
而Postman寫的Code如下:
import Foundationvar semaphore = DispatchSemaphore (value: 0)let parameters = "grant_type=refresh_token&refresh_token=你的refresh token"
let postData = parameters.data(using: .utf8)var request = URLRequest(url: URL(string: "https://accounts.spotify.com/api/token")!,timeoutInterval: Double.infinity)
request.addValue("", forHTTPHeaderField: "")
request.addValue("Basic 第四步的結果", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("__Host-device_id=AQBPwRuubEaHLe3qzncUC_qxhNi3w6W_sXdPNQenUVz1lXG86eZs3u2hW3kbO2RZEz7-XaJA9gE6J-ZHFpnGNlfS-n3BCM6aYe4", forHTTPHeaderField: "Cookie")request.httpMethod = "POST"
request.httpBody = postDatalet task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}task.resume()
semaphore.wait()
再結合寫的Code串接熱門歌曲,完整程式碼如下
class getspotifyTrackData: ObservableObject {
@Published var data = [spotifyTrackData]()
init(){
let parameters = "grant_type=refresh_token&refresh_token=你的refresh token"
let postData = parameters.data(using: .utf8)
if let url = URL(string: "https://accounts.spotify.com/api/token"){
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Basic 第四步的結果", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("__Host-device_id=AQBPwRuubEaHLe3qzncUC_qxhNi3w6W_sXdPNQenUVz1lXG86eZs3u2hW3kbO2RZEz7-XaJA9gE6J-ZHFpnGNlfS-n3BCM6aYe4; __Secure-TPASESSION=AQCz/AtmF0i7zemzOI63JpokY8izsrk2ImSVSTMRoV9wFeKzaJ3fo6PpoDMKHrlkARSTo8l56+mTXLbOHybt/hF9KwIxAZ4C11Q=; csrf_token=AQDysFWy0rN9M1GtLlb6eRbkaTuqNeRmyQmw5VIxjzUTAVHxYgmK41DZhtFdkivrgIZcEgbMBqQFFmDlGQ", forHTTPHeaderField: "Cookie")
request.httpBody = postData
URLSession.shared.dataTask(with: request) { (data, response, error) in
let json = try! JSON(data: data!)
let token = json["access_token"].stringValue
var request = URLRequest(url: URL(string: "https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/top-tracks?country=TW")!,timeoutInterval: Double.infinity)
request.addValue("Bearer " + token, forHTTPHeaderField: "Authorization")request.httpMethod = "GET"
let session = URLSession(configuration: .default)
session.dataTask(with: request){(data, _, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
let json = try! JSON(data: data!)
let tracks = json["tracks"].array!
for i in tracks{
let id = i["id"].stringValue
let name = i["name"].stringValue
let imgurl = i["album"]["images"][0]["url"].stringValue
let artistArr = i["artists"].array!
var artists = ""
for j in artistArr{
if artists == ""{
artists = j["name"].stringValue
}
else {
artists = artists + "," + j["name"].stringValue
}
}
let external_urls = i["external_urls"]["spotify"].stringValue
DispatchQueue.main.async {
self.data.append(spotifyTrackData(id: id, name: name, artists: artists, imgurl: imgurl, external_urls: external_urls))
}
}
}.resume()
}.resume()
}
}
}
至於畫面設計,下載我的app來細細品嚐吧!
5.結語:
spotify應該是這五個api裡,串起來最累的,為了取得token讓我煞費苦心
如果觀眾老爺有看不懂的地方,可以留言告訴我;覺得這篇文章對你有幫助,不妨幫我拍手以及follow我