iOS這邊在取得授權碼後,一樣準備取得權杖
Modules
:
struct ShortAccessTokenResponse: Decodable {
var accessToken : String
var userId : Int
}
struct LongAccessTokenResponse: Decodable {
var accessToken : String
var tokenType : String
var expiresIn: Int64
}
AccessTokenRepository
:
func getShortAccessTokenInfo(clientId: String, clientSecret: String, code: String, redirectUri: String, completionHandler: @escaping (ShortAccessTokenResponse) -> Void) {
let url = URL(string: "https://api.instagram.com/oauth/access_token")!
let headers = [
"content-type": "multipart/form-data; boundary=\(boundary)"
]
let parameters = [
[
"name": "client_id",
"value": clientId
],
[
"name": "client_secret",
"value": clientSecret
],
[
"name": "grant_type",
"value": "authorization_code"
],
[
"name": "redirect_uri",
"value": redirectUri
],
[
"name": "code",
"value": code
]
]
var request = URLRequest(url: url)
let postData = getFormBody(parameters, boundary)
request.allHTTPHeaderFields = headers
request.httpMethod = "POST"
request.httpBody = postData
URLSession.shared.dataTask(with: request) {
data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let response = try decoder.decode(ShortAccessTokenResponse.self, from: data)
completionHandler(response)
} catch {
print(error.localizedDescription)
}
} else {
print("No Data")
}
}.resume()
}
func getLongAccessTokenInfo(accessToken: String,clientSecret: String,grantType: String, completionHandler: @escaping (LongAccessTokenResponse) -> Void) {
let url = URL(string: "https://graph.instagram.com/access_token?access_token=\(accessToken)&client_secret=\(clientSecret)&grant_type=\(grantType)")!
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) {
data, response, error in
if let data = data {
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let response = try decoder.decode(LongAccessTokenResponse.self, from: data)
completionHandler(response)
}catch(let error) {
print(error.localizedDescription)
}
} else {
print("No Data")
}
}.resume()
}
func logout() {
instagramUser = nil
}
AccessTokenViewModel
:
enum State {
case isLoading
case failed(Error)
case loaded(UserInfoResponse)
}
@Published private(set) var state :State? = nil
func getAccessToken(clientId: String, clientSecret: String, code: String, redirectUri: String) {
state = State.isLoading
AccessTokenRepository.shared.getShortAccessTokenInfo(clientId: clientId, clientSecret: clientSecret, code: code, redirectUri: redirectUri) { response in
DispatchQueue.main.async {
AccessTokenRepository.shared.getLongAccessTokenInfo(accessToken: response.accessToken, clientSecret: clientSecret, grantType: "ig_exchange_token") { longAccessTokenResponse in
AccessTokenRepository.shared.saveInstagramInfo(userId: clientId, accessToken: longAccessTokenResponse.accessToken, expiresIn: longAccessTokenResponse.expiresIn)
do {
try AccessTokenRepository.shared.getUserInfo { response in
self.state = State.loaded(response)
}
}catch(let error) {
print(error.localizedDescription)
self.state = State.failed(error)
}
}
}
}
}