본문 바로가기
앱인벤터/실전 앱

앱인벤터 날씨정보(일기예보) 앱 만들기

by 이지이지(EGEasy) 2021. 10. 29.

============================================================================================[2023. 5. 27.] 다음 글과 소스는 관련 openweathermap의 정책 변경으로 유효하지 않음을 말씀드립니다.

다음 소스를 사용하고 싶으신 분께서는 openweahtermap 사이트를 구독하셔야 함을 알려 드립니다.

============================================================================================

 

날씨정보(일기예보) 예제 앱 화면

 

안녕하세요. 이지이지입니다.

이번 포스팅에서는 사용자의 위치정보를 자동으로 알아내어 그 지역의 날씨정보(일기예보)를 제공하는 앱을 만드는 방법에 대해 알아보겠습니다.

 

이번 포스팅을 통해 여러분은

1. LocationSensor(위치 센서) 컴포넌트

2. 카카오 로컬 API 및 OpenWeatherMap API

3. 프로시저 등에 대해 배울 수 있습니다.

 

시작하기 전 API 사용방법과 JSON 데이터를 처리하는 방법을 필수적으로 알아야 하기에,

API와 JSON에 대해 잘 모르시는 분께서는 저의 이전 포스팅을 참고하시기 바랍니다.

 

 

앱인벤터 강좌 #5 API, JSON 사용방법 및 Dictionary 컴포넌트 활용하기

안녕하세요. 이지이지입니다. 이번 포스팅에서는 각종 API 사용방법과 API를 통해 데이터를 받았을 때 가장 흔히 쓰이는 데이터 형식인 JSON 다루기, 그리고 앱인벤터에서 JSON과 잘 어울리는 Dictiona

egeasy.tistory.com

 

 

완성된 앱인벤터 소스 파일입니다.

 

 

 

 

 

 

 

 

eg_weather.aia
0.05MB

 

 

 

    화면 구성

날씨정보 앱 화면 구성

 

소스 파일을 열어보면 화면 구성이 꽤나 복잡합니다.

아무래도 시간 단위, 날짜 단위로 앱을 구성하다 보니 많은 컴포넌트들이 포함되어 있습니다.

 

저는 컴포넌트들의 속성을 디자인상 조금씩 바꾸었는데, 기능상으로는 역할을 하지 않으므로 컴포넌트들의 속성은 바꾸지 않아도 됩니다.

 

다만 유의해야 할 점은

1. Non-visible components를 빼먹지 말고 포함시키기 

2. 컴포넌트 이름이 Hor~로 시작하는 것은 HorizontalArrangement 컴포넌트이고, HorS~로 시작하는 것은 HorizontalScroolArrangement 컴포넌트입니다. Ver~로 시작하는 것과 Vers~로 시작하는 것도 마찬가지입니다.

→ ScroolArrangement를 사용한 이유는 컴포넌트 이름에서도 알 수 있듯 스크롤을 가능하도록 하기 위함입니다.

 

 

    블록 코딩

전체 블록 코딩 화면입니다.

 

전체 블록 코딩

 

한 눈에 보기에 복잡해 보일 수도 있지만, 소스 파일을 보면 대부분 반복되는 내용입니다.

 


이제 블록별로 내용을 설명드리도록 하겠습니다.

 

먼저 앱이 처음 시작되었을 때, 그리고 새로고침 이미지를 클릭했을 때 실행되는 블록입니다.

 

초기화 블록

 

① 앱이 처음 실행되었을 때, initSetting 프로시저를 호출합니다.

 

② 새로고침 이미지를 클릭했을 때, LocationSensor1을 사용가능하게 설정합니다.

 

③ initSetting 프로시저를 호출합니다.

 


initSetting 프로시저 블록입니다.

 

initSetting 프로시저

 

① 화면의 모든 컴포넌트를 둘러싸고 있는 Ver_Wrap 컴포넌트를 보이지 않게 합니다.

