[Flutter] 지역 검색 앱 제작기 (4) - 브이월드 API, 카카오맵 API 활용

티라노·2024년 12월 9일
1

브이월드 API와 카카오맵 API를 활용해서 현위치를 기준으로 하여 주소를 검색하고 지도를 보여주는 기능을 만들어보자.

만들고 싶은 기능

이 버튼을 누르면 현위치의 행정구역을 인식하여 검색하는 기능을 만들어보려고 한다.


브이월드

브이월드는 대한민국 국토 범위 내에서 공간 정보(지도)나 일조량 등 환경 정보를 제공하는 사이트이다.
다른 API가 그렇듯이 브이월드 API도 네이버 API와 비슷한 방식으로 사용할 수 있다.

사이트에서 요청하고 싶은 데이터에 알맞은 주소를 찾고, 해당 데이터가 요구하는 파라미터를 이용하여 검색 함수를 만들면 된다.

지금부터 만들 기능은 아래 단계를 거친다.

  1. geoLocator로 디바이스의 위치 정보(위도, 경도)를 얻는다.
  2. 브이월드 API로 해당 좌표의 행정구역 이름을 얻는다.
  3. 네이버 API 검색 함수로 해당 행정구역 이름을 검색한다.

geoLocator로 좌표를 검색하는 기능은 이전 게시글에 작성하였으니 2번 기능부터 만들어보자.


1) 브이월드에서 인증 키 발급받기

링크 : https://www.vworld.kr/v4po_main.do

사이트에 접속해서 계정을 생성하고 로그인한다.

상단의 오픈API 메뉴에서 인증키를 발급할 수 있다.
다른 칸은 적당히 채우면 되고, 2D 데이터 API와 검색 API를 활용해서 인증키를 만들어보자.

발급받은 인증키를 저장하고 오픈API > API레퍼런스에 들어가서 원하는 API를 고르면 필요한 파라미터 정보를 열람할 수 있다.

2D 데이터 API 버전 2.0에 접속해서 읍면동으로 검색하면

이런 식으로 요청 파라미터나 url을 볼 수 있다.
저 중에서 M으로 표시된 파라미터는 필수이고, 가장 오른쪽에서 어떤 값을 넣어야 유효한지도 확인할 수 있다.

필요한 파라미터

  1. request : GetFeature
  2. key : 발급받은 API 키
  3. data : 사이트에서 지정한 유효값
  4. geomfilter : 검색할 좌표 POINT(위도, 경도)
    + 요청 url

thunderclient로 요청을 넣어보니 데이터가 나오기는 하는데 geometry 데이터가 같이 나와 정보량이 너무 많다.
geometry 라는 파라미터를 false로 설정해서 저 데이터를 받지 않도록 조절할 수 있다고 한다. 넣어보자.

필요했던 동 정보(스크린샷에서는 보이지 않음)만 간략하게 잘 나온 모습이다.


2) 검색 함수 만들기

이제 검색 함수를 만들어보자.
location_repository.dart 파일과 유사하게 만들면 된다.

참고 : https://velog.io/@utiranoj/Flutter-Dio-라이브러리와-모델을-이용한-http-통신

Dio 타입의 _client 객체를 만들고

위도경도를 매개변수로 받는 함수 안에 API 요청을 보내는 response 객체를 선언한다.
그리고 브이월드 API에서는 요청이 성공하면 status 변수가 OK 로 지정된다.

원래는 요청 성공을 판단할 때 응답 코드가 200인지만 확인했는데, 이번에는 이 값도 같이 써보자.
statusresponse 밑에 존재하므로 접근하고 싶을 때는 아래처럼 하면 된다.

response.data['response']['status']

그리고 생각해보니 이 함수는 Location 객체 전체가 아니라 행정구역 이름만 반환하면 돼서 반환 타입을 String 으로 바꾸고 함수 이름은 findByLatLng 에서 findDistrict 로 변경했다.

함수 설명

브이월드 API에 입력한 파라미터로 요청을 보낸다.
만약 응답 코드가 200 이고 responsestatus 값이 OK 라면 요청이 성공한 것으로 판단하고 String 타입의 emd_kor_nm (=행정구역 이름)을 반환한다.
요청에 실패했거나 오류가 생기면 빈 문자열을 반환한다.


3) 뷰모델에서 좌표로 검색하는 기능 만들기

원래는 행정구역 이름으로 검색하는 기능만 있었다.

이제부터 뷰모델에
geoLocator를 통해 받아온 좌표 -> VworldRepository.findDistrict -> findByLocation 순서대로 검색하는 기능을 만들면 된다.


4) 버튼에 기능 연결하기

이제 처음에 설명했던 대로 아이콘 버튼에 기능을 연결해보자.
검색 바 위젯을 구현해둔 home_search_bar.dart 에서 작업할 것이다.

GeoLocatorHelper.getPosition() 으로 만든 객체에는 latitude, longitude 데이터가 저장되어있어서 이 값들을 쓰면 된다.

써보려고 하니 타입이 double이었다.
생각해보면 왜 int도 아니고 String이라고 해놨었는지 모르겠다...

findDistrictsearchByLatLng 함수에서 두 데이터 타입을 모두 double로 바꿔주니 오류가 사라졌다.

오류 발생

한 번 버튼을 눌러봤더니 데이터가 나오지 않는다.
(지금은 버튼을 누른 상태)

