2021. 5. 27. 14:21ㆍAndroid
ㅇ 파일 다운로드 및 저장
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
* android 10 => androidManifest > android:requestLegacyExternalStorage="true"
- Android 버전(Android 11 / R)에서는 Target SDK 버전과 관계없이 모든 앱에 Scoped mode를 적용
- android 11에서 기존 권한(android.permission.WRITE_EXTERNAL_STORAGE) 무시됨
- 범위지정저장소는 미디어콜렉션 안에서 자신의 앱에 해당하는 곳은 접근 권한 요청없이 접근이 가능하다는 차이점이 있음
이를 통해 기존의 불필요한 사용자 권한 요청을 줄일 수 있다는 장점. 하지만 다른 앱이 생성한 미디어 파일에 접근하는 경우는 권한 필요
- Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION ->
저장소 액세스 프레임워크 또는 MediaStore api등 개인정보를 더 안전하게 보호하는 권장사항을 효과적으로 사용할 수 없는 경우에만 모든 파일 액세 권한을 요청함(기존 파일 저장로직으로도 됨)
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION 요청시 아래 참고
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
try {
startActivityForResult(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
addCategory("android.intent.category.DEFAULT")
data = Uri.parse(String.format("package:%s", applicationContext.packageName))
}, 300)
} catch (e: Exception) {
startActivityForResult(Intent().apply {
action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
}, 300)
}
} else {
startActivity()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 300) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
startActivity()
} else {
finish()
}
}
}
}
* android 11에서 기존 퍼미션(android.permission.WRITE_EXTERNAL_STORAGE) 획득없이도 MediaStore로 파일 저장 가능
val fileName = param.substringAfterLast("/") // download url
val body = response.body()
val mimeType = fileName.substring(fileName.indexOf(".") + 1, fileName.length)
try {
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
val fileReader = ByteArray(4096)
var fileSizeDownloaded: Long = 0
inputStream = body?.byteStream()
outputStream = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver = applicationContext.contentResolver
val uri = resolver.insert(MediaStore.Files.getContentUri("external"), ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
put(MediaStore.MediaColumns.MIME_TYPE, "application/$mimeType")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + "folderName")
})
uri?.let { resolver.openOutputStream(it) }
} else {
val folderPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path + File.separator + "folderName"
val folder = File(folderPath)
if (!folder.exists()) {
folder.mkdirs()
}
val file = File(folderPath + File.separator + fileName)
if (file.exists()) {
file.delete()
}
FileOutputStream(file)
}
if (outputStream != null) {
while (true) {
val read: Int? = inputStream?.read(fileReader)
if (read == -1) {
break
}
outputStream?.write(fileReader, 0, read!!)
fileSizeDownloaded += read?.toLong()!!
}
outputStream?.flush()
}
} catch (e: IOException) {
Log.d("IOException: ${e.printStackTrace()}")
} finally {
inputStream?.close()
outputStream?.close()
}
} catch (e: IOException) {
Log.d("IOException: ${e.printStackTrace()}")
}
[참고 : https://ddolcat.tistory.com/490]
[참고 : https://youngest-programming.tistory.com/386]
https://smartstore.naver.com/byrollin?
'Android' 카테고리의 다른 글
Filterable (0) | 2021.11.04 |
---|---|
AppUpdateManager (0) | 2021.10.26 |
안드로이드 RecyclerView 성능 개선팁 (0) | 2020.12.10 |
HorizontalScrollView Scroll Animation (0) | 2020.12.10 |
ViewPager (0) | 2020.03.29 |