티스토리 뷰
앱에서 저장할 수 있는 공간은 두가지로 나뉜다.
internal storage와 external storage.
internal storage는 해당 앱만 접근할 수 있는 저장 공간이다. 따라서 컴퓨터에 장치를 연결하고 파일 탐색기로 들어가보아도 이 공간에는 접속 할 수 없다.
external storage는 해당 앱 뿐만아니라 다른 앱 또는 외부에서 접근이 가능한 공간이다. 즉, 파일 탐색기로 확인이 가능하다.
내가 원하는 것은 external storage에 저장하여 파일 탐색기를 통해 파일을 들여다 보거나, 가져올 수 있는 것이다. 조금 더 추가하면 모바일폰이나 태블릿을 컴퓨터에 연결 했을 때, 아래와 같은 폴더 중 한 곳에다가 앱에서 생성한 파일을 저장 하는 것이다.
플러터에서 external storage에 파일을 저장하기 위해서는
먼저 프로젝트폴더의 android/app/src/main/AndroidManifest.xml 에 아래의 내용을 추가해야한다. (원문링크)
그리고 작성하는 flutter 코드에서 external storage 디렉토리를 가져오기 위해서, path_provider 를 사용하면 편하므로 pubspec.yaml 파일에 이 패키지를 추가해 준다.
플랫폼에 따라 패키지로 접근 가능한 디렉토리는 아래와 같다.
패키지를 살펴보니 위에서 언급했던 내가 원하는 디렉토리(Documents, Download, Music, Movies, Pictures)를 직접적으로 반환하는 메소드는 없었다. 아래의 메소드를 보니 파라미터에 type을 설정 할 수 있고 그 type이 documents, download 등이 있어서 내가 생각했던 root directory에 있는 그 폴더들을 반환해 주나 싶었지만, 실해해보니 getExternalStorageDirectory( ) 메소드를 실행하면 얻게 되는 디렉토리에 type에서 표기한 subDirectory를 만들어서 반환해 줄 뿐이었다.
getExternalStorageDirectories(type:StorageDirectory.documents);
즉, 위의 메소드 반환 값은 아래와 같았다.
/storage/emulated/0/Android/data/[패키지명]/files/documents
구글링을 좀 더 하다보니 정확한 답을 찾았다. 그냥 경로를 내가 입력 해주면된다.
내가 파일을 저장하고 싶은 곳은 root 디렉토리에 있는 폴더들이다.
root 디렉토리는 /storage/emulated/0/ 이다
그리고 거기에 있는 Download, Documents, Music 등은 root 디렉토리 path에 붙여 주기만 하면된다.
가량 Documents 에 넣고 싶을 경우,
Directory externalDirectory = Directory('/storage/emulated/0/Documents');
와 같이 Directory를 설정해주고,
excelFile.copySync('${externalDirectory.path}/$fileName.xlsx');
(임시 폴더에 있는 파일의 reference가 excelFile 임)
위와 같이 복사해주면 끝나더라.
쨘~~~~~
하지만.... 문제는 절대 경로를 저렇게 입력하는 것은, 기계에 따라 혹은 사용자 계정에 따라 바뀔 수 있으므로 error가 발생할 여지가 있다. getExternalSTorageDirectory( )로 base가 되는 경로를 받아 온다음에 oot directory를 계산해야 할 듯하다. 그리고 찾아보니 그런 코드가 있어서 좀 수정했다. (원본코드)
//-------------------------------------------------------------------------
// root directory 를 return 하는 메소드
//-------------------------------------------------------------------------
Directory findRoot(FileSystemEntity entity){
final Directory parent = entity.parent;
// android Mobile device 일 경우에만 해당
if(Platform.isAndroid) {
if (parent.path == '/storage/emulated') return Directory(entity.path);
return findRoot(parent);
}
else{
return Directory(entity.path);
}
}
이렇게 문제 없이 내가 원하는 파일을 공용 폴더(external storage) 저장할 수 있는가보다 싶었다.
하지만 아니었다.
manage_external_storage 퍼미션은 함부로 쓰면 안되는 것이었다. 앱스토에 올릴 때 리젝의 사유가 된다고 한다.
실제로 리젝된 사람이 스택오버플로에 글을 올린 것이 아래와 같다.
지금 만들고 있는 앱에서도, core 기능이 '모든 파일에 접근 가능 권한'이 필요한 것은 아니다. excel파일을 생성해서 shared folder에 저장하고 싶은 것뿐. 따라서 나도 androidManifest 에서 manage_external_storage 권한을 삭제하고, 다른 방법으로 파일을 공용 폴더에 저장해야 한다.
우선 안드로이드 10, 11 버전부터 시작된 scoped Storage에 대해서 알아보자.
위 3개의 자료를 보면, 공용 저장소에 접근하기 위해서는 MediaStore나 SAF(Storage Access Framework)를 사용해야 한다.
앞에서 리젝된 사람이 댓글에 방법을 찾아서 올렿놓은 코드가 있다. 이것을 참고하자.
Shared_storage와 mime(또는 mime_type) 패키지를 이용하면 가능할 듯하다.
아래가 동작하는 코드다.
파일을 저장하려고 할때마다 SAF를 통해 저장할 directoryf를 묻는것을 막기위해 처음 한번 설정한 directory를 sharedPreferce에 저장했다(참고자료에서 처럼).
잘동작한다.....이것때문에 2일이나....ㅋㅋ
-------------------- 2022년 8월 29일 추가 ---------------------------
SAF로 접근한 디렉토리는 더이상 dart:io 의 operation을 통하여 handling 할 수 없다.
'Dart & Flutter > 궁금했던 것, 몰랐던 것' 카테고리의 다른 글
int 는 몇 bits 일까? Unit8List 와의 관계는? (0) | 2022.09.07 |
---|---|
audioplayers (0) | 2022.07.25 |
Text 위젯의 fontSize 에 적당한 Container 위젯의 Height (0) | 2022.07.06 |
UI 또는 위젯을 이미지 파일로 저장하기 (0) | 2022.06.24 |
Singletone Pattern (0) | 2022.05.27 |
- Total
- Today
- Yesterday
- UI
- DART
- 인사이트
- 이미지
- 플러터
- TextFormField
- 크롬
- IOS
- hide
- plugin
- 앱
- 앱 프로그래밍
- Syncfusion
- TextField
- Chrome
- 디자인
- position
- 앱개발
- addPostFrameCallback
- 한빛미디어
- 문제 해결
- firebase
- 다트
- Bluetooth
- error
- BLE
- 에러
- Flutter
- UX
- SizedBox
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |