๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Android]DownloadManager

๊ฐœ์š” : https://developer.android.com/reference/android/app/DownloadManager

์žฅ์‹œ๊ฐ„ HTTP ๋‹ค์šด๋กœ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹œ์Šคํ…œ ์„œ๋น„์Šค

ํด๋ผ์ด์–ธํŠธ๋Š” ํŠน์ • ๋ชฉ์ ์ง€์ธ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•  URI๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค.

๋‹ค์šด๋กœ๋“œ ๋งค๋‹ˆ์ €๋Š” HTTP ์ƒํ˜ธ ์ž‘์šฉ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹คํŒจ ํ›„ ๋˜๋Š” ์—ฐ๊ฒฐ ๋ณ€๊ฒฝ ๋ฐ ์‹œ์Šคํ…œ ์žฌ๋ถ€ํŒ… ์ „๋ฐ˜์— ๊ฑธ์ณ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์žฌ์‹œ๋„ํ•˜๋ฉด์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

ACTION_NOTIFICATION_CLICKED์— ๋Œ€ํ•ด ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ๋ฆฌ์‹œ๋ฒ„๋ฅผ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์ด๋‚˜ ๋‹ค์šด๋กœ๋“œ UI๋กœ ์ง„ํ–‰ ์ค‘์ธ ๋‹ค์šด๋กœ๋“œ๋ฅผ ํด๋ฆญํ•  ๊ฒฝ์šฐ์— ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Manifest.permission.INTERNET ํผ๋ฏธ์…˜์ด ํ•„์š”ํ•˜๋‹ค.

 

๋ถˆํ•„์š”ํ•œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ชจ๋ฐ”์ผ ๋„คํŠธ์›Œํฌ ์‚ฌ์šฉ : https://developer.android.com/topic/performance/vitals/bg-network-usage

DownloadManager์˜ setNotificationVisibility(int)๋ฅผ ์„ค์ • > ์•ฑ์˜ ๋ชจ๋ฐ”์ผ ๋„คํŠธ์›Œํฌ ์‚ฌ์šฉ์„ ํฌ๊ทธ๋ผ์šด๋“œ๋กœ ์ด๋™์‹œํ‚ค๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ์ง„ํ–‰ ์ค‘์ž„์„ ์•Œ๋ฆฌ๊ณ  ๋‹ค์šด๋กœ๋“œ๋ฅผ ์ผ์‹œ์ค‘์ง€ํ•˜๊ฑฐ๋‚˜ ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์ œ์–ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

 

DownloadManager.Request : https://developer.android.com/reference/kotlin/android/app/DownloadManager.Request?hl=ko#setnotificationvisibility

open fun setNotificationVisibility(visibility: Int) : DownloadManager.Request!

 

๋‹ค์šด๋กœ๋“œ๊ฐ€ ์ง„ํ–‰ ์ค‘์ด๊ฑฐ๋‚˜ ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์šด๋กœ๋“œ ๋งค๋‹ˆ์ €์— ์˜ํ•ด ์‹œ์Šคํ…œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์ด ๊ฒŒ์‹œ๋  ์ง€๋ฅผ ์ œ์–ดํ•œ๋‹ค. ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด, ๋‹ค์šด๋กœ๋“œ ๋งค๋‹ˆ์ €๋Š” ์‹œ์Šคํ…œ android.app.NotificationManager๋ฅผ ํ†ตํ•ด ๋‹ค์šด๋กœ๋“œ์— ๊ด€ํ•œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜๋“ค์„ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณดํ†ต ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์€ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ์ง„ํ–‰ ์ค‘์ผ ๋•Œ์—๋งŒ ๋ณด์ธ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ’๋“ค(visibiltiy ํŒŒ๋ผ๋ฏธํ„ฐ)์„ ์‚ฌ์šฉํ•œ๋‹ค. : VISIBILITY_HIDDEN, VISIBILITY_VISIBLE, VISIBILITY_VISIBLE_NOTIFY_COMPLETED

 VISIBILTIY_HIDDEN ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ, android.permission.DOWNLOAD_WITHOUT_NOTIFICATION ํผ๋ฏธ์…˜์ด ํ•„์š”ํ•˜๋‹ค.

 

NetworkSecurityPolicy : https://developer.android.com/reference/kotlin/android/security/NetworkSecurityPolicy

๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ •์ฑ…. 

