코딩하는 일용직 노동자

Android 10(Q) Scope Storage 에 관하여 본문

안드로이드

Android 10(Q) Scope Storage 에 관하여

bacass 2020. 5. 5. 16:40

Android 10(Q) 부터는 기존의 저장공간과는 다른 개념으로 바뀌었습니다.
10 이전의 안드로이드는 기본적으로 내부저장공간과 외부저장공간으로 나뉩니다.

# Android 10(Q) 이전의 Storage
내부저장공간은 샌드박스 형식으로 보호되는 공간을 할당받습니다.
ex) com.kakao.talk, com.kakao.story, com.app.a 
그리고 각 앱은 자신의 저장공간만 접근하고 사용할 수 있습니다.
10 에서도 내부저장공간은 마찬가지로 사용됩니다.

반면 외부저장공간은 하나의 큰 공통저장공간으로 운영되었습니다.
READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE 권한만 있으면 
어떤앱이 작성한 파일이든, 어느 경로에 있든, 어떤 파일이든 모두 접근/수정할 수 있었습니다.

 

Android Q 이전의 저장공간

 

EXTERNAL_STORAGE 권한은 안드로이드 앱에서 가장 많이 사용되는 권한입니다. 
이 권한의 남용으로 그동안 많은 문제들이 발생했습니다.
파일들이 어떤 앱에서 사용되는지 명확하지 않아 관리가 어렵고,
앱을 제거한 후에도 많은 파일 sdcard 에 남아 저장공간을 차지했습니다. 
또한 다른 앱에서 잠재적으로 민감한 파일을 읽을 수도 있습니다.

# Android 10(Q) 를 적용하기 싫다면 
만약 자신의 앱에 Scoped Storage를 바로 적용할 준비가 안된 개발자들을 위해, 구글은 이전 방식을 사용할 수 있도록 유예기간을 두었습니다.
앱이 Android 10 기기에서 Scoped storage 정책을 적용받지 않으려면 다음 중 1가지 방법을 적용해야 합니다.

방법1. Target SDK를 안드로이드 API 28 이하로 설정
방법2. Target SDK를 안드로이드 API 29 이상으로 설정하는 경우, 매니페스트파일 requestLegacyExternalStorage 속성을 true로 설정

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting Android Q. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

 

# Android 10(Q) 부터의 Storage
이제 앱에서는 더이상 sdcard/ 이하의 영역에 직접 접근할 수 없습니다. 
외부저장공간의 경로를 얻기위해 많이 사용하던 Environment.getExternalStorageDirectory()는 deprecated 되었습니다.

 

아이고 의사양반~ getExternalStorageDirectory 가 고자라니 ㅠ.ㅠ

 

Android 10에서는 기존 외부저장공간의 public 한 개념이 사라집니다.
공용공간으로 다운로드, 사진 및 영상, 음악 공간이 있고, 샌드박스 형식의 개별앱공간으로 나뉘어서 관리됩니다.

 

Android 10(Q) 의 저장공간

getExternalFilesDir() 이나 getExternalCacheDir() 을 사용하면
/Android/data/패키지명/files
/Android/data/패키지명/cache
폴더가 자동으로 생성되며 READ_EXTERNAL_STORAGE 퍼미션을 별도로 획득하지 않아도 파일의 접근이 가능합니다.

외부저장공간의 개별앱공간은 내부저장공간과 비슷한 형식으로 동작합니다.
이제 추가권한없이 개별앱공간을 읽고 쓸 수 있습니다.
개별앱공간은 샌드박스 형식으로 관리되며 다른 앱의 공간으로는 접근할 수 없습니다.

외부저장공간의 공용공간은 다운로드, 사진및영상, 음악 공간이 있고 각 공용공간은 MediaStore를 통해 읽고 쓸 수 있습니다.
다운로드 공간을 제외한 나머지 공간은 해당 타입에 맞는 파일만 저장할 수 있습니다.
추가권한없이 각 공용공간에 파일을 생성할 수 있고, 자신이 생성한 파일을 읽을 수 있습니다.
앱이 삭제되면 해당앱이 가지고 있던 모든 파일이 삭제됩니다.
만약 앱 삭제 후에도 파일을 보존할 필요가 있다면 MediaStore를 통해 파일을 생성한 후 메타데이터를 추가해야 합니다.

 

