Flutter Study - 7주차 Using Native device

CHO WanGi·2023년 12월 26일

Flutter

목록 보기
13/27

Outline

  1. 이미지 라이브러리 활용
  2. 위치 라이브러리 활용
  3. Google Maps API 연결 -> 복습 필요
  4. 데이터 장치 저장

이미지 라이브러리 활용

1. ImagePicker

https://pub.dev/packages/image_picker

Flutter 에서 카메라로 촬영한 사진 혹은 갤러리의 이미지를 가져올때 Image_picker 패키지로 구현이 가능하다

  File? _selectedImage;

  void _takePicture() async {
    final imagePicker = ImagePicker();
    final pickedImage =
        await imagePicker.pickImage(source: ImageSource.camera, maxWidth: 600);
    if (pickedImage == null) {
      return;
    }
    setState(() {
      _selectedImage = File(pickedImage.path);
    });
    widget.onPickImage(_selectedImage!);
  }

TakePicture 함수는
패키지를 활용하여, ImageSource.camera로 카메라로 찍은 사진을 바로 업로드 하여 PickedImage 변수에 저장,
(ImageSource.gallery로 갤러리에서 찍었던 사진을 가져올 수도 있다.)

이 함수를 버튼의 OnTap 에 달아서 사용자가 버튼을 누르면, 사진을 찍고 이를 업로드 할 수 있도록 하였다.

위치 라이브러리 활용

1. Location 라이브러리

https://pub.dev/packages/location

사용자의 핸드폰 위치정보를 가져올 수 있는 패키지 이다.
적용시 버전 오류가 많이 나는 것 같다.(나를 포함하여...)

  • Error
    코틀린 버전이 너무 오래되어 location 패키지와 호환이 불가능
    -> 그 밑에 바로 해결법이 나온다

  • Solved
    해당 path 로 들어가 buildscript의 코틀린 버전을 최신버전으로 업그레이드 시켜주면 된다.

I need to Solve it...

일단 위치 라이브러리를 활용하는 UI는 다음과 같다,
Scaffold -> Appbar -> SingleChildScrollView -> Column -> Textfield/ImageInput/LocationInput/ElevatedButton

의 구조로 되어있다.
LocationInput에 지도 출력관련에서 API 링크가 잘못된건지 위치 정보 로드는 잘 되는데 지도 화면이 나타나지를 않는다

사용자의 위치정보 가져오기

void _getCurrentLocation() async {
    setState(() {
      _isGettingLocation = true;
    });
    Location location = Location();

    bool serviceEnabled;
    PermissionStatus permissionGranted;
    LocationData locationData;
	// 서비스 가능여부 확인 코드
    serviceEnabled = await location.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await location.requestService();
      if (!serviceEnabled) {
        return;
      }
    }
    // 사용자 허가 확인 여부 체크
      permissionGranted = await location.hasPermission();
    if (permissionGranted == PermissionStatus.denied) {
      permissionGranted = await location.requestPermission();
      if (permissionGranted != PermissionStatus.granted) {
        return;
      }
    }

    locationData = await location.getLocation();
    final lat = locationData.latitude;
    final lng = locationData.longitude;

    if (lat == null || lng == null) {
      return;
    }
    _savePlace(lat, lng);
  }

Location 타입의 위치정보를 locationData로 가져와서
우리 사람이 읽을 수 있는 주소인 위,경도(lat,lng)로 변환하여 저장하는 기능을 하는 함수이다.
값이 비었는지 유효성검사를 하고 저장한다.

Goolge Maps API 연결

https://codelabs.developers.google.com/codelabs/google-maps-in-flutter?hl=ko#2

아주 친절하게 단계별로 나와있어 잠시 빌려보도록 하자면
기본적인 flutter 구성이 완료 되었다면

https://pub.dev/packages/google_maps_flutter
위 패키지를 추가하고,

IOS/Android 별로 추가로 또 뭔갈 해야 사용이 가능하다.
IOS(PodFile) 같은경우 버전이 11.0 이상,
안드로이드(build.gradle)는 minSdkVersion을 20 으로 바꾸어 주어야 한다.

