Ktor HttpClientで画像をアップロードするコードを紹介する。
使用したプログラミング言語とライブラリのバージョン
- Kotlin 1.6.10
- Jetpack Compose 1.1.1
- Ktor 2.0.0
Ktor HttpClientで画像をアップロードする
build.gradleの編集
build.gradle (:app) に以下の行を追加する。
implementation "io.ktor:ktor-client-core:2.0.0"
implementation "io.ktor:ktor-client-android:2.0.0"
画像をアップロードする
関数storeは、引数にアップロードするBitmapと、レスポンスを返す関数をとる。
画像はJPEGに変換してアップロードする。
val jpg = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)
HttpClientはデフォルトのエンジンを使用する。
後で、レスポンスをJSONに変換するコードを追加する。
val client = HttpClient()
HttpClientのsubmitFormWithBinaryData()メソッドを使用して画像をアップロードする。
val response = client.submitFormWithBinaryData(
url = "http://192.168.10.114/upload.php",
formData = formData {
appendInput(key = "file", headers = Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
}) {
buildPacket {
writeFully(jpg.toByteArray())
}
}
}
)
全体のコードは次のようになる。
object ImageRepository {
suspend fun store(bitmap: Bitmap, onResult: (String?) -> Unit) {
val jpg = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)
val client = HttpClient()
val response = client.submitFormWithBinaryData(
url = "http://192.168.10.114/upload.php",
formData = formData {
appendInput(key = "file", headers = Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
}) {
buildPacket {
writeFully(jpg.toByteArray())
}
}
}
)
onResult(response.bodyAsText())
}
}
JSONのレスポンスを受け取る
レスポンスのJSONをパースして、オブジェクトを返す。
build.gradleの編集
build.gradle (:app) に以下の行を追加する。
plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.10' // 追加
}
dependencies {
implementation 'io.ktor:ktor-serialization-kotlinx-json:2.0.0' // 追加
implementation 'io.ktor:ktor-client-content-negotiation:2.0.0' // 追加
implementation 'org.jetbrains.kotlin:kotlin-serialization:1.6.21' // 追加
}
JSONのレスポンスを受け取る
パースするJSONの形式に合わせてクラスを作成する。
@Serializable
data class StoreResponse(
val success: String? = null,
val error: String? = null,
val filename: String? = null
)
HttpClientがJSONを扱えるように設定する。
val client = HttpClient {
install(ContentNegotiation) {
json(json = Json, contentType = ContentType.Application.Json)
}
}
そうすると、自動的にクラスに合わせてパースしてくれる。
val response: StoreResponse = client.submitFormWithBinaryData(
// 省略
).body()
全体のコードは次のようになる。
object ImageRepository {
suspend fun upload(bitmap: Bitmap, onResult: (StoreResponse?) -> Unit) {
val jpg = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)
val client = HttpClient {
install(ContentNegotiation) {
json(json = Json, contentType = ContentType.Application.Json)
}
}
val response: StoreResponse = client.submitFormWithBinaryData(
url = "http://192.168.10.114/upload.php",
formData = formData {
appendInput(key = "file", headers = Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
}) {
buildPacket {
writeFully(jpg.toByteArray())
}
}
}
).body()
onResult(response)
}
}
@Serializable
data class StoreResponse(
val success: String? = null,
val error: String? = null,
val filename: String? = null
)