https://developer.android.com/training/data-storage/files/external-scoped?hl=ko

 


자신이 생성한 파일에 대해서는 읽기/쓰기 권한이 필요없지만, 공용공간에 저장된 다른앱이 생성한 파일에 대해서는 권한이 필요합니다.
이를 위해 Android 10에서는 READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO 권한이 새롭게 추가되었습니다.

각 앱은 다른앱이 다운로드 공간에 생성한 파일을 직접 접근할 수 없습니다.
앱이 Android 10의 다른 앱에서 만든 비 미디어 파일에 액세스하는 유일한 방법은 Storage Access Framework 에서 제공하는 파일 선택기를 사용하는 것입니다.
(https://developer.android.com/guide/topics/providers/document-provider#kotlin)

Storage Access Framework 를 이용한 파일 검색 방법은 아래처럼 사용하면 됩니다.

private val REQUEST_CODE_FOR_SINGLE_FILE: Int = 3020
...
fun findImageFiles() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        // Filter to only show results that can be "opened", such as a
        // file (as opposed to a list of contacts or timezones)
        addCategory(Intent.CATEGORY_OPENABLE)

        // Filter to show only images, using the image MIME data type.
        // If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
        // To search for all documents available via installed storage providers,
        // it would be "*/*".
        type = "image/*"
    }
    startActivityForResult(intent, REQUEST_CODE_FOR_SINGLE_FILE)
}

 

이미지만 검색된다.

 

private val EDIT_REQUEST_CODE: Int = 3030
...
fun findPdfFiles() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        // Filter to only show results that can be "opened", such as a
        // file (as opposed to a list of contacts or timezones)
        addCategory(Intent.CATEGORY_OPENABLE)

        // Filter to show only images, using the image MIME data type.
        // If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
        // To search for all documents available via installed storage providers,
        // it would be "*/*".
        // type = "text/plain"
        type = "application/pdf"
    }
    startActivityForResult(intent, EDIT_REQUEST_CODE)
}

 

pdf 만 검색된다.

# 정리하며...
그동안 외부저장장치에 파일을 읽고 쓰는것에는 큰 제약이 없었습니다. 
사용자에게 READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE 권한만 획득하면 됐습니다.
그러다보니 외부저장장치에 여러 앱의 폴더가 무분별하게 생성되고 관리되었습니다.

앞으로는 딱 정해진 방식대로만 쓰라는 것이 이번 변경점의 특징이라고 할 수 있습니다.

자신이 개발하는 앱에서만 사용될 파일들은 getExternalFilesDir() 이나 getExternalCacheDir() 을 사용해 private 한 공간에서만 관리되도록 했습니다.
이 공간에 파일을 저장/수정/삭제 할때는 READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE 권한이 필요없습니다.

그리고 다운로드 폴더를 제외한 나머지 공간에서는 해당 타입에 맞는 파일(Image, Video, Audio)만 저장하도록 하고 MediaStore를 통해 저장/수정/삭제 되도록 했습니다.
이런 공통공간에 다른앱이 저장시켜 놓은 파일에 접근할때는 READ_EXTERNAL_STORAGE 권한을 요청하도록 합니다.

외부저장장치에 저장되어있는 파일들을 선택할때는 Storage Access Framework에서 제공하는 파일 선택기를 이용하도록 합니다.


안드로이드의 버전이 높아질수록 보안에 관한 내용이 꾸준히 추가되네요. -_-;;

 

'안드로이드' 카테고리의 다른 글

유튜브를 웹뷰로 구성하기 (1)  (0) 2020.05.11
웹뷰 키보드 이슈 해결사례  (0) 2020.05.07
코틀린 ScopeFunction 종류와 역할  (0) 2020.05.03
File Exploler 라이브러리  (0) 2020.05.03
Wifi ADB 디버깅 방법  (0) 2020.05.03