Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

안드로이드 앱 만들기 : File Download 구현 (ktor 활용)

Billcorea 2023. 2. 28. 01:29
반응형
안드로이드가 파일을 download 해야 한다고?

이런 일이 있을까 싶기도 합니다.  안드로이드 앱에서 파일을 받아야 한다니? 

 

하지만 그것이 필요한 시점이 되었을 때,  기초가 미흡한 입장에서는 어디서 찾아야 하는 가 하는 고민을 하게 됩니다. 

오늘은  ktor을 활용해 파일 받기 구현을 해 보았습니다. 

 

gradle 구성하기
// ktor download
implementation "io.ktor:ktor-client-android:1.2.5"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

앱 수준의 grade 파일에는 위와 같은 implementation 이 필요합니다. 

 

manifest에서 필요 권한  선언 하기
<uses-permission android:name="android.permission.INTERNET" />

당연한 이야기 이겠지만, internet 접속을 위한 권한은 있어야 합니다. 그래야 통신으로 원격지에 있는 파일을 받아올 테니까요.

인터넷을 활용하는 앱을 구성할 때 챙겨서 가야  하는 부분들이 있더군요. 인터넷은 비동기 통신을 하기 때문에 꼭 들어가야 합니다. 

 

<application
    ...
    android:usesCleartextTraffic="true"
    android:networkSecurityConfig="@xml/network_security_config"
    ...
    >

개발자 페이지 참조

요새는 다들 보안 때문에 HTTPS:// 으로 시작하는 대부분의 URL을 보게 되는 데, 예전 HTTP 통신보다는 인증서등을 활용해서 보안이 강화되어 기본적으로 안드로이드는 HTTPS 통신이 아닌 경우 처리가 되지 않습니다.  그래서 안드로이드에서는 http 통신을 해야 하는지에 대한 부분을 선언해 주어야 하거나,  아래와 같이 보안 구성을 해 주는 방식으로 처리를 해야 한다고 합니다.

 

network_security_config

이 파일은 res/xml 폴더에 network_security_config.xml로 작성 되어 있습니다. 저기에 기술되는 도메인이나, ip 등은 http로 접속을 해도 허용하도록 해 주는 것이지요.

<?xml version="1.0" encoding="utf-8"?>

<network-security-config>

    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">192.168.0.7</domain>
    </domain-config>

</network-security-config>

https://developer.android.com/training/articles/security-config?hl=ko 

 

네트워크 보안 구성  |  Android 개발자  |  Android Developers

앱 개발자가 안전한 구성 파일에서 네트워크 보안 설정을 사용자설정할 수 있는 기능입니다.

developer.android.com

좀 더 자세한 부분은 개발가이드를 참조해 보세요.

 

activity에서 download 받아 보기.

이제 download을 구현해 보겠습니다.  봐야 하는 부분은 파일을 저장할 경로입니다.  예전에는 sdcard 등등 External Storage에 권한을 이용해서 저장을 많이 하고는 했지만, 안드로이드가 보안에 적극적이면 앱이 사용할 수 있는 경로가 한정적으로 변해 왔습니다.

 

그래서 기본적으로 사용이 가능한 경로는 앱마다 가지게 되는 경로를 이용해서 저장을 하게 됩니다.

/sdcard/Android/data/패키지이름/files/Download를 지칭하게 됩니다.

val folder = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
val file = File(folder, tableOrder.pos_app_id)

val uri = FileProvider.getUriForFile(this@MainActivity, "${BuildConfig.APPLICATION_ID}.provider", file)

Log.e("","path= ${file.path} ${file.name}")

downloadFile(this@MainActivity, tableOrder.pos_file_link, uri)

 downloadFile  함수는 다음 코드처럼 구현을 할 수 있습니다.   이렇게 함수를 호출하는 것 만으로 파일을 내려받을 수 있습니다. 

private fun downloadFile(context: Context, url: String, file: Uri) {
    val ktor = HttpClient(Android)

    context.contentResolver.openOutputStream(file)?.let { outputStream ->
        CoroutineScope(Dispatchers.IO).launch {
            ktor.downloadFile(outputStream, url).collect {
                withContext(Dispatchers.Main) {
                    when (it) {
                        is DownloadResult.Success -> {
                            ... // 정상적으로 끝났을 때
                        }

                        is DownloadResult.Error -> {
                            ... // 처리 하다가 오류가 발생한 경우
                        }

                        is DownloadResult.Progress -> {
                            // 프로그램바 표시를 위한 처리
                            dataViewModels.downloadProgress.value = it.progress
                        }
                    }
                }
            }
        }
    }
}

 

오늘은 이상으로 파일 내려받기를 구현해 보았습니다.   아직 정리가 될 되어 실행하는 모습은 보여 드릴 수가 없네요.

아무튼 오늘도 하나 기억으로 남겨 두고자 글을 적었습니다. 

 

이 부분이랑, 받은 파일을 이용해서 설치 하는 코드를 구현 하느라 2일이 지나갔습니다.  다음에 안 그래야 할 텐데 말입니다. 

 

 

반응형