728x90
앱에서 사용자로부터 이미지 접근 권한을 요청하고 이를 처리하는 방법은 iOS와 Android에서 다르게 작동합니다. 이 글에서는 Flutter를 사용하여 iOS와 Android에서 이미지 접근 권한을 설정하고 구현하는 방법을 공유합니다.
1. iOS 권한 설정
iOS에서는 PermissionHandler 패키지를 사용하여 이미지 접근 권한을 요청할 수 있습니다. 권한 요청을 위해 다음 단계를 수행합니다:
1.1 Info.plist 수정
Info.plist에 다음 권한 요청 메시지를 추가합니다:
xml
코드 복사
<key>NSPhotoLibraryUsageDescription</key> <string>사진 접근 권한이 필요합니다.</string> <key>NSCameraUsageDescription</key> <string>카메라 사용 권한이 필요합니다.</string>
1.2 Podfile 수정
Podfile에서 필요한 권한을 활성화합니다:
post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', 'PERMISSION_PHOTOS=1', # 사진 접근 권한 플래그 'PERMISSION_CAMERA=1', # 카메라 권한 플래그 ] end end end
이후 pod install 명령어를 실행하여 변경사항을 적용합니다.
2. Android 권한 설정
Android에서는 AndroidManifest.xml 파일에 필요한 권한을 선언합니다.
2.1 AndroidManifest.xml 수정
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" />
2.2 requestLegacyExternalStorage 추가 (Android 10 이하 지원)
application 태그 내에 다음 속성을 추가합니다:
<application android:requestLegacyExternalStorage="true" ... > </application>
3. Flutter에서 권한 요청 구현
3.1 PermissionHandler 패키지 설치
pubspec.yaml에 permission_handler를 추가합니다:
dependencies: permission_handler: Version
3.2 PermissionService 클래스 구현
권한 요청을 처리하기 위해 PermissionService 클래스를 작성합니다.
import 'dart:io';
import 'package:memory_on/common/constants/app_logger.dart';
import 'package:permission_handler/permission_handler.dart';
class PermissionService {
/// 권한 요청 (카메라, 사진, 파일 저장소)
static Future<Map<String, bool>> requestPermissions() async {
final Map<String, bool> permissionsStatus = {
"카메라": false,
"사진": false,
"저장소": false,
};
if (Platform.isIOS) {
// iOS 권한 요청
permissionsStatus["카메라"] = await _requestPermission(Permission.camera);
permissionsStatus["사진"] = await _requestPermission(Permission.photos);
} else if (Platform.isAndroid) {
// Android 권한 요청
permissionsStatus["카메라"] = await _requestPermission(Permission.camera);
// Android 11(API 30) 이상: READ_MEDIA_IMAGES 요청
if (await _isAndroid11OrAbove()) {
permissionsStatus["사진"] = await _requestPermission(Permission.photos);
permissionsStatus["저장소"] =
await _requestPermission(Permission.manageExternalStorage);
} else {
// Android 10 이하: READ_EXTERNAL_STORAGE 요청
permissionsStatus["사진"] =
await _requestPermission(Permission.storage);
permissionsStatus["저장소"] =
await _requestPermission(Permission.storage);
}
}
return permissionsStatus;
}
/// Android 11(API 30) 이상 확인
static Future<bool> _isAndroid11OrAbove() async {
if (!Platform.isAndroid) return false;
final int sdkVersion =
await Permission.storage.status.then((_) => 30); // 강제값 대체
return sdkVersion >= 30;
}
/// 개별 권한 요청
static Future<bool> _requestPermission(Permission permission) async {
final status = await permission.status;
if (status.isGranted) {
// 이미 권한이 허용된 경우
logger.i("${permission.toString()} 권한이 허용되었습니다.");
return true;
} else if (status.isPermanentlyDenied) {
// 영구적으로 거부된 경우
logger.e("${permission.toString()} 권한이 영구적으로 거부되었습니다.");
return false;
} else {
// 권한 요청
final requestStatus = await permission.request();
logger.i("${permission.toString()} 권한 요청 결과: ${requestStatus}");
return requestStatus.isGranted;
}
}
}
4. 권한 요청 적용
권한 요청을 사용하는 코드는 다음과 같습니다
Future<void> _pickImages() async {
// PermissionService를 통해 필요한 권한 요청
final permissionsStatus = await PermissionService.requestPermissions();
// 권한 상태 확인
if (permissionsStatus["사진"] == true) {
// 갤러리 접근 권한이 허용된 경우
final ImagePicker picker = ImagePicker();
final List<XFile>? images = await picker.pickMultiImage();
if (images != null && images.isNotEmpty) {
setState(() {
// 최대 5장까지만 추가
final int availableSlots = 5 - _selectedImages.length;
if (images.length > availableSlots) {
_selectedImages.addAll(
images.take(availableSlots).map((image) => image.path),
);
} else {
_selectedImages.addAll(images.map((image) => image.path));
}
});
}
} else {
// 권한이 거부된 경우 처리
if (permissionsStatus["사진"] == false) {
showLoginFailedDialog(
"갤러리 접근 권한이 필요합니다",
"갤러리 접근 권한을 허용하지 않으면 파일 첨부가 불가능합니다.\n설정에서 권한을 허용해주세요.",
context,
);
}
}
}
728x90
LIST
'Flutter' 카테고리의 다른 글
Flutter에서 반응형 배너 UI와 애니메이션 구현 (1) | 2025.01.13 |
---|---|
Flutter에서 갤러리 이미지 선택 UI: 간격과 레이아웃 최적화 (이미지 썸네일) (0) | 2025.01.07 |
iOS Xcode 시뮬레이터 키보드 안보일때 (1) | 2025.01.07 |
상태 관리 ) Riverpod 2 vs Bloc vs GetX (0) | 2024.02.23 |
Dart 3.0 문법 (1) | 2024.02.21 |