본문 바로가기
전체보기

[TIL-5][Flutter 숙련] 마켓 앱 만들기 GPS 설정 및 VWORLD API

by 오늘도잡학다식 2025. 4. 16.

[Flutter 숙련] 마켓 앱 만들기 Part 02 :: GPS 설정 및 VWORLD API

🎯 오늘 배운 것

  • Geolocator 패키지를 사용해 GPS 센서에서 위치 정보를 가져오는 방법
  • Dio를 활용한 VWORLD API 연동
  • 위도/경도를 행정동 주소로 변환하는 실습

📌 VWORLD API 사용 준비

  1. vworld.kr 회원가입 및 로그인
  2. 오픈API 메뉴 → 인증키 발급 → 키 복사
  3. 주요 API 문서:

예시 요청 URL

https://api.vworld.kr/req/data?request=GetFeature&data=LT_C_ADEMD_INFO&key=발급받은_키&geomfilter=point(경도 위도)&geometry=false&size=100
https://api.vworld.kr/req/search?request=search&key=발급받은_키&query=검색어&type=DISTRICT&category=L4&size=100

📦 dio 패키지 연동

flutter pub add dio
// lib/data/repository/vworld_repository.dart
class VWorldRepository {
  final Dio _client = Dio(BaseOptions(validateStatus: (status) => true));

  Future<List> findByName(String query) async {
    final response = await _client.get(
      'https://api.vworld.kr/req/search',
      queryParameters: {
        'request': 'search',
        'key': '발급받은키',
        'query': query,
        'type': 'DISTRICT',
        'category': 'L4',
        'size': 100,
      },
    );

    if (response.statusCode == 200 && response.data['response']['status'] == 'OK') {
      return List.of(response.data['response']['result']['items'])
          .map((e) => e['title'].toString())
          .toList();
    }

    return [];
  }

  Future<List> findByLatLng({required double lat, required double lng}) async {
    final response = await _client.get(
      'https://api.vworld.kr/req/data',
      queryParameters: {
        'request': 'GetFeature',
        'data': 'LT_C_ADEMD_INFO',
        'key': '발급받은키',
        'geomfilter': 'point($lng $lat)',
        'geometry': 'false',
        'size': 100,
      },
    );

    if (response.statusCode == 200 && response.data['response']['status'] == 'OK') {
      return List.of(response.data['response']['result']['featureCollection']['features'])
          .map((e) => e['properties']['full_nm'].toString())
          .toList();
    }

    return [];
  }
}

📍 geolocator 패키지로 현재 위치 가져오기

flutter pub add geolocator

AndroidManifest.xml 권한 추가:

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

Info.plist (iOS)

<key>NSLocationWhenInUseUsageDescription</key>
<string>동네 정보를 가져오기 위해 위치 권한을 허용해 주세요</string>
// lib/core/geolocator_helper.dart
class GeolocatorHelper {
  static bool _idDenied(LocationPermission permission) {
    return permission == LocationPermission.denied ||
           permission == LocationPermission.deniedForever;
  }

  static Future<Position?> getPositon() async {
    final permission = await Geolocator.checkPermission();
    if (_idDenied(permission)) {
      final request = await Geolocator.requestPermission();
      if (_idDenied(request)) return null;
    }

    final locationSettings = LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 100,
    );

    return await Geolocator.getCurrentPosition(locationSettings: locationSettings);
  }
}

📚 ViewModel에 연동

// lib/ui/pages/address_search/address_view_model.dart
class AddressSearchViewModel extends AutoDisposeNotifier<List<String>> {
  @override
  List<String> build() => [];

  final vWorldRepository = VWorldRepository();

  Future<void> search(String query) async {
    state = await vWorldRepository.findByName(query);
  }

  Future<void> searchByAddress(double lat, double lng) async {
    state = await vWorldRepository.findByLatLng(lat: lat, lng: lng);
  }
}

final addressSearchViewModel =
  NotifierProvider.autoDispose<AddressSearchViewModel, List<String>>(
    () => AddressSearchViewModel(),
);

🔍 AddressSearchPage에서 GPS 버튼으로 주소 검색

ElevatedButton(
  onPressed: () async {
    final position = await GeolocatorHelper.getPositon();
    if (position != null) {
      await ref.read(addressSearchViewModel.notifier).searchByAddress(
        position.latitude,
        position.longitude,
      );
    }
  },
  child: Text('현재 위치로 찾기'),
)

📝 JoinPage에서 주소 받기

class JoinPage extends StatefulWidget {
  JoinPage({required this.address});
  final String address;

  @override
  State<JoinPage> createState() => _JoinPageState();
}

---

💬 마무리

오늘은 Flutter 마켓 앱에서 위치 기반 주소 검색 기능을 완성해보았습니다. GPS 센서를 통해 실시간 위치를 받아와 행정동 주소로 변환하는 방법을 익혔고, 외부 API(VWORLD)를 효율적으로 연동하는 실습도 함께 했습니다. 다음은 이 주소를 활용한 가입/등록 흐름 구현으로 이어집니다.