→ 위치정보를 얻고, API와 통신할 때 시간이 걸리기 때문에 이 때 데이터 처리 중 화면(Notifier1 컴포넌트)을 보여주고 앱의 본 화면은 보이지 않게 합니다. 

 

② 만약 리스트 LocationSensor1.AvailableProviders에 network가 포함되어 있다면,

→ AvailableProviders는 위치정보를 제공할 수 있는 기능이라고 생각하면 됩니다. 보통 network 또는 gps가 있습니다.

 

③ LocationsSensor1.ProviderName을 network로 설정합니다.

→ 위치정보를 제공할 수 있는 다른 기능이 있더라도 network를 통해 위치정보를 받겠다는 의미입니다.

 

④ LocationSensor1의 위치 제공 기능을 잠구어 다른 기능을 통해서는 위치정보 제공을 받지 않겠다는 것입니다.

→ gps를 우선순위로 하든, network를 우선순위로 하든 개발자 마음입니다. 더 확실하게 위치정보를 제공해 줄 수 있다고 생각되는 것으로 선택하세요.

 

⑤ 위치정보를 가져오는 동안 Notifier1을 통해 진행 상태라고 표시해줍니다.

 

⑥ 리스트 LocationSensor1.AvailableProvider에 network가 없고 gps가 있다면,

 

⑦~⑨: ③~⑤와 동일

 

⑩ 만약 위치정보를 제공할 수 있는 network 기능과 gps기능이 없다면 위치정보를 가져올 수 없으므로 Notifier1을 통해 선택대화상자를 띄워 "확인"을 선택할 수 있도록 유도합니다.

 

선택 대화상자에서 선택 후 실행되는 블록

 

⑪ ⑩에서 "확인" 버튼을 누른 후 실행되며, 위치정보를 받아올 수 없기 때문에 그냥 앱을 종료시킵니다.

→ 실제로 다른 사람들에게 배포할 목적으로 앱을 만든다면, 다른 안내문구를 보여주는 게 좋겠습니다.

 

 


위치정보가 변경되었을 때 실행되는 블록입니다.

 

위치정보가 변경되었을 때 실행되는 블록

 

②~④는 사용자의 현재 위치를 표시하기 위한 것으로 자세한 사항은 카카오 로컬 API 문서 중 "좌표로 행정구역정보 받기" 부분을 함께 참고하도록 하세요.

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 

 

 

 

 

 

 

 

① 위치정보가 변경되었을 때

 

② Web_Address컴포넌트에 RequestHeaders를 입력합니다.

curl -v -X GET "https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=127.1086228&y=37.4012191" \
  -H "Authorization: KakaoAK {REST_API_KEY}"

→ 위의 카카오 API 문서에서 -H에 해당하는 부분입니다.

→ 빨간색 네모친 부분에 여러분의 API KEY를 넣어야 한다는 것을 잊지마세요~

 

③ Web_Address 컴포넌트에 카카오 로컬 API의 url주소와 필요한 정보(parameters)를 입력합니다.

→ 위의 카카오 API 문서에서 GET 뒤에 해당하는 부분입니다.

 

④ Web_Address 컴포넌트를 통해 ③의 URL 주소(카카오 API 서버)에 GET 방식을 통해 정보를 요청합니다.

 

⑤ Web_Weather 컴포넌트에 OpenWeatherMap API의 url주소와 필요한 정보(parameters)를 입력합니다.

→ OpenWeatherMap의 많은 API 중 One Call API를 사용했습니다. 자세한 사항은 다음 문서를 참고하세요.

 

 

One Call API: weather data for any geographical coordinate - OpenWeatherMap

To learn about how get access to historical weather data for the previous 5 days, please use this section of the documentation. How to make an API call https://api.openweathermap.org/data/2.5/onecall/timemachine?lat={lat}&lon={lon}&dt={time}&appid={API key

openweathermap.org

 

- https~: API 주소입니다.

- lat=: 위도를 나타냅니다.

- long=: 경도를 나타냅니다.

