Android

Android 11 (Api 30) 파일 저장 관련

blackspade 2021. 5. 27. 14:21

ㅇ 파일 다운로드 및 저장

<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" />

https://ourcodeworld.com/articles/read/1559/how-does-manage-external-storage-permission-work-in-android

 

How does MANAGE_EXTERNAL_STORAGE permission work in Android?

Learn how the MANAGE_EXTERNAL_STORAGE permission works in android and how to implement it.

ourcodeworld.com



* 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? 

 

바이롤린 : 네이버쇼핑 스마트스토어

언제나 함께해요

smartstore.naver.com

 

'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