๐Ÿฆ Flutter ๋„ค์ดํ‹ฐ๋ธŒ ํŒจํ‚ค์ง€_Geolocator๋กœ ์œ„์น˜ ์ •๋ณด ์–ป๊ธฐ

YeonheeHanยท2024๋…„ 1์›” 6์ผ
0
post-thumbnail

์œ„์น˜ ์ •๋ณด ์–ป๊ธฐ
https://pub.dev/packages/geolocator

1. Android

android ํด๋” > app ํด๋” > src ํด๋” > profile ํด๋” > AndroidManifest.xml ํŒŒ์ผ

์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ geolocator๋ฅผ ์ด์šฉํ•˜๋ ค๋ฉด AndroidManifest.xml ํŒŒ์ผ์— ํผ๋ฏธ์…˜์„ ์„ ์–ธํ•ด์•ผ ํ•จ. AndroidManifest.xml ์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜๋Š” ํŒŒ์ผ์ด๋ฉฐ ์ด๊ณณ์— ํผ๋ฏธ์…˜์„ ์„ค์ •ํ•จ. ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์‹คํ–‰๋˜๋Š” ์•ฑ์ด ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ์–ป์œผ๋ ค๋ฉด AndroidManifest.xml ์— ํผ๋ฏธ์…˜์„ ๋‹ค์Œ์ฒ˜๋Ÿผ ์„ ์–ธํ•ด์•ผ ํ•จ.

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

2. iOS

ios ํด๋” > Runner ํด๋” > info.plist ํŒŒ์ผ

iOS์—์„œ ์‹คํ–‰๋˜๋Š” ์•ฑ์ด ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ์–ป์œผ๋ ค๋ฉด iOS ์•ฑ์˜ info.plist ํŒŒ์ผ์— ๋‹ค์Œ์ฒ˜๋Ÿผ ํ‚ค๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•จ.

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>

๐Ÿ“ ํ˜„์žฌ ์œ„์น˜ ์–ป๊ธฐ

์•ˆ๋“œ๋กœ์ด๋“œ์™€ iOS ์„ค์ •์„ ํ–ˆ์œผ๋ฉด ์ด์ œ ๋‹คํŠธ ์ฝ”๋“œ์—์„œ geolocator ํŒจํ‚ค์ง€๋ฅผ ์ด์šฉํ•ด ํ˜„์žฌ ์œ„์น˜๋ฅผ ์–ป์œผ๋ฉด ๋จ. geolocator ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์€ Geolocator ํด๋ž˜์Šค์˜ ํ•จ์ˆ˜๋กœ ์ œ๊ณตํ•จ.

๋จผ์ € ํ˜„์žฌ ์œ„์น˜๋ฅผ ์–ป๊ธฐ ์ „์— ๊ธฐ๊ธฐ์—์„œ ์œ„์น˜ ์ •๋ณด ํš๋“ ๊ธฐ๋Šฅ์ด ํ™œ์„ฑํ™”๋˜์—ˆ๋Š”์ง€๋ฅผ ํŒ๋‹จํ•ด์•ผ ํ•จ. ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ธฐ๊ธฐ ์„ค์ • ๋“ฑ์œผ๋กœ ์œ„์น˜ ์ถ”์ ์ด ๋ถˆ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ. ์ด๋Š” Geolocator.isLocationServiceEnabled() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์‰ฝ๊ฒŒ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์Œ. ์ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ด true ๋ฉด ํ™œ์„ฑ ์ƒํƒœ, false ์ด๋ฉด ๋น„ํ™œ์„ฑ ์ƒํƒœ๋ผ๋Š” ์˜๋ฏธ์ž„.

// ์œ„์น˜ ์ •๋ณด ํš๋“ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธ
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!servieEnabled) {
	return Future.error('Location services are disabled.');
}

๊ธฐ๊ธฐ์—์„œ ์œ„์น˜ ์ถ”์  ๊ธฐ๋Šฅ์ด ํ™œ์„ฑ ์ƒํƒœ๋ผ๊ณ  ํ•˜๋ฉด ๊ทธ๋‹ค์Œ์œผ๋กœ ํผ๋ฏธ์…˜ ์„ค์ •์„ ํ™•์ธํ•จ. ์œ„์น˜ ์ถ”์ ์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฏผ๊ฐํ•œ ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ํ—ˆ์šฉํ• ์ง€๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ  ์žˆ์Œ. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์˜ ์œ„์น˜ ์ถ”์  ๊ธฐ๋Šฅ์„ ๊ฑฐ๋ถ€ํ–ˆ๋‹ค๋ฉด ์ฝ”๋“œ์—์„œ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Œ. ์•ฑ์— ์œ„์น˜ ์ถ”์  ํผ๋ฏธ์…˜์ด ์„ค์ •๋๋Š”์ง€๋Š” Geolocator.checkPermission() ํ•จ์ˆ˜๋กœ ์‰ฝ๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Œ. ์ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์€ LocationPermission ๊ฐ์ฒด์ด๋ฉฐ ์ด ๊ฐ’์ด Location.denied ๋ผ๋ฉด ํผ๋ฏธ์…˜์ด ๊ฑฐ๋ถ€๋œ ์ƒํƒœ์ž„.

// ์œ„์น˜ ์ถ”์  ํผ๋ฏธ์…˜ ํ™•์ธ
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
	permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
    	return Future.error('permissions are denied');
    }
}

ํผ๋ฏธ์…˜์ด ๊ฑฐ๋ถ€๋œ ์ƒํƒœ์—์„œ๋Š” ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ํผ๋ฏธ์…˜์„ ํ—ˆ์šฉํ•ด ๋‹ฌ๋ผ๊ณ  ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋„์›Œ์•ผ ํ•จ. ํผ๋ฏธ์…˜ ์กฐ์ • ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋„์šฐ๋Š” ํ•จ์ˆ˜๋Š” GeoLocatior.requestPermission(). ๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค์‹œ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ๋‹ซํž ๋•Œ ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ป๊ฒŒ ์กฐ์ •ํ–ˆ๋Š”์ง€๋ฅผ GeoLocation. requestPersmission() ํ•จ์ˆ˜์˜ ๊ฒฐ๊ด๊ฐ’์œผ๋กœ ๋ฐ›์•„ ๋‹ค์‹œ ํ•œ๋ฒˆ ํผ๋ฏธ์…˜์„ ํ™•์ธํ•ด์•ผ ํ•จ.

๋งŒ์•ฝ ์œ„์น˜ ์ถ”์  ํผ๋ฏธ์…˜์„ ์ •์ƒ์œผ๋กœ ๋ถ€์—ฌํ–ˆ๋‹ค๋ฉด ์ด์ œ ์œ„์น˜๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Œ. ์ด๋•Œ Geolocator.getCurrentPosition() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•จ. ์ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ธ Position ๊ฐ์ฒด๊ฐ€ ํ˜„์žฌ ์œ„์น˜์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์ž„. ์œ„์น˜๋Š” ์œ„๋„์™€ ๊ฒฝ๋„ ๊ฐ’์ด๋ฉฐ Position ๊ฐ์ฒด์˜ latitude, longitude ์†์„ฑ์œผ๋กœ ์–ป์Œ. latitude์™€ Longitude๋Š” double ํƒ€์ž…์˜ ์‹ค์ˆ˜์ž„.

// ํ˜„์žฌ ์œ„์น˜ ๊ตฌํ•˜๊ธฐ
Position position = await Geolocator.getCurrentPosition();
setState(() {
	latitude = position.latitude.toString();
    longitude = position.longitude.toString();
});

๐Ÿ“ ํ˜„์žฌ ์œ„์น˜ ํ™œ์šฉํ•˜๊ธฐ

gelolocator ํŒจํ‚ค์ง€๋ฅผ ํ™œ์šฉํ•ด ํ˜„์žฌ ์œ„์น˜๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์•ฑ์„ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ž„. ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ์™€ ์—ฐ๋™ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์•ˆ๋“œ๋กœ์ด๋“œ์™€ iOS ๊ฐ๊ฐ์—์„œ ํ…Œ์ŠคํŠธํ•ด๋ณด๋ ค ํ•จ.

1๋‹จ๊ณ„. ํŒจํ‚ค์ง€ ๋“ฑ๋กํ•˜๊ธฐ

pubspec.yaml ํŒŒ์ผ์„ ์—ด๊ณ  dependencies ํ•ญ๋ชฉ์— ๋‹ค์Œ์ฒ˜๋Ÿผ ํŒจํ‚ค์ง€๋ฅผ ๋“ฑ๋กํ•œ ํ›„ <Pub Get> ์„ ํด๋ฆญ.

dependencies:
  geolocator: ^8.2.1

2๋‹จ๊ณ„. ๋‹คํŠธํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ

lib ํ•˜์œ„์— ์žˆ๋Š”main.dart ํŒŒ์ผ์— ๋‹ค์Œ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ.

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return new MaterialApp(
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: NativePluginWidget(),
    );
  }
}

class NativePluginWidget extends StatefulWidget {
  
  NativePluginWidgetState createState() => NativePluginWidgetState();
}

class NativePluginWidgetState extends State<NativePluginWidget> {
  String? latitude;
  String? longitude;

  getGeoData() async {
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        return Future.error('permissions are denied');
      }
    }

    Position position await Geolocator.getCurrentPosition();
    setState(() {
      latitude.position.latitude.toString();
      longitude.position.longitude.toString();
    });
  }

  
  void initState() {
    super.initState();
    getGeoData();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Geolocator")),
      body: Container(
        color: Colors.indigo,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: (<Widget>[
              Text(
                'MyLocation',
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
              Text(
                'latitude : ${latitude}',
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
              Text(
                'longitude: ${longitude}',
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
            ]),
          ),
        ),
      ),
    );
  }
}


3๋‹จ๊ณ„. ์•ˆ๋“œ๋กœ์ด๋“œ ์„ค์ •ํ•˜๊ธฐ

