구글 맵 API를 이용하기 위한 google_maps_flutter 플러그인과 GPS 활용을 위한 geolocator 플러그인을 사용하여 회사나 목적지 근처에 도착을 체크하는 예제를 만들어보자.
Geolocator 플러그인
Geolocator 플러그인의 주요 기능은 위치 서비스 권한을 얻거나 확인하는 것과 GPS 위치를 활용할 수 있는 것이다.
위치 서비스 권한
위치 서비스 권한이 켜져 있는지 확인하는 함수로 IsLocationServiceEnabled() 를 사용한다.
bool isLocationEnabled = await Geolocator.isLocationServiceEnabled();
앱의 위치 서비스 사용 권한 확인 함수는 checkPermission() 이다. 권한 확인 후 아직 권한을 받지 못하였다면 requestPermission() 함수로 권한을 요청한다.
LocationPermission chkPermission = await Geolocator.checkPermission();
LocationPermission reqPermission = await Geolocator.requestPermission();
LocationPermission
- denied – 기본 상태(요청한 적이 없는 상태) 또는 거절 상태.
- deniedForever – 완전 거절 상태로 이 상태에서는 기기의 설정 화면에서 직접 허가해 줘야 한다.
- whileInUse – 앱이 사용 중일때만 허가된 상태.
- always – 허가 상태. (항상)
- unableToDetermine – 알 수 없음. (앱에서는 해당 사항이 없음)
현재 위치 스트리밍
Geolocator 플러그인의 getPositionStream() 함수로 현재 위치 변경 감지 시마다 Position 클래스 타입으로 얻어올 수 있다.
Geolocator.getPositionStream().listen((Position position) { });
위치 간의 거리 구하는 방법
Geolocator 플러그인의 distanceBetween() 함수를 사용한다.
final distance = Geolocator.distanceBetween( startLat, startLng, endLat, endLng );
Google Map API Key 발급 방법
구글 클라우드에 접속하여 프로젝트를 하나 임의의 이름으로 생성한다.


상단 탐색창에 “Maps SDK for”를 입력하고 검색한다.

검색한 Maps SDK 활성화 과정을 마치고 아래 스크린샷과 같이 “키 및 사용자 인증 정보”로 가서 “키 표시” 버튼을 통해 키를 복사해 둔다.

예제 구현
플러그인 추가 – google_maps_flutter, geolocator
pubspec.yaml
...
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
google_maps_flutter: ^2.9.0
geolocator: ^13.0.1
...
위치 사용 권한과 구글 맵 API 키 등록
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
...
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="발급받은 구글 맵 API 키"/>
...
ios/Runner/AppDelegate.swift
import Flutter
import UIKit
import GoogleMaps
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMServices.provideAPIKey("발급받은 구글 맵 API 키")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
info.plist
...
<key>NSLocationWhenInUseUsageDesription</key>
<string>위치 정보가 필요합니다.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>위치 정보가 필요합니다.</string>
</dict>
</plist>
예제 코드
파일 구조

이번 예제는 home_screen 단일 파일로 구현되었다.
main.dart
import 'package:flutter/material.dart';
import 'package:geo_chool_check/screen/home_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const HomeScreen(),
);
}
}
screen/home_screen.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class HomeScreen extends StatelessWidget {
static final LatLng companyLatLng = LatLng(37.5649151, 126.9870850);1
static final Marker marker = Marker(
markerId: MarkerId('company'),
position: companyLatLng,
);
static final Circle circle = Circle(
circleId: CircleId('checkCircle'),
center: companyLatLng,
fillColor: Colors.blue.withValues(alpha: 0.5),
radius: 100,
// 반지름 (미터 단위)
strokeColor: Colors.blue,
strokeWidth: 1,
);
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: renderAppBar(),
body: FutureBuilder(
future: checkPermission(),
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.data == "위치 권한이 허용 되었습니다.") {
return Column(
children: [
Expanded(
flex: 2,
child: GoogleMap2(
initialCameraPosition: CameraPosition(
target: companyLatLng,
zoom: 16,
),
myLocationEnabled: true3,
myLocationButtonEnabled: true,
markers: {marker}4,
circles: {circle},
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.timelapse_outlined,
color: Colors.blue,
size: 50.0,
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () async {
final curPos = await Geolocator.getCurrentPosition();
final distance = Geolocator.distanceBetween(
curPos.latitude,
curPos.longitude,
companyLatLng.latitude,
companyLatLng.longitude,
);
bool canCheck = distance < 100;5
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('Check'),
content: Text(
canCheck
? 'Could you check now?'
: "You can't check where current position",
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('Cancel'),
),
if (canCheck)
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('Do Check'),
),
],
);
},
);
},
child: Text('Check!'),
),
],
),
),
],
);
}
return Center(child: Text(snapshot.data.toString()));
},
),
);
}
AppBar renderAppBar() {
return AppBar(
centerTitle: true,
title: Text(
'출첵',
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w700),
),
backgroundColor: Colors.white,
);
}
Future<String> checkPermission() async {
// 위치 서비스 활성화 여부
final isLocationEnabled = await Geolocator.isLocationServiceEnabled();
if (!isLocationEnabled) {
return '위치 서비스를 활성화해주세요.';
}
// 위치 권한 확인
LocationPermission checkPermission = await Geolocator.checkPermission();
// 위치 권한 거절 상태
if (checkPermission == LocationPermission.denied) {
// 위치 권한 요청
checkPermission = await Geolocator.requestPermission();
if (checkPermission == LocationPermission.denied) {
return '위치 권한을 허용해 주세요.';
}
}
// 위치 권한 재요청 불가
if (checkPermission == LocationPermission.deniedForever) {
return "앱의 위치 권한 설정을 허용해 주세요.";
}
return "위치 권한이 허용 되었습니다.";
}
}
- LatLng 클래스는 위도와 경도로 위치를 표현하는 클래스이다. 첫 번째 매개변수 latitude에 위도를 두 번째 매개변수 longitude에 경도를 입력해 준다. ↩︎
- GoogleMap 위젯은 필수 입력인 initialCameraPosition 인자가 있다. 여기에는 CameraPosition 클래스를 입력해 준다. CameraPosition의 target 인자는 지도의 중심이 될 위치를 LatLng로 입력할 수 있다. ↩︎
- 현재 위치를 지도에 표시하는 옵션으로 GoogleMap 위젯에 myLocationEnabled 인자가 있다. 기본 값이 false이니 true로 입력해 주었다. ↩︎
- Marker 클래스를 사용하여 각 마커별 ID와 함께 위치를 입력해 준다. 그 후 GoogleMap 위젯의 markers 인자에 Set 형태로 원하는 만큼의 Marker를 넣어준다. ↩︎
- 목표 지점과 100미터 반경 안에 있는 경우 체크 가능하도록 팝업 화면의 버튼을 활성화 해 주었다. ↩︎