2021. 2. 24. 10:45ㆍ바삭바삭 IT/안드로이드
안드로이드 버전10 이상부터는 Scoped Storage를 사용합니다. 이전 버전이였던 Legacy Storage와 어떤차이가 있는걸까요? 지난 포스트에서도 말했듯이 안드로이드의 저장소는 크게 내부저장소와 외부저장소로 나뉩니다. 두 버전에서 내부저장소는 동일하고 외부저장소의 구조가 살짝 바뀌었습니다.
외부저장소 구조의 변화
기존에는 공용공간안에 모든 파일이 저장되었다면, 변경된 후에는 개별공간이 샌드박스 형태로 보호되어있고 공용공간 또한 타입별로 분리되었습니다. 개별 앱 공간은 앱 삭제시 함께 제거되고, 공용공간은 앱이 삭제되어도 기기에 남아있습니다.
외부저장소 접근 방법
1. 개별 앱 접근방법
개별 앱 공간은 따로 권한요청이 필요 없고 Context.getExternalFilesDir()를 통해 자신의 앱 공간에만 접근할 수 있습니다. 기존에는 EXTERNAL_STORAGE권한으로 다른 앱의 개별공간을 접근했지만 변경된 후 부터는 접근할 수 없습니다.
2. 공용공간 접근방법 (Media부분 - 사진 및 동영상, 음악)
안드로이드 버전 10부터는 MediaStore api 사용을 권장하고 있습니다. MediaStore은 사용자가 가지고있는 파일들을 다른 앱에서도 사용될 수 있도록 설계된 api입니다. Media디렉토리 안에서는 자신의 앱에 해당하는 곳은 권한없이 사용할 수 있습니다. 이전 버전에서는 WRITE_EXTERNAL_STORAGE만 있으면 다른 앱의 공용파일에도 접근할 수 있었지만, 보안상의 이슈로 10부터는 이를 막아놓은 것입니다.
아래 코드는 MediaStore API 샘플입니다. 만약, 다른 앱의 미디어스토어를 사용하려면 접근권한이 필요합니다.
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN)
val sortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC"
context.contentResolver.query(
uri, //찾고자 하는 데이터의 Uri
projection, //DB의 column과 같다
null, //Selection, DB의 where과 같다
null, //Selection args, selection에서 물음표에 들어갈 값
sortOder //쿼리 결과데이터의 정렬 기준
)?.use{ cursor ->
while(cursor.moveToNext()){
//projection의 ID column을 사용해서 미디어 아이템의 URI획득
}
}
3. 공용공간 접근방법 (Downloads부분 - 기타 파일들)
미디어 파일 외의 파일들에 접근하는 방법입니다. 이곳은 접근권한 없이 Storage Access Framework와 시스팀 파일 선택기를 통해 사용자가 명시적으로 파일을 선택할 수 있습니다.
Stroage Access Framework는 선택 ui를 화면에 띄워서 앱에서 파일에 접근할 수 있도록 합니다. Intent.ACTION_OPEN_DOCUMENT액션을 사용해 새로운 액티비티를 띄우는 방식입니다.
val READ_REQUEST_CODE : Int = 42
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply{
addCategory(Intent.CATEGORY_OPENABLE) //열 수 있는 파일들만 보고싶을 때 사용
type = "image/*" //타입과 일치하는 파일들만 보여줍니다.
}
startActivityForResult(intent, READ_REQUEST_CODE)
선택ui에서 이미지 하나를 선택하면 해당 이미지의 Uri가 앱으로 전달됩니다.
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
resultData?.data?.also { uri ->
showImage(uri)
}
}
}
저장소 사용방법 요악
파일위치 | 권한 | 접근 | 앱 삭제시 제거 | ||
내부저장소 | 개별 앱 공간 | 필요 없음 | Context.getFilesDir() | Y | |
외부저장소 | 개별 앱 공간 | 필요 없음 | Context.getExternalFilesDir() | Y | |
공용공간 | Media(사진 및 동영상, 음악) | READ_EXTERNAL_STORAGE (다른 앱 접근할때만) | MediaStore(or SAF) | N | |
Downloads(기타) | 필요없음 | Storage Access Framework(system's file picker) | N |
출처
codechacha.com/ko/android-storage-access-framework/
'바삭바삭 IT > 안드로이드' 카테고리의 다른 글
단방향 데이터 흐름의 이해 (0) | 2021.11.21 |
---|---|
[안드로이드] WebViewClient와 WebChromeClient (1) | 2021.11.01 |
[안드로이드] 저장소 사용하기 - 1. Legacy Storage (1) | 2021.02.23 |
[ACC] 데이터 바인딩 기초 (0) | 2021.02.14 |
[Android Jetpack] LiveData 사용방법 (0) | 2021.01.24 |