728x90
안드로이드 코틀린 언어로 Retrofit2 를 활용하여서 이미지 전송 해보겠습니다.
php 는 제가 모르는 관계로 게시하지 못했습니다.
- 환경구성
- 인터페이스
- 이미지 업로드
의 순서로 작성해보겠습니다.
1. 환경구성
ViewBinding - build.gradle (:app)
.
.
.
kotlinOptions {
jvmTarget = '1.8'
}
viewBinding{
enabled true
}
}
http 설정 - androidManifest.xml
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
Permission - build.gradle (:app)
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
implementation - build.gradle (:app)
dependencies {
.
.
.
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.retrofit2:converter-gson:2.8.1"
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
}
그래들 파일에서 꼭 Sync Now 해주세요.
2. 인터페이스 구성
APIS.kt
interface APIS {
@Multipart
@POST(PHP파일주소)
fun sendImage(
@Part upload : MultipartBody.Part?,
):Call<String>
companion object{
private const val url = 서버주소
fun create():APIS{
val interceptor = HttpLoggingInterceptor()
.apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(interceptor).build()
val gson = GsonBuilder()
.setLenient()
.create()
return Retrofit.Builder()
.baseUrl(url)
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(APIS::class.java)
}
}
}
인터셉터를 사용하여서 이미지 업로드되는 부분을 상세하게 확인해보았습니다.
3.이미지 업로드
class SendImageActivity : AppCompatActivity() {
private val binding by lazy { ActivitySendImageBinding.inflate(layoutInflater) }
val api = APIS.create() // 인터페이스
private val TAG = "이미지전송로그"
private lateinit var imageResult: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
imageResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
if (result.data?.clipData != null){
// 여러장( 미구현 )
}else{
// 한장
result.data?.data?.let { uri->
val imageUri :Uri? = result.data?.data
if (imageUri!=null){
val file = File(getPath(this,imageUri))
var requestBody = file.asRequestBody("image/jpg".toMediaTypeOrNull())
var body = MultipartBody.Part.createFormData("upload", createFileName(), requestBody)
api.sendImages(body).enqueue(object :Callback<String>{
override fun onResponse(
call: Call<String>,
response: Response<String>
) {
Log.d(TAG, "onResponse: ${response.body()}")
}
override fun onFailure(call: Call<String>, t: Throwable) {
Log.e(TAG, "onFailure: ${t.message}", )
}
})
}
}
}
}
}
binding.btnLoad.setOnClickListener {
selectImage()
}
}
private fun selectImage() {
val writePms =
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
val readPms =
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
if (writePms == PackageManager.PERMISSION_DENIED||readPms == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE),
1
)
} else {
val intent = Intent()
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true)
intent.action = Intent.ACTION_GET_CONTENT
imageResult.launch(intent)
}
}
private fun createFileName(): String {
val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
val filename = sdf.format(System.currentTimeMillis())
return "$filename.jpg"
}
@Nullable
private fun getPath(context: Context,uri:Uri):String?{
val contentResolver = context.contentResolver ?: return null
val filePath :String=(context.applicationInfo.dataDir+File.separator+System.currentTimeMillis())
val file = File(filePath)
try {
val inputStream = contentResolver.openInputStream(uri) ?: return null
val outputStream = FileOutputStream(file)
val buf = ByteArray(1024)
var len : Int
while (inputStream.read(buf).also { len = it }>0)outputStream.write(buf,0,len)
outputStream.close()
inputStream.close()
}catch (e:Exception){
Log.e(TAG, "getPath: ${e.message}", )
return null
}
return file.absolutePath
}
}
버튼을 클릭하면 권한을 확인합니다
권한이 허락되어 있으면 갤러리를 엽니다.
multiple 이므로 여러장 선택이 가능하지만 아직 미구현입니다.
인텐트를 통하여 갤러리 사진 주소를 가져와서 그 주소를 절대주소로 변환합니다.
변환된 절대주소를 이용하여 File로 변환합니다
변환된 파일을 MultiPartBody로 변환후 api를 이용해 파일을 전송합니다.
php로 파일을 업로드 합니다.
궁금하신 부분이나 코드에 문제점이 있으면 댓글로 남겨주세요 감사합니다.
'한국 20대 개발자의 성장기' 카테고리의 다른 글
| [Kotlin] MutableList clear (0) | 2022.12.12 |
|---|---|
| [kotlin] Dialog 다이얼로그 간단하게 띄우기 (2) | 2022.12.07 |
| [Kotlin] NestedScrollView 이용하여 스크롤 부드럽게 만들기 (0) | 2022.12.05 |
| [Koltin] 화면 전환 부드럽게 하기 (0) | 2022.12.05 |
| [Kotlin] 키보드 외 공간 터치하면 키보드 내려가기 (0) | 2022.12.05 |