ScopedStoage 모드에서 아무런 권한이 없어도 MediaStore api를 사용하지 않고도, Pictures 폴더에 이미지 저장이 가능한가?
App Target sdk 31
Android 11 에서 테스트
AndroidManifest에 어떤한 권한이나, element 수정이 없이 기본 값으로 테스트
@RequiresApi(Build.VERSION_CODES.Q)
private fun onClickButton1(v: View) {
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val filename = System.currentTimeMillis().toString() + ".jpg"
val file = File(dir, filename)
val bitmap = viewToBitmap(binding.text1)
saveBitmap(bitmap, file)
scanMediaFile(file)
Toast.makeText(requireContext(), "isScopedStorage=${!Environment.isExternalStorageLegacy()}", Toast.LENGTH_SHORT).show()
}
private fun viewToBitmap(view: View): Bitmap {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.layout(view.left, view.top, view.right, view.bottom)
view.draw(canvas)
return bitmap
}
private fun saveBitmap(bitmap: Bitmap, file: File) {
val fos = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
fos.flush();
fos.close();
}
private fun scanMediaFile(file: File) {
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
val contentUri: Uri = Uri.fromFile(file)
mediaScanIntent.data = contentUri
requireContext().sendBroadcast(mediaScanIntent)
}
결과는
isScopedStorage=true, 이미지 저장도 잘 되고, OS 갤러리에 이미지도 잘 표시된다.
관련 기술 문서는 :
Storage updates in Android 11 | Android Developers
Access files using direct file paths and native librariesTo help your app work more smoothly with third-party media libraries, Android 11 allows you to use APIs other than the MediaStore API to access media files from shared storage using direct file paths. These APIs include the following:
|
Access media files from shared storage | Android Developers
Direct file pathsTo help your app work more smoothly with third-party media libraries, Android 11 (API level 30) and higher allow you to use APIs other than the MediaStore API to access media files from shared storage. You can instead access media files directly using either of the following APIs:
If your app tries to access a file using the File API and it doesn't have the necessary permissions, a FileNotFoundException occurs. To access other files in shared storage on a device that runs Android 10 (API level 29), it's recommended that you temporarily opt out of scoped storage by setting requestLegacyExternalStorage to true in your app's manifest file. In order to access media files using native files methods on Android 10, you must also request the READ_EXTERNAL_STORAGE permission. |
WRITE_EXTERNAL_STORAGE 퍼미션은 어떻게 응답하는가?
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
private val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
private fun onClickFav(v: View) {
ActivityCompat.requestPermissions(this, permissions, 100)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 100) {
permissions.forEachIndexed { index, permission ->
val isGranted = grantResults[index] == PackageManager.PERMISSION_GRANTED
Log.e("__T", "$permission -> isGranted = $isGranted")
}
}
}
결과는 두 개다 isGranted = true, 그렇다고 sd카드 root에 폴더를 만들수 있는 것은 아니다. 그럴려면 MANAGE_EXTERNAL_STORAGE 권한이 필요. 어쨌든 WRITE_EXTERNAL_STORAGE 퍼미션에 android:maxSdkVersion=" "을 추가해 놓은 예제를 봐서.. maxSdk SDK_INT에 따라서 WRITE_EXTERNAL_STORAGE를 제외하지 않아도 될 것 같다.
관련 기술 문서는:
Storage updates in Android 11 | Android Developers
Target any versionThe following changes take effect in Android 11, regardless of your app's target SDK version:
Target Android 11If your app targets Android 11, both the WRITE_EXTERNAL_STORAGE permission and the WRITE_MEDIA_STORAGE privileged permission no longer provide any additional access.Keep in mind that, on devices that run Android 10 (API level 29) or higher, your app can contribute to well-defined media collections such as MediaStore.Downloads without requesting any storage-related permissions. Learn more about how to request only the necessary permissions when working with media files in your app. |