작업하다가 위와 같은 에러가 나왔다.
당시에 나는 정확한 원인을 알수가 없었다.
그리고 검색을 해본결과
이 에러가 뜨는 이유는 다양하다.
파일을 못불러오거나, 파일에 불러올 자료가 없거나, 아니면 경로를 잘못 선언해주어서 이거나,
구글링을 해도 알수 없었고 그 이유는 위 사진과 같은 에러가 나오는 이유의 원인이 다방면으로 많기 때문이다.
또한 각자 다른 이유가 있었다.
위와같이 에러가 뜨거나 할경우는 디버깅을 해보는게 가장 빠른 길이라고 할수 있다.
사실 필자도 이 에러에 대해서 구글링으로만 해결하려고 노력한 결과 8일이라는시간이 걸렸고,
게다가 에러를 해결하지 못했다.
결국엔 디버깅을 혼자 해가면서 찾으니까 하루만에 이유를 알수 있었다.
내가 너무 디버깅을 안일하게 생각했던것같다.
디버깅에 대한 정확한 개념도 파악하지 못했었다 그런데 이번에 혼자 디버깅을 해보면서
왜 디버깅을 하면 좋은지에 대해서 알게됬던거 같다.
서론은 여기까지만 하고 본론으로 들어가면,
우선 나는 저 위에 에러가 뜨는 부분을 잡으려고 파일을 가져오는 부분에 로그도 찍고 브레이크 포인트를 찍어서
변수나 메서드안에 어떤값이 들어가는지와 어디에서 파일을 못 넘겨주는지 또는 못 찾는지에 대해서 알아봤다.
위와 같은 식으로 Log를 찍어서 올바른,유도한 파일 경로에서 파일을 가져오는지에 대해서 로그를 찍었다.
그 결과 catch문으로 예외처리가 발생했고, 에러가뜨는 곳인 클립보드에 "파일 복사 중 예외 발생" 이라고 뜨면서
파일에 접근을 할수가 없었다고 나온다. 그래서 좀더 정확하게 어디서 에러가 뜨는지를 알기위해서 디버깅을 하기로했다.
방법은
위와같이 옆에 statment 번호 옆에 마우스로 클릭해서 빨간점을 생성시킨다. 그리고,
이 버튼을 클릭하면 맨 위에있는 빨간점에서 부터 디버깅을 시작한다.
( 디버깅이란 : 컴퓨터 분야에서 디버깅이란 컴퓨터 프로그램이나 하드웨어 장치에서 잘못된 부분, 즉 버그를 찾아서 수정하거나 또는 에러를 피해나가는 처리과정이다. )
클릭을하면 디버거를 위해 기다려달라는 문구가 뜨게되고, 짧으면 1초 길면 5초정도를 기다리면 화면이 넘어가게된다.
시작하게되면 코드창에는 이런식으로 파란색 줄이 나오는데 이 파란줄이 가르키는건 이제 디버깅을 할곳이라는 말이다.
화면에서 보이는것 처럼 오른쪽에 주석과 같은색인 회색으로 pathDir : ~ 어디 경로에 접근하는지를 알수 있다.
그리고 여기서 F9를 누르게 되면
다음으로 넘어가게 되면서 또 그안에 어떤 경로로 접근 중 인지옆에 보여주면서 디버그 클립보드에는 이런식으로 뜬다.
위와같이 나오게 되고, 여기서 pathDir을 눌러서 경로를 확인 할 수 있다.
그래서 그 경로를 확인하기 위해서
위와 같은 식으로 검색해서 디바이스의 폴더파일을 확인해보았다.
위와같이 퍼미션이 거부된것을 알수 있었다.
그래서 퍼미션 관련해서 공부를 더 해본결과
API29. 즉 안드로이드 Q 부터 퍼미션 관련 보안이 더 강화된것을 알수 있었다. 그래서 퍼미션을 허용하거나 뚫을? 사용하려면
메니페스트에 따로 입력을 하거나 내부저장소에 저장하고 그 저장된 파일을 외부저장소에 옮기는 등으로 방법을 구현해야 한다.
< 그럼 안드로이드 Q의 새로운 저장소 정책인, scoped Storage에 대해서 알아보자. >
안드로이드 Q에서 외부저장소를 다루는 scoped Storage를 사용하며, Q이전의 기존 정책은 앱이 디바이스의 어떤 파일에 접근 할 때 사용자에게 저장소 권한만 얻으면 되었습니다. 그럼 앱은 모든 폴더를 탐색할 수 있었고 파일의 path를 얻어 데이터를 읽고 쓸 수 있었습니다.
하지만, Q의 Scoped Sotage는 기본적으로 앱이 디바이스의 모든 파일을 탐색화지 못한다는 전제가 깔려있습니다. 공용 미디어 파일들은 READ_EXTERNAL_STORAGE 권한이 있어야 접근 가능하고, 그 외의 파일들은 사용자에게 접근 권한을 개별로 받아야 합니다. 앱이 자유롭게 접근 할 수 있는것은 자신의 개인 앱 데이터 뿐입니다.
구글의 이런 정책은 요즘 트렌드인 보안을 향상시키기 위한 목적입니다. 사용자는 앱이 알 필요가 없는 파일들에 대한 접근 권한을 주지 않아도 되어, 개인 정보를 보호할 수 있습니다.
Scoped Storage에 대해서 알아보기 전에, 지금까지 사용해왔던 외부 저장소 정책에 대해서 먼저 알아보고, Scoped Storage를 알아보겠습니다.
내부 저장소 vs 외부 저장소
안드로이드의 저장소는 크게 내부 저장소(Internal Storage)와 외부 저장소(External Storage)로 나뉩니다. 내부 저장소는 /data/ 아래 경로의 파일들을 의미하고, 외부저장소는 /storage/ 아래 경로의 파일들을 의미합니다.
모든 앱들은 자신만의 데이터 폴더를 갖고 있습니다. 자신의 데이터 폴더는 자신만 접근할 수 있습니다. 즉, 어떤 앱이 다른 앱의 데이터 폴더에 접근할 수 없다는 것을 의미합니다. 데이터 폴더는 내부 저장소와 외부 저장소에 모두 존재하고 경로는 다음과 같습니다.
- 내부 저장소의 데이터 폴더: /data/data/[앱의 Package Name]/
- 외부 저장소의 데이터 폴더: /storage/emulated/0/Android/data/[앱의 package name]/
Scoped Storage는 외부 저장소에 대한 정책입니다. 그렇기 때문에 외부 저장소에 초점을 맞추어 확인하시면 좋을 것 같습니다.
Q 이전의 외부 저장소 정책
안드로이드 P 이하의 버전에서, 외부 저장소에는 다음과 같은 폴더들이 있습니다.
- 앱 데이터 폴더 : /storage/Android/data/[앱의 package name]/
- 공용 폴더(DCIM, Pictures 등): /storage/[폴더 이름]
앱 데이터 폴더는 앱 자신만 접근할 수 있습니다. 그리고 앱이 삭제될 때 데이터도 함께 삭제됩니다.
반면에 공용 폴더는 모든 앱이 접근할 수 있습니다. Pictures, DCIM 등의 폴더가 자동으로 생성되어있지만 다른 목적으로 사용할 폴더를 직접 만들 수도 있습니다. 이 폴더에 파일을 읽거나 쓰려면 READ_EXTERNAL_STORAGE 또는 WRITE_EXTERNAL_STORAGE 권한을 얻어야 합니다. 그리고 파일을 생성한 앱을 삭제해도 데이터는 삭제되지 않습니다.
그리고 시스템은 MediaStore를 통해 디바이스에 존재하는 미디어 데이터를 공유합니다. MediaStore는 시스템에서 미디어 데이터에 대한 정보를 제공하는 Provider입니다.
< 저장소 내부의 폴더 경로에 대해서 궁금하시다면 Android의 데이터 폴더 경로 및 내부/외부 저장소 설명을 참고해주세요. >
Q의 Scoped Storage 정책
구글은 Scoped Storage를 다음 3개로 나누어서 설명하고 있습니다.
- 앱 데이터 폴더(App specific directory)
- 미디어 파일들(MediaStore)
- 공용 파일들(Storage Access Framework)
앱 데이터 폴더(App specific directory, Sandbox)
앱 데이터 폴더는 이전과 동일합니다. 읽고 쓰는데 권한이 필요없고, 다른 앱들은 자신의 데이터 폴더에 접근할 수 없습니다. 앱이 삭제되면 데이터 폴더도 함께 삭제됩니다.
미디어 파일들(MediaStore)
공용 폴더 안에 있는 미디어 파일들은 MediaStore를 통해 읽을 수 있습니다. 예를 들어, 사진 또는 동영상 파일을 찾고 싶으면 공용 폴더 아래의 모든 파일들을 탐색해서 찾는 것이 아니라 MediaStore에 쿼리를 하여 Uri 객체를 얻어 사용해야 합니다.
다음과 같은 콜렉션들에 저장된 파일들은 MediaStore를 통해 읽을 수 있습니다.
- MediaStore.Images: 사진 파일
- MediaStore.Video: 비디오 파일
- MediaStore.Audio: 음악 파일
또한, MediaStore를 통해 파일을 읽으려면 READ_EXTERNAL_STORAGE 권한이 필요합니다. 하지만 파일을 생성하는 것은 권한이 없어도 됩니다.
이미지 파일의 위치 정보를 읽으려면 ACCESS_MEDIA_LOCATION 권한이 필요합니다. 이 권한은 Android 10(SDK 29)부터 추가된 신규 퍼미션이기 때문에, SDK 28 이하로 빌드된 앱의 경우 READ_EXTERNAL_STORAGE 권한만 요청하면 ACCESS_MEDIA_LOCATION도 함께 부여됩니다.
공용 파일들(Downloads 폴더, Storage Access Framework)
공용 미디어 파일들을 제외하고, Downloads 폴더 등을 접근할 때는 SAF(Storage Access Framework)를 이용해야 합니다. SAF는 Android Lollipop 부터 소개되었지만, 시스템 구조가 직접 접근하는 방식보다 간단하지 않고 UX가 복잡해 많은 앱들이 사용하지 않았습니다. SAF는 폴더들을 관리하는 DocumentsProvider와, 사용자가 앱에 파일 접근을 허용할 수 있도록 UI를 제공하는 DocumentsUI로 이루어져 있습니다.
Q에서 앱들은 공용 파일들에 접근할 때 DocumentsUI의 액티비티를 띄워 사용자에게 어떤 파일에 대한 접근 권한을 부여받아야 합니다. 그 이후에, 그 파일을 읽거나 쓰도록 해야 합니다. 사용자가 파일 또는 폴더를 선택하기 때문에 사용자는 더 좁은 범위로 권한을 부여할 수 있게 되었습니다.
< Android developers: scoped storage에 SAF를 이용하는 방식에 대한 소개가 있고, 케이스별로 어떻게 처리가 되어야 하는지 안내하고 있습니다. SAF에 대한 설명은 Android developers: document provider를 참고해주세요.>
앱 업데이트
앱 개발자들은 바로 자신의 앱에 Scoped Storage를 적용하지 않아도 됩니다. Scoped Storage를 바로 적용할 준비가 안된 개발자들을 위해, 구글은 Q에서 이전 방식을 사용할 수 있도록 유예기간을 두었습니다.
앱이 Android 10 디바이스에서 Scoped storage 정책을 적용받지 않으려면 다음 중에 1가지 방법을 따라야 합니다.
- 안드로이드 API 28 이하를 Target SDK로 설정
- 안드로이드 API 29 이상을 Target SDK로 설정하는 경우, requestLegacyExternalStorage를 true로 설정합니다.
다음과 같이 앱의 AndroidManifest.xml에 requestLegacyExternalStorage 속성을 true로 설정하면 Scoped Storage 정책이 적용되지 않습니다.
정리
장황하게 설명한 Scoped storage를 간단히 설명하면, 앱은 직접 파일에 접근할 수 없고 MediaStore와 SAF를 통해 파일에 대한 Uri을 얻어 접근해야 합니다. 이런 정책은 사용자가 앱이 필요로하는 파일에만 접근 권한을 부여할 수 있게 만들고, 보안을 향상시키려는 목적입니다. 설명을 읽는 것보다 구글에서 제공하는 샘플들을 실행해보고 코드를 분석해보는 것이 더 좋을 것 같습니다.
참고
- Android developers: scoped storage
- Android developers: document provider
- Android SAF 예제
- Android developers: Storage updates in Android 11
Recommended Posts:
- Android11 - Storage(저장소) 변경사항 정리
- Android11 - Package visibility 변경사항 소개
- Android - File-Based Encryption과 Direct Boot
- 안드로이드 Q - Thermal API로 발열 상태 모니터링
- 안드로이드 Q - Background Activity 실행 제한
- Android App Bundle로 Apk 크기를 더 작게 만들기
- 안드로이드 Q - Background Location 권한 제한
- 안드로이드 Q - Settings Pannel에 대해서 알아보기
- 안드로이드 Q - Mainline, APEX에 대해서 알아보기
- 안드로이드 - JobScheduler로 백그라운드 작업 실행하는 방법
- Android P - Non-SDK 인터페이스는 제한
- 안드로이드 Adaptive Icon 적용하는 방법
- 안드로이드 - Autosizing TextView 구현 방법
'workSpace > ANDROID' 카테고리의 다른 글
Git 리모트(remote) 브랜치 생성 및 삭제하기 (0) | 2022.07.26 |
---|---|
Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager 오류 해결법 (0) | 2021.08.26 |