๊ฐ์ : 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"