Programming/Android
[Kotlin/Android] Ktor 를 이용한 Api 통신
생각하는로뎅
2024. 3. 24. 13:55
반응형
Ktor 은 Server 와 Client가 있고, 글쓴이는 Client 를 사용 한다.
사용할 Ktor 버전은 2.3.9 이고, 로그인 기능을 구현해 볼 것이다.
https://ktor.io/docs/getting-started-ktor-client.html
Creating a client application | Ktor
ktor.io
라이브러리를 사용하기 위해서, 아래와 같이 사전 작업이 필요하다.
0. AndroidManifest.xml
인터넷을 사용하기 위해서는 퍼미션을 꼭 설정해 준다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
.....
</application>
</manifest>
1. settings.gradle.kts
pluginManagement {
repositories {
....
maven {
setUrl("https://kotlin.bintray.com/kotlinx")
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "kotlinx-serialization") {
useModule("org.jetbrains.kotlin:kotlin-serialization:${requested.version}")
}
}
}
}
}
2. build.gradle.kts : Project Level
plugins {
...
id("org.jetbrains.kotlin.plugin.serialization") version "1.6.21" apply true
}
3. build.gradle.kts : app Level
plugins {
.....
id("kotlinx-serialization")
}
....
dependencies {
val ktor_version = "2.3.9"
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-android:$ktor_version")
implementation("io.ktor:ktor-client-json:$ktor_version")
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-client-serialization:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
}
Gradle Sync 후 코드로 구현한다.
4. LoginRequestBean.kt
@Serializable 을 이용하여, JSON 송신(Request)할 data class 를 생성한다.
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* 로그인
*/
@Serializable
data class LoginRequestBean (
@SerialName("email")
val id : String,
@SerialName("encryptedPassword")
val pwd : String
)
5. LoginResultBean.kt
@Serializable 을 이용하여, 서버로부터 JSON 수신(Receive) 결과를 받을 data class 를 생성한다.
package com.leestech.smarthealth.network.beans
import kotlinx.serialization.Serializable
/**
* 결과
*/
@Serializable
data class LoginResultBean (val result : Boolean)
6. HttpRequest.kt
1) _client 라는 HttpClient 를 객체를 생성하되, Json 통신을 하기 위한 각종 설정을 해주고,
// http client
private val _client : HttpClient = HttpClient(Android) {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
install(HttpTimeout) {
requestTimeoutMillis = _NETWORK_TIME_OUT
connectTimeoutMillis = _NETWORK_TIME_OUT
socketTimeoutMillis = _NETWORK_TIME_OUT
}
install(ResponseObserver) {
onResponse { response ->
Log.d("HTTP status:", "${response.status.value}")
}
}
install(DefaultRequest) {
header(HttpHeaders.ContentType, ContentType.Application.Json)
}
defaultRequest {
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
}
}
}
2) loginRequstBean.kt 객체 생성 후 setBody 에 주입하면 JSON 으로 변환되어 전송되어 진다.
결과는 body() 를 통해서 LoginResultBean에 JSON이 파싱되어 생성되어 진다.
// 결과 반환 객체
var response = LoginResultBean(false)
response = _client.post("$_serverUrl$_login") {
contentType(ContentType.Application.Json)
setBody(loginRequestBean)
}.body()
Full 코드는 아래와 같다.
import android.util.Log
import com.leestech.smarthealth.network.beans.LoginRequestBean
import com.leestech.smarthealth.network.beans.LoginResultBean
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpTimeout
import io.ktor.serialization.kotlinx.json.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.plugins.observer.ResponseObserver
import io.ktor.client.request.accept
import io.ktor.client.request.header
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import kotlinx.serialization.json.Json
class HttpRequest {
companion object {
const val _NETWORK_TIME_OUT = 6_000L
// 서버 주소
const val _serverUrl : String = "http://192.168.0.6/api/v2/"
// 로그인
const val _login : String = "login"
// http client
private val _client : HttpClient = HttpClient(Android) {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
})
install(HttpTimeout) {
requestTimeoutMillis = _NETWORK_TIME_OUT
connectTimeoutMillis = _NETWORK_TIME_OUT
socketTimeoutMillis = _NETWORK_TIME_OUT
}
install(ResponseObserver) {
onResponse { response ->
Log.d("HTTP status:", "${response.status.value}")
}
}
install(DefaultRequest) {
header(HttpHeaders.ContentType, ContentType.Application.Json)
}
defaultRequest {
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
}
}
}
/**
* 로그인 요청
*/
suspend fun requstLogin(id : String, pwd : String) : LoginResultBean {
// 결과 반환 객체
var response = LoginResultBean(false)
try {
var loginRequestBean = LoginRequestBean(id, pwd)
response = _client.post("$_serverUrl$_login") {
contentType(ContentType.Application.Json)
setBody(loginRequestBean)
}.body()
Log.i("Network", "ok")
} catch (ex : Exception) {
ex.message.let {
it.let {
Log.e("NetworkError", "$it")
}
}
} finally {
}
return response
}
}
}
7. 특정 액션에 따라서 아래와 같이 HttpRequest.requstLogin 를 호출하여 사용한다.
/**
* 로그인 요청
*/
fun requestLogin() {
// 로딩바 보이기
this.binding.spLoading.visibility = View.VISIBLE
CoroutineScope(Dispatchers.IO).launch {
val response = HttpRequest.requstLogin(binding.edId.text.toString(), binding.edPwd.text.toString())
CoroutineScope(Dispatchers.Main).launch {
// 로딩바 숨기기
binding.spLoading.visibility = View.GONE
// 로그인 성공시
if (response.result) {
// 화면 이동
} else {
// 로그인 실패시
context?.let {
AlertDialog.Builder(it).apply {
setMessage(getString(R.string.msg_fail_login))
setPositiveButton(getString(R.string.ok), DialogInterface.OnClickListener { dialog, which ->
})
show()
}
}
}
}
}
}
반응형