[내배캠/TIL(8/8)/kotlin]안드로이드 서버로 사진 보내기

손홍서·2022년 8월 8일
0

day75 TIL

retrofit service

    @Multipart
    @POST("make/loc")
    fun makeMapCommunity(
        @Header("X-AUTH-TOKEN") token : String?,
        @Part communityImg: MultipartBody.Part,
        @Part("name") name : RequestBody,
        @Part("introduce") introduce : RequestBody
    ) : Call<MakeCommunity>

받아온 uri를 실제경로로 변경해 줘야한다.

            ActivityResultCallback {
             
                // API level 28 이하는 MediaStore.Images.Media.getBitmap 사용 (deprecated)
                // 그 이상부터 ImageDecoder.createSource 사용
                val bitmap = it?.let {
                    if (Build.VERSION.SDK_INT < 28) {
                        MediaStore.Images
                            .Media.getBitmap(context.contentResolver, it)
                    } else {
                        val source = ImageDecoder
                            .createSource(context.contentResolver, it)
                        ImageDecoder.decodeBitmap(source)
                    }
                }

                imgFile = UriUtil.toFile(context, it!!)
            }
        )

그런데 Android 10 이상에서는 저장소 접근 정책이 변경됨에 따라, 사용자가 선택한 파일의 URI에서 파일의 절대 경로를 얻어내는 것이 불가능해졌다. 따라서 불러온 이미지의 URI로부터 임시 파일로 복사본을 생성한 뒤, 해당 복사본을 서버에 업로드하는 방식으로 구현해야한다.

object FileUtil {
        // 임시 파일 생성
        fun createTempFile(context: Context, fileName: String): File {
            val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            return File(storageDir, fileName)
        }

        // 파일 내용 스트림 복사
        fun copyToFile(context: Context, uri: Uri, file: File) {
            val inputStream = context.contentResolver.openInputStream(uri)
            val outputStream = FileOutputStream(file)

            val buffer = ByteArray(4 * 1024)
            while (true) {
                val byteCount = inputStream!!.read(buffer)
                if (byteCount < 0) break
                outputStream.write(buffer, 0, byteCount)
            }

            outputStream.flush()
        }
    }


    object UriUtil {
        // URI -> File
        fun toFile(context: Context, uri: Uri): File {
            val fileName = getFileName(context, uri)

            val file = FileUtil.createTempFile(context, fileName)
            FileUtil.copyToFile(context, uri, file)

            return File(file.absolutePath)
        }

        // get file name & extension
        fun getFileName(context: Context, uri: Uri): String {
            val name = uri.toString().split("/").last()
            val ext = context.contentResolver.getType(uri)!!.split("/").last()

            return "$name.$ext"
        }
    }

서버와 통신

                val imgRequestBody = MultipartBody.Part.createFormData("communityImg", imgFile.name, requestFile)
                Log.d("LISTENER", authType)
                val nameRequestBody : RequestBody = communityName.toPlainRequestBody()
                val introduceRequestBody : RequestBody = introduce.toPlainRequestBody()
  RetrofitService.communityService.makeMapCommunity(sharedManager.getToken(), imgRequestBody, nameRequestBody, introduceRequestBody)?.enqueue(object :
                        retrofit2.Callback<MakeCommunity> {
                        override fun onResponse(
                            call: Call<MakeCommunity>,
                            response: Response<MakeCommunity>
                        ) {
                            ...
                        }

                        override fun onFailure(call: Call<MakeCommunity>, t: Throwable) {
                            ...
                        }
                    })
private fun String?.toPlainRequestBody() = RequestBody.create(MediaType.parse("text/plain"), this)

참고자료
https://yjyoon-dev.github.io/android/2022/04/09/android-05/

profile
Hello World!!

0개의 댓글