반응형
안드로이드에서는 Foreground Service를 활용하면 되지만, iOS는 백그라운드에서 GPS를 실행할 수 있는 정책이 다릅니다.
iOS는 사용자의 배터리 소모를 줄이기 위해 앱이 백그라운드 상태일 때 대부분의 작업을 제한합니다.
하지만 Background Modes와 Significant Location Changes (중요 위치 변경), Region Monitoring을 사용하면 조깅 앱에서도 지속적인 위치 추적이 가능합니다.
1️⃣ iOS에서 백그라운드 위치 추적을 위한 설정
🔹 (1) Info.plist에 백그라운드 권한 추가
ios/Runner/Info.plist 파일을 열고 다음을 추가합니다.
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>조깅 기록을 위해 사용자의 위치를 백그라운드에서도 추적합니다.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>조깅 기록을 위해 위치를 사용합니다.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>조깅 기록을 위해 백그라운드에서도 위치를 추적합니다.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>fetch</string>
</array>
설명
- NSLocationAlwaysAndWhenInUseUsageDescription: 앱이 포그라운드 & 백그라운드 모두에서 위치 정보를 사용할 것임을 알림.
- NSLocationWhenInUseUsageDescription: 앱이 포그라운드에서 위치를 사용할 것임을 알림.
- NSLocationAlwaysUsageDescription: 항상 위치를 추적할 권한 요청.
- UIBackgroundModes: location을 추가하면 앱이 백그라운드에서도 위치를 추적할 수 있음.
2️⃣ Flutter에서 iOS 백그라운드 위치 추적 구현
🔹 (1) geolocator 패키지 설정
geolocator 패키지를 사용하면 백그라운드에서 GPS 위치를 추적할 수 있습니다.
import 'package:geolocator/geolocator.dart';
class LocationService {
Future<Position?> getCurrentPosition() async {
bool serviceEnabled;
LocationPermission permission;
// 위치 서비스 활성화 확인
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('위치 서비스가 비활성화되어 있습니다.');
}
// 위치 권한 확인
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('위치 권한이 거부되었습니다.');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error('위치 권한이 영구적으로 거부되었습니다. 설정에서 변경해야 합니다.');
}
// 현재 위치 반환
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
);
}
}
설명
- 위치 서비스가 활성화되었는지 확인
- 위치 권한 요청 (사용자가 허용하지 않으면 오류 반환)
- 현재 위치 가져오기 (LocationAccuracy.best 옵션 사용)
🔹 (2) 백그라운드에서도 위치 업데이트 받기
iOS에서 백그라운드 실행을 지속하려면 "Significant Location Change" 또는 "Region Monitoring" 방식을 사용해야 합니다.
✅ 1) 중요한 위치 변경(Significant Location Change)
이 방법은 배터리 소모를 줄이면서도 백그라운드에서 지속적인 위치 업데이트를 받을 수 있습니다.
import 'package:geolocator/geolocator.dart';
class BackgroundLocationService {
static Future<void> startTracking() async {
Geolocator.getPositionStream(
locationSettings: LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 50, // 50m 이동 시 업데이트
),
).listen((Position position) {
print('새로운 위치: ${position.latitude}, ${position.longitude}');
// Hive 또는 서버에 저장
});
}
}
설명
- getPositionStream(): 위치가 업데이트될 때마다 호출
- distanceFilter: 50 → 50m 이상 이동해야 업데이트됨 (배터리 절약)
- accuracy: high → GPS 정확도를 최대한 높임
✅ 2) 지오펜싱(Region Monitoring)
특정 지역을 설정하면 앱이 백그라운드에서도 해당 지역에 들어오거나 벗어날 때 이벤트를 감지할 수 있습니다.
import 'package:geolocator/geolocator.dart';
import 'package:geofence_service/geofence_service.dart';
class RegionMonitoringService {
final _geofenceService = GeofenceService.instance;
void startGeofencing() {
_geofenceService.start(
geofenceList: [
Geofence(
id: 'home',
latitude: 37.5665,
longitude: 126.9780,
radius: [100.0], // 100m 반경 감지
triggers: [GeofenceTrigger.enter, GeofenceTrigger.exit],
),
],
);
}
}
설명
- Geofence 설정 → 사용자가 설정한 위치(예: 집, 공원)에 들어오거나 벗어날 때 이벤트 발생
- 배터리를 적게 소모하면서도 특정 지역에서 자동 감지가 가능
3️⃣ 조깅 앱 MVVM 패턴 적용
🔹 (1) Location Model
import 'package:hive/hive.dart';
@HiveType(typeId: 1)
class LocationModel {
@HiveField(0)
final double latitude;
@HiveField(1)
final double longitude;
@HiveField(2)
final DateTime timestamp;
LocationModel({required this.latitude, required this.longitude, required this.timestamp});
}
🔹 (2) Location ViewModel
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive/hive.dart';
import 'package:geolocator/geolocator.dart';
final locationProvider = StateNotifierProvider<LocationNotifier, List<LocationModel>>((ref) {
return LocationNotifier();
});
class LocationNotifier extends StateNotifier<List<LocationModel>> {
LocationNotifier() : super([]);
Future<void> addLocation(Position position) async {
final location = LocationModel(
latitude: position.latitude,
longitude: position.longitude,
timestamp: DateTime.now(),
);
final box = await Hive.openBox<LocationModel>('locationBox');
box.add(location);
state = [...state, location];
}
}
설명
- Hive를 사용하여 GPS 데이터를 로컬에 저장
- Riverpod을 활용한 상태 관리
iOS에서는 Foreground Service를 사용할 수 없기 때문에, 아래 3가지 방법을 조합해서 백그라운드 위치 추적을 수행해야 합니다.
- 백그라운드 모드 활성화 (UIBackgroundModes → location 추가)
- Significant Location Change 방식 사용 (배터리 절약 가능)
- Region Monitoring을 활용한 특정 지역 감지
📝 정리
- iOS에서 Foreground Service가 없는데 백그라운드에서 GPS를 지속적으로 추적하려면?
→ Background Modes + Significant Location Change + Region Monitoring 조합 - WorkManager 대신 무엇을 사용해야 할까?
→ Geolocator + 백그라운드 위치 업데이트 방식 - MVVM 패턴 적용이 가능할까?
→ Riverpod과 Hive를 활용하여 상태 관리 가능
이제 이 방법을 적용하면 iOS에서도 백그라운드에서 GPS를 추적하는 조깅 앱을 만들 수 있습니다! 🚀
반응형
'Flutter > Study' 카테고리의 다른 글
플러터 초보자를 위한 Firebase Dynamic Links 사용법: go_router와 함께 딥 링크 구현하기 (1) | 2025.02.14 |
---|---|
위치 추적앱 안드로이드와 iOS, 한 코드로 통합할 수 있을까? (0) | 2025.02.12 |
Flutter 실시간 경로 시각화: 조깅 앱에 Google Maps 적용하기 (0) | 2025.02.12 |
Flutter 백그라운드 위치 추적 앱 개발하기: WorkManager와 Riverpod로 구현하는 조깅 앱 (0) | 2025.02.12 |
플러터에서 조깅 앱을 만들 때 백그라운드에서 GPS 위치를 계속 저장하는 방법 (1) | 2025.02.12 |