테스트를 돌려보니 결과가 제대로 나오지 않았다.
요청 자체가 실패하고 있는 것 같다.

해결

문제는 JSON 데이터를 받아오는 방식이었다.
JSON 데이터는 Map을 이용해서 String 형태로 존재하는 데이터 컬렉션을 데이터 모델에 넣어주는 작업을 거쳐서 사용할 수 있었다.

그런데 기존 코드에서는 이런 변환 작업 없이 emd_kor_nm 을 바로 반환하고 있었던 것이다.

당연히 이 정보에는 바로 접근할 수 없다. 가공을 거치지 않은 JSON 데이터이기 때문이다.

내가 받고자 하는 데이터가 features > properties > emd_kor_nm 이니까

  1. features로 List를 만든다.
  2. List를 mapping 한다. (features.map) 이 때 mapping한 List는 내가 쓰려고 했던 정보, 즉 emd_kor_nm 으로 채워진다.
  3. 원하는 데이터만 남긴 iterable 객체를 toList()한 뒤 반환한다.

이러면 리스트의 상태는

[ㅇㅇ동]

과 같은 상태가 된다. 하지만 앱에서 원하는 검색어는 '[ㅇㅇ동]'이 아닌 'ㅇㅇ동' 이기 때문에 List의 0번 인덱스를 검색어로 쓴다.

리스트에 요소가 무조건 1개밖에 없기 때문에 쓸 수 있는 방법이다.
이렇게 구현하면 잘 나온다.


TextEditingController

현재 위치를 검색하는 버튼을 누를 때 textField에 검색어가 업데이트되지 않아서, 사용자가 현 위치가 어디인지도 모르고 이전 검색어가 그대로 남아있어 뭐라고 검색한 건지 헷갈리는 문제가 있었다.

TextEditingController를 써서 textField에 입력된 검색어를 관리해줄 필요가 있다.
선언은 이렇게 한다.

TextEditingController tec = TextEditingController();

예문은 길이를 짧게 하려고 약자를 썼지만, tec 처럼 변수명을 줄임말로 정하면 좋지 않다.
나는 textEditingController라고 풀어서 선언했다.
이 값을 textField의 controller: 속성에 넣으면 된다.

그리고 textEditingController를 쓸 때는 항상 dispose 함수를 오버라이드해서 검색할때마다 더미 데이터가 남지 않게 처리해야 한다.

다음으로 뷰모델에서 searchByLatLng 함수의 반환값을 Future<String> 으로 바꾼다. 이러면 이 함수는 state를 업데이트한 다음 검색어를 반환한다.

그리고 현위치 탐색 버튼이 있는 코드로 가서

원래는 뷰모델 함수를 실행하기만 했는데, String 변수에 검색어를 담고 해당 문자로 textEditingController를 업데이트하도록 바꿨다.
textEditingController의 문자열을 바꾸고 싶을 때는 .text 를 이용하자.

현위치 버튼을 누를 때마다 검색어가 업데이트되는 모습을 확인할 수 있다.
기능 구현 끝!
☺️☺️☺️☺️☺️☺️


도전 기능 - 지도 내장

이번에 만들어보고 싶은 기능은 앱 내에 지도를 내장하는 기능이다.
지도 모양 아이콘을 누르면 해당 주소를 임베드한 지도에 띄우고 싶다.

내가 선택한 기능은 카카오맵 API 인데 장점이 크게 세 가지 있었다.

  1. 구글맵보다 UI가 마음에 든다.
  2. 국내 지리 정보를 자세히 제공한다.
  3. 패키지가 이용하기 편했다.

1) 아이콘 및 페이지 연결

우선 지도 페이지로 이동할 수 있는 아이콘 버튼을 추가하자.


핀 모양 아이콘을 누르면 MapPage로 이동한다.
MapPage의 body에 구글맵을 임베드해서 보여줄 예정이다.


2) 카카오맵 API 키 발급

카카오 개발자센터 : https://developers.kakao.com/

로그인하고 App key를 발급받는다.
그 다음 아래 문서에서 안내하는 방법대로 데이터를 가져오면 된다.

https://developers.kakao.com/docs/latest/ko/local/dev-guide


3) kakaomap_webview 패키지 이용

kakaomap webview는 플러터 공식 팀에서 만든 라이브러리는 아니지만 편리한 기능이 이것저것 들어있다.
라이브러리 정보는 하단 링크를 참고하자.

pub dev 문서 : https://pub.dev/packages/kakaomap_webview/install
개발자 블로그 : https://devmemory.tistory.com/68

먼저 프로젝트에 패키지를 추가한다.

flutter pub add kakaomap_webview

그 다음으로는 아주 간단하다.
이렇게 위젯을 추가하고 여러 옵션을 설정하면 된다. 패키지 문서에서 필수 옵션이 무엇무엇인지 볼 수 있으니 참고하자.

카카오맵은 좌표를 기준으로 지도를 보여주는데, 네이버 API가 좌표에 소수점을 안 찍고 줘서 원하는 숫자가 나올 때까지 나누는 작업을 추가했다.

예쁘게 잘 나온다^^!
MapPage와 DetailPage에 홈으로 바로 이동할 수 있는 버튼을 추가해서 편리하게 했다.
마지막으로 색상도 입히고 나니까 깔끔한 앱이 되었다...ㅎㅎ
이제 리드미 작성하고 마무리하면 끝이다~~~☺️☺️☺️☺️☺️☺️

0개의 댓글