[Flutter] 이미지와 파일을 위한 Storage 다루기

2023. 3. 25. 02:32Developers 공간 [Shorts]/Frontend

728x90
반응형
<분류>
A. 수단
- OS/Platform/Tool : Linux, Kubernetes(k8s), Docker, AWS
- Package Manager : node.js, yarn, brew, 
- Compiler/Transpillar : React, Nvcc, gcc/g++, Babel, Flutter

- Module Bundler  : React, Webpack, Parcel

B. 언어
- C/C++, python, Javacsript, Typescript, Go-Lang, CUDA, Dart, HTML/CSS

C. 라이브러리 및 프레임워크 및 SDK
- OpenCV, OpenCL, FastAPI, PyTorch, Tensorflow, Nsight

 


1. What? (현상)

 

작업을 하다 보면 storage에 접근해야 하는 방법이 다양합니다.

 


2. Why? (원인)

  • X

3. How? (해결책)

  • path_provider : Flutter 기본 패키지
    • getApplicationDocumentsDirectory() : 앱만의 저장공간이며, 앱의 크기와 관련있습니다.
    • getApplicationSupportDirectory() 
    • getExternalCacheDirectories()
    • getExternalStorageDirectories({StorageDirectory type })
    • getExternalStorageDirectory()
    • getLibraryDirectory()
    • getTemporaryDirectory() : 캐시와 같이 임시로 데이터 저장하는 공간입니다.
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

final path = join(
      (await getTemporaryDirectory()).path,
      '${DateTime.now()}.png',
    );
final File file = File(path);

file.writeAsBytes(...);
file.writeAsString(...);
// Get the directory and file List
Directory directory = await getApplicationDocumentsDirectory();
List<FileSystemEntity> fileList = await directory.list().toList();

// Get file names
List<File> allFileList = [];
allFileList.clear();
List<Map<int, dynamic>> fileNames = [];
fileList.forEach((file) {
    if (file.path.contains('.jpg') || file.path.contains('.mp4')) {
      allFileList.add(File(file.path));

      String name = file.path.split('/').last.split('.').first;
      fileNames.add({0: int.parse(name), 1: file.path.split('/').last});
    }
});

// Retrieving the recent file
if (fileNames.isNotEmpty) {
    final recentFile = fileNames.reduce((curr, next) => curr[0] > next[0] ? curr : next);
    String recentFileName = recentFile[1];
}
  • flutter_secure_storage : JWT와 같은 중요한 정보 저장시 사용
    ** JWT(Json Web Token) : Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token으로, Oauth를 구현할 때 사용합니다.
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class BasicStorageService {
  final _storage = new FlutterSecureStorage();
  
  Future<String> readFromStorage({String key}) async {
  	// Map<String, String> allValues = await _stroage.readAll();
    String jwt = await _storage.read(key: key);
    return jwt ?? "";
  }

  Future<void> deleteFromStorage(String key) async {
  	//await _storage.deleteAll();
    await _storage.delete(key: key);
  }

  Future<void> writeToStorage(String key, String value) async {
    await _storage.write(key: key, value: value);
  }
}
  • image_gallery_saver : 이미지 갤러리에 저장하기
    • ios/Runner/Info.plist : 읽기 권한 key를 추가해줍니다.
      <key>NSPhotoLibraryAddUsageDescription</key>
      <string> ${PRODUCT_NAME}가 권한이 필요합니다.</string>
    • android/app/src/main/AndroidManifest.xml : <application> 아래 <activity> 위 추가
      android:requestLegacyExternalStorage="true"
import 'package:image_gallery_saver/image_gallery_saver.dart';

await ImageGallerySaver.saveImage(
    Uint8ListObject,
    quality: 60,
    name: "hello"
);
  • gallery saver : 이미지와 비디오를 저장하기
    • ios/Runner/Info.plist : 읽기/쓰기 권한 key를 추가해줍니다.
      <key>NSPhotoLibraryUsageDescription</key>
      <string> ${PRODUCT_NAME}가 권한이 필요합니다.</string>
    • android/app/src/main/AndroidManifest.xml : <manifest> 아래 <application>위 추가
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
import 'package:gallery_saver/gallery_saver.dart';

