Flutter

카메라 다루기 1단계

whs5758 2025. 8. 20. 17:10
  image_picker: ^1.1.2
  gal: ^2.3.2

 

패키지 설명:

패키지  용도 특징
image_picker 카메라나 갤러리에서 이미지 선택 크로스 플랫폼 지원, 안정적인 성능
gal 이미지나 비디오를 갤러리에 저장 gallery_saver의 개선된 버전, 최신 AGP 지원

 

권한 설정

Android (android/app/src/main/AndroidManifest.xml)\

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

 

iOS (ios/Runner/Info.plist)

<key>NSCameraUsageDescription</key>
<string>카메라를 사용하여 사진을 촬영합니다.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>사진을 갤러리에 저장합니다.</string>

 

AGP 오류 확인
│ [!] This is likely due to a known bug in Android Gradle Plugin (AGP) versions less than 8.2.1,   │
│ when                                                                                             │
│   1. setting a value for SourceCompatibility and                                                 │
│   2. using Java 21 or above.

 

해결 방안

settings.gradle 파일 확인

plugins {
    id "dev.flutter.flutter-plugin-loader" version "1.0.0"
    id "com.android.application" version "8.5.0" apply false  #수정
    id "org.jetbrains.kotlin.android" version "1.9.10" apply false #수정 
}

 

gradle/gradle-wrapper.propertise
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip

 

수정 후 명령어 입력

# 1. 캐시 완전 정리
flutter clean 
# 2. 의존성 다시 설치
flutter pub get
# 3. 빌드 테스트
flutter run

0

import 'package:flutter/material.dart';
import 'package:gal/gal.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String statusMessage = "사진 저장하기";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: [
              Expanded(
                child: Center(
                  child: Text(
                    statusMessage,
                    style: TextStyle(fontSize: 40),
                  ),
                ),
              ),
              Row(
                children: [
                  IconButton(
                    onPressed: _takePhoto,
                    icon: Icon(
                      Icons.camera_alt_outlined,
                      size: 50,
                    ),
                  )
                ],
              )
            ],
          ),
        ),
      ),
    );
  }

  void _takePhoto() async {
    setState(() {
      statusMessage = "카메라 준비중 ...";
    });

    try {
      // 갤러리 접근 권한 확인 요청
      if (await Gal.hasAccess() == false) {
        await Gal.requestAccess();
      }

      // 카메라에서 사진 촬영 요청
      // source - 사진 촬영
      // source - 갤러리에서 이미지 선택
      XFile? image = await ImagePicker().pickImage(
        source: ImageSource.camera,
        imageQuality: 85,
      );

      if (image != null) {
        print("저장 경로: ${image.path}");

        setState(() {
          statusMessage = "사진을 저장 중 ... ";
        });

        // 갤러리(사진첩에 촬용한 사진을 저장한다)
        await Gal.putImage(image.path);

        Future.delayed(const Duration(seconds: 3), () {
          setState(() {
            statusMessage = "사진 저장하기";
          });
        });
      }
    } catch (e) {
      print('오류 발생 $e');
      setState(() {
        statusMessage = "오류가 발생 했습니다";
      });

      Future.delayed(const Duration(seconds: 3), () {
        setState(() {
          statusMessage = "사진 저장하기";
        });
      });
    }
  } // end of takePhoto
} // end of class