cleartext(ํ‰๋ฌธ. ์ผ๋ฐ˜์ธ ๋ˆ„๊ตฌ๋‚˜ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์„œ. http://www.ktword.co.kr/test/view/view.php?m_temp1=4240) ์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด ํ”Œ๋žซํผ์˜ ์ปดํฌ๋„ŒํŠธ( HTTP์™€ FTP stacks, android.app.DownloadManager, android.media.MediaPlayer ๋“ฑ)๋Š” cleartext traffic์„ ์ด์šฉํ•˜๋ ค๋Š” ํ”„๋กœ์„ธ์Šค์˜ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค. 

open fun isCleartextTrafficPermitted() : Boolean์„ ํ†ตํ•ด cleartext ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ(HTTP, FTP, WebSockets, XMPP, IMAP, SMTP - TLS๋‚˜ STARTTLS๋Š” ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค)์ด ํ”„๋กœ์„ธ์Šค์˜ ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์— ํ—ˆ์šฉ๋๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

<application android:usesCleartextTraffic=["true"|"false"]> : https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic

android:usesCleartextTraffic

์•ฑ์ด ์ผ๋ฐ˜ ํ…์ŠคํŠธ HTTP์™€ ๊ฐ™์€ ์ผ๋ฐ˜ ํ…์ŠคํŠธ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. API ๋ ˆ๋ฒจ 27 ์ดํ•˜๋ฅผ ํƒ€๊ฒŸํŒ…ํ•˜๋Š” ์•ฑ์—์„œ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด "true"์ด๊ณ , API ๋ ˆ๋ฒจ 28 ์ด์ƒ์„ ํƒ€๊ฒŸํŒ…ํ•˜๋Š” ์•ฑ์—์„œ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด "false"์ž…๋‹ˆ๋‹ค.

์ด ์†์„ฑ์ด "false"๋กœ ์„ค์ •๋˜๋ฉด ํ”Œ๋žซํผ ๊ตฌ์„ฑ์š”์†Œ(์˜ˆ: HTTP ๋ฐ FTP ์Šคํƒ, DownloadManager, MediaPlayer)๋Š” ์•ฑ์˜ ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํŠธ๋ž˜ํ”ฝ ์‚ฌ์šฉ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์ด ์„ค์ •์„ ์ค€์ˆ˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํŠธ๋ž˜ํ”ฝ์„ ํ”ผํ•˜๋Š” ์ฃผ์š” ์ด์œ ๋Š” ๊ธฐ๋ฐ€์„ฑ, ์ง„์‹ค์„ฑ์ด ๋ณด์žฅ๋˜์ง€ ์•Š๊ณ  ๋ณ€์กฐ ๋ฐฉ์ง€๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ๊ณต๊ฒฉ์ž๋Š” ์ „์†ก๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋„์ฒญํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋“คํ‚ค์ง€ ์•Š๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ๊ณต๋˜๋Š” ์•ก์„ธ์Šค ์ˆ˜์ค€์œผ๋กœ ์ธํ•ด Android ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‚˜์˜ค๋Š” ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํŠธ๋ž˜ํ”ฝ์„ ๋ชจ๋‘ ์ฐจ๋‹จํ•  ์ˆ˜๋Š” ์—†์œผ๋ฏ€๋กœ, ์ด ํ”Œ๋ž˜๊ทธ๋Š” ์ตœ๋Œ€ํ•œ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Socket API๋Š” ํŠธ๋ž˜ํ”ฝ์ด ์ผ๋ฐ˜ ํ…์ŠคํŠธ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ํŒ๋ณ„ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐ ์žˆ์–ด ์˜ˆ์™ธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‚˜์˜ค๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์€ ์ƒ์œ„ ์ˆ˜์ค€ ๋„คํŠธ์›Œํฌ ์Šคํƒ/๊ตฌ์„ฑ์š”์†Œ์—์„œ ์ฒ˜๋ฆฌ๋˜๋ฉฐ, ์ด ๊ฒฝ์šฐ ApplicationInfo.flags ๋˜๋Š” NetworkSecurityPolicy.isCleartextTrafficPermitted()์—์„œ ์ฝ์–ด ๋“ค์—ฌ ์ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ฑ ๊ฐœ๋ฐœ ์ค‘์— StrictMode๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ์˜ ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํŠธ๋ž˜ํ”ฝ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ StrictMode.VmPolicy.Builder.detectCleartextNetwork()๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ด ์†์„ฑ์€ API ๋ ˆ๋ฒจ 23์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ํ”Œ๋ž˜๊ทธ๋Š” Android 7.0(API ๋ ˆ๋ฒจ 24) ์ด์ƒ์—์„œ Android ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ๊ตฌ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.

 

Android 7.0 ๋™์ž‘ ๋ณ€๊ฒฝ ์‚ฌํ•ญ : ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ถŒํ•œ ๋ณ€๊ฒฝ : https://developer.android.com/about/versions/nougat/android-7.0-changes

 

DownloadManager๋Š” ๋น„๊ณต๊ฐœ๋กœ ์ €์žฅ๋œ ํŒŒ์ผ์„ ๋” ์ด์ƒ ํŒŒ์ผ ์ด๋ฆ„๋ณ„๋กœ ๊ณต์œ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ ˆ๊ฑฐ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ COLUMN_LOCAL_FILENAME์— ์•ก์„ธ์Šคํ•  ๋•Œ ์•ก์„ธ์Šค๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Android 7.0 ์ด์ƒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์•ฑ์€ COLUMN_LOCAL_FILENAME์— ์•ก์„ธ์Šคํ•  ๋•Œ SecurityException์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.  DownloadManager.Request.setDestinationInExternalFilesDir() ๋˜๋Š” DownloadManager.Request.setDestinationInExternalPublicDir()์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์šด๋กœ๋“œ์œ„์น˜๋ฅผ ๊ณต์šฉ ์œ„์น˜๋กœ ์„ค์ •ํ•˜๋Š” ๋ ˆ๊ฑฐ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ COLUMN_LOCAL_FILENAME์— ์žˆ๋Š” ๊ฒฝ๋กœ์— ์—ฌ์ „ํžˆ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ๋ฉ”์„œ๋“œ๋Š” ๋ถ€๋“์ดํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. DownloadManager์— ์˜ํ•ด ๋…ธ์ถœ๋˜๋Š” ํŒŒ์ผ์— ์•ก์„ธ์Šคํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ContentResolver.openFileDescriptor()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

DownloadManager.Request : https://developer.android.com/reference/kotlin/android/app/DownloadManager.Request?hl=ko#setdestinationinexternalfilesdir

open fun setDestinationInExternalFileDir(context: Context!, dirType: String!, subPath: String!) : DownloadManager.Request!

๋‹ค์šด๋กœ๋“œํ•œ ํŒŒ์ผ์˜ ๋กœ์ปฌ ์œ„์น˜๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์™ธ๋ถ€ ํŒŒ์ผ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ ๊ฒฝ๋กœ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(Context#getExternalFilesDir(String)์—์„œ ๋ฐ˜ํ™˜๋จ). ๋‹ค์šด๋กœ๋“œํ•œ ํŒŒ์ผ์€ MediaScanner์—์„œ ์Šค์บ”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ allowScanningByMediaScanner()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์Šค์บ” ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

open fun setDestinationInExternalPyblicDir(dirType: String!, dubPath: String!) : DownloadManager.Request!

๋‹ค์šด๋กœ๋“œํ•œ ํŒŒ์ผ์˜ ๋กœ์ปฌ ๋Œ€์ƒ์„ ๊ณต์šฉ ์™ธ๋ถ€ ์ €์žฅ์†Œ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋‚ด์˜ ๊ฒฝ๋กœ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(Environment#getExternalStoragePublicDirectory(String)์—์„œ ๋ฐ˜ํ™˜๋จ). ๋‹ค์šด๋กœ๋“œํ•œ ํŒŒ์ผ์€ MediaScanner์—์„œ ์Šค์บ”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ allowScanningByMediaScanner()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์Šค์บ” ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. android.os.Build.VERSION_CODES#Q ์ด์ƒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ WRITE_EXTERNAL_STORAGE ๊ถŒํ•œ์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ dirType์€ Environment#DIRECTORY_DOWNLOADS, Environment#DIRECTORY_PICTURES, Environment#DIRECTORY_MOVIES ๋“ฑ๊ณผ ๊ฐ™์€ ์•Œ๋ ค์ง„ ๊ณต๊ฐœ ๋””๋ ‰ํ† ๋ฆฌ ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

Context DOWNLOAD_SERVICE : https://developer.android.com/reference/kotlin/android/content/Context?hl=pt#download_service

static val DOWNLOAD_SERVICE: String

HTTP ๋‹ค์šด๋กœ๋“œ๋ฅผ ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด android.app.DownloadManager๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด getSystemService(java.lang.String)์™€ ์‚ฌ์šฉํ•œ๋‹ค.

Value: "download"