- units=: 온도 단위를 설정합니다. (imperial: 화씨, metric: 섭씨, standard: 켈빈)

- exclude=: API로부터 받는 정보 중 불필요한 요소를 받지 않도록 합니다.

이 날씨앱은 분 단위(minutes), 경보(alerts)까지는 정보를 받지 않도록 했습니다.

- lang=: 언어를 설정합니다. 이 앱에서는 kr(한국어)로 설정했습니다.

- appId=: API KEY를 입력합니다. openweathermap 사이트에서 회원가입하면 API KEY를 받을 수 있습니다.

 

⑥ Web_Weather 컴포넌트를 통해 ⑤의 URL 주소(OpenWeatherMap API 서버)에 GET 방식을 통해 정보를 요청합니다.

 

⑦ LocationSensor1을 사용불가능하게 설정합니다.

→ 위치정보가 변경되었을 때마다 실행되게 하면 계속해서 이벤트가 발생할 것이므로 한 번만 받고난 뒤 사용을 불가능하게 한 것입니다.

 

 


다음은 위에서 Web_Address.GET 요청을 통해 카카오 로컬 API 서버에서 정보를 받게 되었을 때 실행되는 블록입니다.

 

카카오 로컬 API로 부터 정보를 받았을 때 실행되는 블록

 

① Web_Address 컴포넌트가 카카오 로컬 API 서버로부터 정보를 받았을 때

 

② 변수 getAddress에 Web_Address 컴포넌트가 받은 JSON 데이터 형식으로 된 정보(responseContent)를 디코딩하여 앱인벤터의 Dictionary형태로 저장합니다.

 

③~④: lbl_Address의 텍스트를 변수 getAddress에 저장되어 있는 특정 항목을 골라내어 표시하도록 합니다.

처음과 중간의 공백은 띄어쓰기를 위한 것입니다.

→ get value at key path 블록을 이해하기 위해서는 이 포스팅 맨 위에 링크되어 있는 API 관련 예전 포스팅을 참고하세요.

→ API 관련 포스팅에 올려두었던 Postman과 JSON Viewer Pro를 통해 카카오 로컬 API 서버로부터 받은 데이터는 다음과 같습니다.

 

JSON Viewer PRO로 본 API 서버로부터 받은 데이터

 

→ 본 예제 앱에서는 두 번째, 세 번째 수준의 주소를 사용자에게 보이도록 하였습니다.

→ get value at key path의 리스트를 구성할 때 숫자를 사용해야 할 경우, JSON Viewer PRO로 얻게 된 숫자에 1을 더해 주어야 합니다.

 

 


다음은 Web_Weather 컴포넌트가 LocationSensor1(위치정보)이 변경되었을 때, OpenWeatherMap API로 정보를 요청하고 그 결과 데이터를 받았을 때 실행되는 블록입니다.

 

Web_Weather 컴포넌트가 날씨 API로부터 정보를 받았을 때 실행되는 블록

 

① Web_Weather 컴포넌트가 날씨 정보 API로부터 데이터를 받았을 때

 

② 변수 getWeatherData에 날씨 정보 API로 부터 받은 JSON 형식의 데이터(responseContent)를 앱인벤터 Dictionary 형태로 저장합니다.

 

③ weather_Today 프로시저를 호출합니다.

 

④ weather_Next 프로시저를 호출합니다.

 

 


다음은 weather_Today와 weather_Next 프로시저를 이해하기 위해 날씨정보 API(OpenWeatherMap) 중 One Call API로부터 받은 데이터를 살펴보겠습니다. 예제 앱에서 사용하는 키 부분만 설명드립니다.

 

먼저 하위 구조를 접어 큰 구조만 보면 다음과 같습니다.

 

큰 트리구조


current의 구조를 펼치면 다음과 같습니다.

 

current 수준의 트리구조

 

- dt는 시간을 나타내며 Unix, UTC 방식으로 되어 있습니다.

유닉스 시간은 1970년 1월 1일 00:00:00 협정 세계시(UTC) 부터의 경과 시간을 초로 환산하여 정수로 나타낸 것입니다.