그리고 안드로이드에는 AndroidManifest.xml 파일에 자신의 APIKEY 를 담아서 메타 데이터를 추가 해주어야 한다.

  • GoogleMap 클래스
GoogleMap(
        onTap: !widget.isSelecting
            ? null
            : (position) {
                setState(() {
                  _pickedLoctiaon = position;
                });
              },
        initialCameraPosition: CameraPosition(
          target: LatLng(
            widget.location.latitude,
            widget.location.longitude,
          ),
          zoom: 16,
        ),
        markers: (_pickedLoctiaon == null && widget.isSelecting)
            ? {}
            : {
                Marker(
                  markerId: const MarkerId('m1'),
                  position: _pickedLoctiaon ??
                      LatLng(
                        widget.location.latitude,
                        widget.location.longitude,
                      ),
                ),
              },
      ),
    );

Location 데이터를 Provider를 사용하여 한곳에서 관리하고 있음을 알린다.

class UserPlacesNotifier extends StateNotifier<List<Place>> {
  // 초기 값  전달(빈 리스트)
  UserPlacesNotifier() : super(const []);

  Future<void> loadPlaces() async {
    final db = await _getDatabase();
    final data = await db.query('user_places');
    final places = data
        .map(
          (row) => Place(
            id: row['id'] as String,
            title: row['title'] as String,
            image: File(row['image'] as String),
            location: PlaceLocation(
                latitude: row['lat'] as double,
                longitude: row['lng'] as double,
                address: row['address'] as String),
          ),
        )
        .toList();
    state = places;
  }

SQL DB 활용

우리에게 데이터베이스가 없다면, 폰을 껏다가 키면 그동안 저장했던 데이터가 사라진다.

https://pub.dev/packages/path_provider
=> 운영체제에 의해 데이터 삭제를 방지하는 패키지

https://pub.dev/packages/path/install
=> 경로를 간소화하는 패키지

https://pub.dev/packages/sqflite/install
=> SQL DB를 flutter code로 생성가능토록 만드는 이미지

  • DB 생성
import 'package:path_provider/path_provider.dart' as syspaths;
import 'package:path/path.dart' as path;
import 'package:sqflite/sqflite.dart' as sql;
import 'package:sqflite/sqlite_api.dart';

Future<Database> _getDatabase() async {
  final dbPath = await sql.getDatabasesPath();
  final db = await sql.openDatabase(
    path.join(dbPath, 'places.db'),
    onCreate: (db, version) {
      return db.execute(
          'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, location TEXT, lat REAL, lon REAL, lng REAL, address TEXT)');
    },
    // 데이터 변경시마다 이 값이 1씩 올라간다
    version: 1,
  );
  return db;
}

이렇게 SQL 문법을 활용하여 필요한 데이터베이스를 만들고 여기 데이터를 저장할 수 있다.

  • DB data 추가
void addPlace(String title, File image, PlaceLocation location) async {
    final appDir = await syspaths.getApplicationCacheDirectory();
    final filename = path.basename(image.path);
    final copiedImage = await image.copy('${appDir.path}/$filename');

    final newPlace =
        Place(title: title, image: copiedImage, location: location);
    final db = await _getDatabase();
    db.insert('user_places', {
      'id': newPlace.id,
      'title': newPlace.title,
      'image': newPlace.image.path,
      'lat': newPlace.location.latitude,
      'lng': newPlace.location.longitude,
      'address': newPlace.location.address
    });
    // spread operator 를 통해 state가 바뀌어도 기존 내용을 잃어버리지 않도록
    state = [newPlace, ...state];
  }

insert 키워드를 활용하여 Place 클래스로 들어오는 장소 제목과 이미지, 위치 정보를 db에 집어넣을 수 있다.
Future 타입의 데이터를 가져오기 때문에 async await을 활용하였다.

profile
제 Velog에 오신 모든 분들이 작더라도 인사이트를 얻어가셨으면 좋겠습니다 :)

0개의 댓글