반응형
Flutter에서는 dart:io의 Platform.isAndroid와 Platform.isIOS를 사용하여 플랫폼별로 다른 로직을 실행할 수 있습니다.
즉, 하나의 코드에서 안드로이드와 iOS의 백그라운드 GPS 로직을 구분해서 실행할 수 있습니다.
🏗️ 플랫폼별 구현 방식
기능안드로이드 (Android)iOS
백그라운드 실행 방식 | Foreground Service + WorkManager | Background Modes + Significant Location Change |
권한 요청 | ACCESS_BACKGROUND_LOCATION 필요 | NSLocationAlwaysUsageDescription 필요 |
위치 업데이트 방법 | getPositionStream() 사용 | getPositionStream() 또는 Region Monitoring 사용 |
백그라운드 유지 | Foreground Service로 강제 유지 가능 | 시스템이 자동으로 종료할 수 있음 |
배터리 절약 | 서비스 유지로 배터리 사용 높음 | 이동 거리를 기반으로 업데이트 |
📌 안드로이드 & iOS 통합 코드 (MVVM + Riverpod)
플랫폼에 따라 WorkManager + Foreground Service를 사용할지, Background Modes + Significant Location Change를 사용할지를 분기 처리해야 합니다.
1️⃣ 권한 요청 함수
import 'dart:io';
import 'package:geolocator/geolocator.dart';
class LocationPermissions {
static Future<bool> requestPermissions() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('위치 서비스가 비활성화됨');
}
LocationPermission 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 true;
}
}
설명
- Geolocator.checkPermission()을 사용하여 플랫폼에 관계없이 위치 권한을 확인하고 요청
- iOS의 경우 NSLocationAlwaysUsageDescription이 필요
- 안드로이드는 ACCESS_BACKGROUND_LOCATION이 추가 필요
2️⃣ 플랫폼별 GPS 업데이트 방식 선택
import 'dart:io';
import 'package:geolocator/geolocator.dart';
import 'package:workmanager/workmanager.dart';
class LocationService {
static void startTracking() {
if (Platform.isAndroid) {
_startAndroidTracking();
} else if (Platform.isIOS) {
_startIOSTracking();
}
}
// ✅ 안드로이드 - WorkManager + Foreground Service
static void _startAndroidTracking() {
Workmanager().initialize(
callbackDispatcher,
isInDebugMode: true,
);
Workmanager().registerPeriodicTask(
"1",
"fetchLocation",
frequency: Duration(minutes: 15), // 15분마다 실행
);
}
// ✅ iOS - 백그라운드 위치 업데이트
static void _startIOSTracking() {
Geolocator.getPositionStream(
locationSettings: LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 50, // 50m 이상 이동 시 업데이트
),
).listen((Position position) {
print('iOS 위치 업데이트: ${position.latitude}, ${position.longitude}');
// Hive 또는 서버에 저장
});
}
}
// ✅ 안드로이드 백그라운드에서 실행될 WorkManager 콜백
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
Position position = await Geolocator.getCurrentPosition();
print('안드로이드 위치 업데이트: ${position.latitude}, ${position.longitude}');
return Future.value(true);
});
}
설명
- Platform.isAndroid일 경우 WorkManager를 활용한 Foreground Service 실행
- Platform.isIOS일 경우 백그라운드 위치 업데이트 (Significant Location Change) 방식 실행
- WorkManager를 이용해 15분마다 위치를 업데이트 (안드로이드의 백그라운드 제한 우회)
3️⃣ MVVM + Riverpod으로 상태 관리
위치 데이터를 Riverpod을 사용해 관리하고, Hive에 저장합니다.
✅ (1) 모델 생성
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) 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];
}
}
설명
- 안드로이드와 iOS 모두에서 위치 데이터를 Hive에 저장하고 Riverpod으로 관리
- 상태가 변경될 때마다 UI 업데이트 가능
하나의 코드로 안드로이드 & iOS 대응
🎯 방법 정리
기능안드로이드iOS
권한 요청 | ACCESS_BACKGROUND_LOCATION | NSLocationAlwaysUsageDescription |
백그라운드 위치 추적 | WorkManager + Foreground Service | Significant Location Change |
GPS 업데이트 | getPositionStream() + WorkManager | getPositionStream() |
배터리 최적화 | Foreground 유지 | 백그라운드 위치 변경 감지 |
✅ 코드 통합 방법
- Platform.isAndroid와 Platform.isIOS로 분기 처리
- 안드로이드는 WorkManager + Foreground Service 활용
- iOS는 Significant Location Change 활용하여 배터리 절약
- Riverpod과 Hive를 사용해 데이터 관리
이제 하나의 코드에서 안드로이드 & iOS를 모두 지원하는 조깅 앱을 만들 수 있습니다!
구독!! 공감과 댓글,
광고 클릭은 저에게 큰 힘이 됩니다.
Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.
Tester Share [테스터쉐어] - Google Play 앱
Tester Share로 Google Play 앱 등록을 단순화하세요.
play.google.com
반응형
'Flutter > Study' 카테고리의 다른 글
HomeScreen({super.key}); vs HomeScreen({Key? key}) : super(key: key); 무슨 차이? (0) | 2025.02.14 |
---|---|
플러터 초보자를 위한 Firebase Dynamic Links 사용법: go_router와 함께 딥 링크 구현하기 (1) | 2025.02.14 |
iOS에서 백그라운드 위치 추적 구현하기 (1) | 2025.02.12 |
Flutter 실시간 경로 시각화: 조깅 앱에 Google Maps 적용하기 (0) | 2025.02.12 |
Flutter 백그라운드 위치 추적 앱 개발하기: WorkManager와 Riverpod로 구현하는 조깅 앱 (0) | 2025.02.12 |