GallerySaver.saveImage(recordedImage.path)
    .then((bool? result){
    	print('result : $result');
    })
    .catchError((err) {
    	print('error : $err');
    });
  • photo manager : 이미지를 여러개 읽는 것에 사용
    • ios/Runner/Info.plist : 읽기/쓰기 권한 key를 추가해줍니다.
      <key>NSPhotoLibraryUsageDescription</key>
      <string> ${PRODUCT_NAME}가 권한이 필요합니다.</string>
    • android/app/src/main/AndroidManifest.xml : <application> 아래 <activity> 위 추가
      android:requestLegacyExternalStorage="true"
    • Photo manager를 활용하는 경우 권한에 대한 셋팅을 permission_handler를 사용하지 않고 다룰 수 있는데, 아래와 같이 경우에 따라 구현할 수 있으며, iOS 14이상인 경우 "limited"라는 공유를 원하는 사진만을 선택하는 옵션이 있는데 이 경우는 presentLimited()라는 함수를 활용해 공유를 원하는 사진을 선택하게 해줄 수도 있습니다.
    • Album의 type은 AssetPathEntity이며, photo의 type은 AssetEntity입니다. getAssetListRange() 혹은 getAssetListPaged()를 활용해 구현할 수 있는데, 후자는 pagenation을 구현할 때 활용합니다.
      ** AssetEntity : Android의 MediaStore field, iOS/macOS의 PHAsset object를 의미
import 'package:photo_manager/photo_manager.dart';

PermissionState permitted = await PhotoManager.requestPermissionExtend();

switch(permitted){
      case PermissionState.notDetermined:
        break;
      case PermissionState.restricted:
        return;
        break;
      case PermissionState.denied:
        return;
        break;
      case PermissionState.authorized:
        // TODO
        break;
      case PermissionState.limited: //For iOS 14 and above
        // TODO
        // await PhotoManager.presentLimited(); //this is for letting them select photos
        break;
      default:
        break;
    }
import 'package:photo_manager/photo_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class PhotoAlbum {
  List<AssetEntity> photos = [];
  int CurrentPages = 0;
  Uint8List? thumbnail;

  Future<void> _getAssets() async{
    List<AssetPathEntity> albums = await PhotoManager.getAssetPathList(onlyAll: true);
    AssetPathEntity recentAlbum = albums.first;
    
    // photos = await recentAlbum.getAssetListRange(start: 0, end: 50);
    photos = await recentAlbum.getAssetListPaged(page: 0, size: 50);

    if(photos.isNotEmpty){
      thumbnail = await photos[0].thumbnailData;
    }
  }

  PhotoAlbum() {
    _getAssets();
  }

}
더보기

-----------------------------------------------------------------------------------------------------

<참고 : MacOS에서 확인했을 때 iOS상의 저장된 위치 프린트>

  • 사진 : /private/var/mobile/Containers/Data/Application/컴파일ID/tmp/flutter-images/NAME_exif.jpg
  • 비디오 : /private/var/mobile/Containers/Data/Application/컴파일ID/tmp/.video/NAME.MOV

-----------------------------------------------------------------------------------------------------

 

 

 

** 이외에 사진 여러장을 한번에 선택 가능하도록 할 수 있는 wechat_camera_picker 플러그인도 있습니다.


https://blog.logrocket.com/flutter-camera-plugin-deep-dive-with-examples/

https://iosroid.tistory.com/45

https://pub.dev/packages/flutter_secure_storage

https://pub.dev/packages/wechat_camera_picker

https://pub.dev/packages/gallery_saver

https://pub.dev/packages/image_gallery_saver

https://annhee.tistory.com/58

https://aloe-study.tistory.com/m/81

https://www.abdou.dev/blog/build-a-gallery-app-using-flutter

728x90
반응형