Flutter에서 이미지를 다룰 때 iOS의 경로 문제 (Stored image is missing)
이미지를 다루다가...
전에 마와셀 1.0 버전대 개발을 하다 겪은 일이다.
마와셀에는 와인 사진 및 셀러, 시음 노트에 이미지를 첨부하는 기능이 있다.
안드로이드에서는 잘 되어서 문제없이 넘어갔다가,
iOS도 실제 디바이스에서 테스트를 진행하면서 문제가 없음을 확인했었다.
하지만 iPad용 스크린샷이 필요해서 시뮬레이터에서 구동하다가 문제가 생겼다.
이미지를 못 가져옴
시뮬레이터를 끈 다음 빌드 후 다시 접근하는데 이미지가 없어서 앱 크래시가 발생했다.
물론 2.0에서는 이미지가 없을 때 기본 이미지 표시로 바꾸긴 했다.
마와셀의 이미지는 파일명만 가져와서 저장을 하게 된다.
경로의 경우 조립해서 사용하는 방식을 사용했다.
로직에는 문제가 없었고,
뭔가 이상함을 느낀 나는 몇 가지 로그를 남기며 테스트를 했다.
그 결과 시뮬레이터의 이미지 경로가 계속 변경함을 찾을 수 있었다.
- 첫 번째 테스트 빌드 하였을 때 경로
/Users/testMan/Library/Developer/CoreSimulator/Devices/73169529-CF2Z-20FT-U1A1-O23DBE772DCA/data/Containers/Data/Application/2DQ07F26-AB29-968D-00FA-DOQE96A35B27/Documents/tmp_img/2233-FF00-img001.png
- 두 번째 테스트 빌드 하였을 때 경로
/Users/testMan/Library/Developer/CoreSimulator/Devices/73169529-CF2Z-20FT-U1A1-O23DBE772DCA/data/Containers/Data/Application/576G7D01-Z3K0-D2K1-6FFQ-J6YF3ME8A02B/Documents/tmp_img/O1DV-W991-img001.png
iOS는 별도 구현이 필요
위 로그를 보면 알겠지만, 어플리케이션 ID가 계속 변함을 알 수 있다.
저 앱 ID의 경우 path_provider의 getApplicationDocumentsDirectory를 통해서 가져오게 된다.
class DirectoryManager {
late final Directory appDir;
late final Directory tmpDir;
DirectoryManager();
Future<void> init() async {
appDir = await getApplicationDocumentsDirectory();
tmpDir = Directory('${appDir.path}/tmpRes');
await _createDirectories();
}
}
난 디렉토리랑 파일을 다루는 별도의 클래스를 두고,
get_it을 통해서 Injection 해서 사용한다.
해당 문제를 수정하려면 결국 경로를 플랫폼마다 조정해서 써야 한다.
아래의 코드를 참고하자.
try {
String imgPath;
///Android
if (Platform.isAndroid) {
imgPath = _getAttachImageFullPath(attachImageEnum);
}
///iOS
else if (Platform.isIOS) {
imgPath =
"${dirManager.appDir.path}/${attachImageEnum.getAttachPath()}";
}
// 웹이나 다른 플랫폼의 경우 임시 디렉토리 사용
else {
imgPath = (await getTemporaryDirectory()).path;
}
} catch (e) {
logger.d('[cloneFile] Error: $e');
}
/// 다른 함수
String _getAttachImageCategoryFullPath(AttachImageEnum imgEnum) {
final directoryManager = getIt.get<DirectoryManager>();
if (imgEnum == AttachImageEnum.wine) {
return directoryManager.wine.path;
}
return directoryManager.tmpDir.path;
}
내가 사용하는 코드를 잘라서 주요 로직은 잘라낸 예제 코드다.
핵심은 iOS의 경우 getApplicationDocumentsDirectory이거를 직접 가져와서
뒤에 사용자 경로를 붙이면 되고, 그 외 플랫폼은 그냥 고정된 값을 사용해도 된다.
정리
이걸 처음엔 GPT한테 물어봤는데 내가 프롬프트를 이상하게 줘서 스택에서 찾게 되었다.
Flutter-iOS when apps update / recompile stored image is missing
Flutter는 이런 플랫폼 간 몇 가지 설정을 해줘야 하는 부분이 있다.
문제가 생길 땐 Claude나 GPT에게 물어보자.