์•ˆ๋“œ๋กœ์ด๋“œ ๋ฉ”์ธ ํ™˜๊ฒฝ ํŒŒ์ผ์„ ์—ด๊ณ  ํผ๋ฏธ์…˜์„ ์„ ์–ธํ•œ๋‹ค. ์ด ํŒŒ์ผ์€ android/app/src/main ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์žˆ์Œ. ์ด ํŒŒ์ผ์„ ์—ด์–ด ๋‹ค์Œ์ฒ˜๋Ÿผ ํผ๋ฏธ์…˜์„ ์„ ์–ธํ•จ.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.flutter_lab">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  ...(์ƒ๋žต)...
</manifest>

๊ทธ๋Ÿฐ๋‹ค์Œ ์•ˆ๋“œ๋กœ์ด๋“œ AVD๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์ƒ์˜ ์œ„์น˜ ์ •๋ณด๋ฅผ ์„ค์ •ํ•จ. AVD ์ƒ๋‹จ์˜ ๋„๊ตฌ์—์„œ ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ์˜ Extended Controls ๋ผ๊ณ  ํ•˜๋Š” ์•„์ด์ฝ˜์„ ํด๋ฆญํ•จ.

๋‹ค์Œ์ฒ˜๋Ÿผ ์—๋ฎฌ๋ ˆ์ดํ„ฐ ์„ค์ • ์ฐฝ์ด ๋œจ๋ฉด ์™ผ์ชฝ ๋ฉ”๋‰ด์—์„œ Location ์„ ์„ ํƒํ•˜๊ณ  ์ง€๋„์—์„œ ์ž„์˜์˜ ์ง€์ ์„ ํด๋ฆญํ•จ. ๊ทธ๋ฆฌ๊ณ  ์ง€๋„ ์•„๋ž˜์— SAVE POINT ๋ฅผ ํด๋ฆญํ•œ ํ›„ Set Location์„ ํด๋ฆญํ•˜๋ฉด ์ง€๋„์—์„œ ์„ ํƒํ•œ ์ง€์ ์˜ ์œ„์น˜๊ฐ€ ํ˜„์žฌ ๊ธฐ๊ธฐ์˜ ์œ„์น˜๋กœ ์„ค์ •๋จ.

4๋‹จ๊ณ„. ์•ˆ๋“œ๋กœ์ด๋“œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์•ฑ ์‹คํ–‰ํ•˜๊ธฐ

1๋‹จ๊ณ„์—์„œ ์ž‘์„ฑํ•œ main.dart ํŒŒ์ผ์„ ์•ˆ๋“œ๋กœ์ด๋“œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์‹คํ–‰ํ•ด ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•จ. ์•ฑ์„ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๊ธฐ๊ธฐ์˜ ์œ„์น˜ ์ •๋ณด์— ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•  ๊ฒƒ์ธ์ง€ ๋ฌป๋Š” ์ฐฝ์ด ๋‚˜ํƒ€๋‚จ. ์—ฌ๊ธฐ์„œ While using the app (์•ฑ ์‚ฌ์šฉ ์ค‘์—๋งŒ ํ—ˆ์šฉ) ์ด๋‚˜ Only this time(์ด๋ฒˆ๋งŒ ํ—ˆ์šฉ) ์„ ํด๋ฆญํ•˜๋ฉด ํ˜„์žฌ ์œ„์น˜๊ฐ€ ์ถœ๋ ฅ๋˜๊ณ , Don't allow(ํ—ˆ์šฉ ์•ˆ ํ•จ) ์„ ํด๋ฆญํ•˜๋ฉด 'permissions are denied' ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋จ.


5๋‹จ๊ณ„. iOS ์„ค์ •ํ•˜๊ธฐ

iOS์˜ info.plist ํŒŒ์ผ์— ํ‚ค๋ฅผ ์„ ์–ธํ•จ. ์ด ํŒŒ์ผ์€ iOS/Runner ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์žˆ์Œ. info.plist ํŒŒ์ผ์„ ์—ด๊ณ  ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์— ๋‹ค์Œ์ฒ˜๋Ÿผ ํ‚ค๋ฅผ ๋“ฑ๋กํ•จ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  	...(์ƒ๋žต)...
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>This app needs access to location when open.</string>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>This app needs access to location when in the background.</string>
</dict>
</plist>

๊ทธ๋Ÿฐ ๋‹ค์Œ iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์ƒ์˜ ์œ„์น˜ ์ •๋ณด๋ฅผ ์„ค์ •ํ•จ. ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ Features > Location > Custom Location ๋ฉ”๋‰ด๋ฅผ ํด๋ฆญํ•จ.

5๋‹จ๊ณ„. iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์•ฑ ๋นŒ๋“œํ•˜๊ธฐ

1๋‹จ๊ณ„์—์„œ ์ž‘์„ฑํ•œ main.dart ํŒŒ์ผ์„ Xcode์˜ iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์‹คํ–‰ํ•ด ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•จ.


์ถœ์ฒ˜: https://product.kyobobook.co.kr/detail/S000200832185

profile
Educational Business Manager, Technical Product Manager

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 11์›” 21์ผ

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ์œ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