- temp는 온도를 나타냅니다.

- icon은 날씨 데이터에 맞는 아이콘입니다.

 


다음은 hourly 수준의 트리구조입니다.

 

hourly 수준의 트리구조

 

- hourly[0]: 시간별 날씨 데이터는 위에서 언급했듯 지금부터 향후 48시간까지의 데이터를 제공받습니다.

그래서 [0~47]까지의 경로가 존재합니다.

예제 앱에서는 현재 날씨, 3시간 이후의 날씨, 6시간 이후의 날씨를 제공할 것이므로 0, 3, 6을 사용합니다.

하지만 앱인벤터에서는 리스트 형식의 데이터는 1부터 시작하므로 각 숫자에 1을 더해 1, 4, 7을 사용하게 됩니다.

 


daily 수준의 트리구조도 사용하게 되는데 반복되는 내용이고 포스팅이 너무 길어지는 것 같아 생략하도록 하겠습니다.

다만 hourly 수준처럼 [숫자]를 사용하게 되는데, 여기에는 [0~7]까지가 있습니다.

0은 오늘 날씨이고, 나머지는 향후 날짜의 날씨입니다.

 

오늘 날씨는 current 수준과, hourly 수준에서 가져오기 때문에,

daily 수준에서는 [1~7]을 사용하게 됩니다.

하지만 앱인벤터에서는 위에서도 설명드렸듯 1을 더해 [2~8]을 사용하게 됩니다.

 


다음은 weather_Today 프로시저에 대한 블록입니다.

블록 덩어리가 너무 길고 반복되는 것이 많아 일부분만 설명드리겠습니다.

 

Clock1.FormatDate

 

→ Clock1.FormatDate는 주어진 instant를 pattern에 설정한 방식으로 표시하도록 합니다.

pattern에 대해서는 다음 SimpleDateFormat 문서를 참고하세요.

 

 

 

 

 

 

 

 

 

 

 

SimpleDateFormat  |  Android Developers

 

developer.android.com

 

→ Clock1.MakeInstantFromMillis는 위에서 설명드렸던 유닉스 시간을 사용해 시간 instant로 만들어줍니다.

→ 뒤에 1,000을 더해주는 이유는 유닉스 시간은 초 단위까지인데 앱인벤터 블록이 MakeInstantFromMills에서 보듯이 밀리세컨드(1,000 = 1초) 단위이기 때문입니다.

 


다음 블록은 One Call API에서 아이콘을 가져오는 블록입니다.

icon 경로 지정

OpenWeatherMap에서 icon을 가져오는 방법에 대한 다음 문서를 참고하세요.

 

 

Weather Conditions - OpenWeatherMap

Weather Conditions Home Weather Conditions

openweathermap.org

 


 

다음은 시간대별로 보여지는 크기를 설정하는 블록입니다.

 

시간대별 크기 설정

 

→ 현재 너비(WidthPercent)에 45 pixel을 더해 준 이유는 시간대별로 간격을 두기 위해서입니다.

 

 


다음은 weather_Today_Data 프로시저 블록입니다.

 

weather_Today_Data 프로시저

 

→ weather_Today_Data 프로시저에는 orderNum이라는 Parameter(앱인벤터에서는 item)가 있습니다.

프로시저에서 Parameter에서는 다른 블록은 모두 같지만 이 부분만 달라지는 경우 사용합니다.

 

→ 오늘 날씨는 현재(current 구조)를 제외하고 3시간 후, 6시간 후의 날씨 정보를 제공하므로, 위의 hourly 트리구조에서 보았듯 orderNum에 들어갈 숫자는 4와 7입니다. 

※ weather_Today 프로시저 안에서 사용합니다.

 


weather_Next 프로시저와 weather_Next_Data 프로시저 부분도 반복되는 경우라 생략하도록 하겠습니다.

 

의문사항이 있으시면 댓글로 남겨주세요...

 

댓글