2026/03/12

오늘의 이야기

이번 여행에는 차편(자체, 렌터카)을 준비하지 않았습니다. 혼자 하는 여행이기도 했지만, 아무 준비도 없이 떠난 여행이었기 때문에요.


울릉군청 홈페이지


울릉군청 홍보대사(?)도 아니면서 울릉군청 홈페이지 링크를 달아 놓은 이유는 딱 하나... 정보가 필요해서 입니다.
1. 시실운행정보
2. 버스노선정보
이 2가지의 정보는 울릉군청을 통해서 확인해 보셔야 합니다. 특히 뚜벅이 겨울 여행객이라면...

https://www.ulleung.go.kr/ko/main.do







울릉군


아름다운 신비의 섬 울릉군


www.ulleung.go.kr






시설 운행정보


울릉도에서 만날 수 있는 이런저런 탈거리, 그렇다고 액티비티는 아니고요. 갈 수 있는 곳 (주변의 섬 등등)에 대해서 확인해 볼 수 있습니다. 겨울철이라 풍랑이 불 기 때문에 첫날 못 갔던 관음도도 셋째 날 가 보았고요. 주변에 있는 관망대 등등 방문 시 참고가 될 정보가 있었습니다.


버스 운행정보


울릉도에서 운영되는 버스는 조금 특이합니다. 크게 섬 일주를 하는 노선이 4개, 그리고 주변으로 이동하는 지선이 3개 있었습니다. 배차시간은 2시간 간격이기는 하나, 버스 노선이 2개씩 겹쳐 있고 그 노선의 배차간격이 2시간 이기 때문에 실상은 1시간처럼 보입니다. 그리고 종점이라는 게 일주노선이라 한 바퀴 돌고 나면 제자리에 온다는 특성이 있기 때문에 한쪽 방향으로만 잘 돌면 버스를 타고도 여행을 잘해 볼 수 있을 것 같았습니다.

첫날은 잘 모르고 다녔는 데, 하루 지나서 눈치를 챈 것은 노선표 보는 방법입니다. 군청 홈페이지나, 버스 정류소에 붙어 있는 시간표를 보면 특정 위치에서 버스가 출발하는 시간이 적혀 있습니다. 그럼 지도에서 내가 있는 곳 위치를 보고 그 시간에 지나가는 버스를 찾으면 됩니다. 물론 섬을 일주하는 버스 이기 때문에 방향은 한쪽으로만 다녀야 혼돈이 생기지 않습니다. 예을 들어 1번, 11번 버스를 타겠다고 하면 그날은 계속 같은 버스만 타는 겁니다. 1번, 11번을 타고 이동하다, 2번 22번을 타게 되면 왔던 자리로 되돌아가는 일이 발생됩니다.

아.. 그리고 울릉도 버스는 탈 때 어디서 내릴 건지를 말씀드려야 합니다. 행정구역을 벗어 나는 경우 버스 요금이 조금 다르게 책정이 되는 것 같더군요. 그때마다 기사님이 가격을 입력해 주시면 버스 카드로 결제를 할 수 있었습니다.

사동항 버스 정류소에서


그리고 지선으로 운영되는 버스를 타면 나리분지와 봉래 폭포를 방문하는 것도 그렇게 힘들지 않고 갈 수 있을 것 같았습니다.


렌터카


렌트가 회사는 검색을 통해서 여럿 있는 것으로 확인을 했습니다. 후기를 읽어 보면 그다지 비추인 경우도 있고 해서 렌터카는 고민을 하지 않았습니다. 섬 전체 둘레가 61Km 안팎이기 때문에 렌터카의 필요성은 글쎼요 입니다. 섬 전체의 도로들이 산 중턱을 다니는 노선으로 되어 있고, 편도 1차로 이고, 겨울철이라 그랬는지는 모르겠지만, 공사 구간이 많습니다. 베테랑 운전사가 아니라면 권장하고 싶지 않습니다.


택시여행


첫날 배에서 내려 숙소로 이동할 때 버스 시간을 몰라 지나는 택시를 잡아타고 사동항에서 숙소가 있는 저동항까지 이동했습니다. 가방이 무겁기도 했고 해서... 기사님이 택시 여행을 권하시던데요. 제주도에서는 1일 여행 단위로 했던 기억이 있어서 하루 비용을 말씀드렸더니, 12만 원에 3시간, 18만 원에 5시간 이렇게 말씀을 하시더라고요. 물론 겨울철 비수기 요금 기준인 듯했습니다. 버스 이동으로 비치어 보고 도로 사정을 가만해 보면 3시간에 그렇게 다닐 수 있는 곳이 있을 까는 의문이 듭니다. 자세한 설명은 기본 일 듯 하기는 합니다만... (성수기에 가면 20만원도 넘게 받으신다고 하더군요)





오늘의 이야기

여행에서의 남는 기억은 주변 관광지와 먹거리 일 듯합니다.  이번 여행에서는 혼자 떠난 여행이기에 먹는 건 제약(?)이 있었습니다.  울릉도에서의 식당은 대부분은 2인 이상의 메뉴를 제공하고 있습니다. 그래서 혼자 가는 여행에서는 먹는 게 나름 원활하지는 못합니다. 


 


그래도 갔던 식당들을 하나씩 둘러 보도록 하겠습니다.


 


1일 차 아침


여행사를 동반한 여행이 아녔기에 먹는 것도 자유롭게(?) 할 수 있습니다.  다만 메뉴 선택에 제약(?)이 따릅니다.


대부분 2인 이상의 메뉴로  준비를 하는 경우가 많더라고요.


 


1일차 아침



1일 차 아침은 배가 아침 7시 무렵에 울릉도 사동항에 내렸습니다. 뚜벅이인 경우 이동이 수월하지 않기 때문에 사동항 근처에서 아침을 해결 하기로 했습니다.  이날의 아침은 사동항에 있는 특산물 체험유통 타운 2층에 있는 미당 이라는 식당에서 먹었습니다.  1인 11,000원 기준으로 부페 처럼 운영을 하시기 때문에 먹을 만큼 먹을 수 있습니다.  사진은 없지만, 라면도 하나 먹었습니다. 그리고 4층에 있는 카페에 갈 때 영수증을 가지고 가면 10% 할인해 주십니다.


 


https://goo.gl/maps/4sxpjHedTc3NaeMcA



 


울릉항(사동항) 여객선터미널 · 경상북도 울릉군 울릉읍 사동리 946


★★★★☆ · 페리/국내여객선


www.google.com




 


1일 차 점심


첫날은 길이 서툴러 무작정 걷기도 했고, 지나는 버스를 타면서 구글 지도에서 태하 항목 모노레일을 타 보고자 하고 갔었던 태하리에서 점심을 먹었습니다.  늦은 점심 이기도 했고, 바닷가에서는 주는 해물짬뽕은 어떨까 하는 생각에 먹어 보았습니다.  9000원 치고는 그다지(?) 비추입니다.  시골 중국집의 가성비는 그저 그런 것 같습니다.


1일차 점심



 


https://goo.gl/maps/UH8AAqaxSLCY6fyx6



 


광장식당 · 경상북도 울릉군 서면 태하리 748-8


★★★★☆ · 중국 음식점


www.google.com




태하에 있는 모노레일 그것이 겨울에 공사를 한다고 합니다. 해서 2023년 4월까지는 탈 수 없습니다.  대신 열심히 걸어서 배가 고프게 하고 먹었던 점심으로 기억이 됩니다.


 


 


1일 차 저녁


저동항 근처에 있는 식당에서 먹은 따개비 비빔밥입니다. 이 메뉴 또한 2인 기준인 듯 하나, 혼자 왔다는 말을 듣으신 사장님께서 싫은 얼굴이지만 주심 맛난 저녁이었습니다.  가격이 17000원 입니다. 그래도 나름 울릉도에서만 먹어 볼 수 있는 맛나 저녁 이였습니다.


 


1일차 저녁



https://goo.gl/maps/pXR1V4HZLHRwHyaN9



 


해돋이식당 · 경상북도 울릉군 울릉읍 울릉순환로 212-6


★★★★★ · 음식점


www.google.com




 


 


2일 차 아침


이튿날 아침은 간단하게 먹을 요량으로 찾았던 카페입니다. 내부는 작은 소규모 이기는 하지만, 나름 야채가 많이 들어 있는 토스트와 아메리카노입니다. 아직 9시 무렵이기는 했지만, 이날은 행군(?)을 생각하지 않고 먹었던 아침입니다.


커피와 토스트 해서 12,500원을 드렸습니다.


 


2일차 아침



https://goo.gl/maps/4Kh6FfJg4WwHhwrX9



 


791토스트 · 대한민국 울릉군 저동 울릉읍


★★★★☆ · 샌드위치 가게


www.google.com




 


2일 차 점심


나리분지에서 만난 점심 식사입니다. 야영장 식당이라고 되어 있더라고요. 주변에 캠핑장이 있는지는 모르겠습니다.  이곳에서 먹은 점심은 건강해질 것 같은 느낌을 주는 맛난 비빔밥이었습니다.  가격도 13,000원으로 나쁘지 않습니다.  혼자 왔다고 했더니, 혼자 다니는 여행이 부럽다 하시는 사장님이 건넌 귤 2개도 후식으로 맛나게 먹었습니다.


 


이 식사를 하고 힘내서 성인봉 등정을 했습니다.  밥 먹고 가지 않았다면, 아마 힘들어서 돌아오지 않았을까 하는 생각이 듭니다.


2일차 점심



 


https://goo.gl/maps/BxWGjE8i5rXUnCLYA



 


야영장식당 · 경상북도 울릉군 북면 나리 91-2


★★★★☆ · 한식당


www.google.com




 


 


2일 차 저녁


고된(?) 산행 끝에 돌아온 숙소 근처에서 먹었던 저녁입니다.  이 식당 역시 혼자 먹을 수 있는 건 이런 국밥뿐? 그래도 가격은 10,000원으로 먹었던 밥 중에는 제일 저렴했던 것 같습니다. 울릉도에서의 식당 등은 대부분 다 오래된 가게이기 때문에 외관을 보고 식당을 정하면 정하기 힘들어집니다. 그냥 아무 곳이나 선택해 가는 것이 좋습니다.


2일차 저녁



https://goo.gl/maps/UYoK6NUeTVwBywa29



 


부산식당 · 대한민국 울릉군 저동 울릉읍


★★★★★ · 음식점


www.google.com




혼자 먹는 밥이기는 해도 그렇게 나쁜 기억은 없습니다.  다만 조금 시끌거렸다는 것 말고는...


 


 


3일 차 아침.


강릉 식당 이었는 데, 지도에서는 찾을 수 없습니다.  지도에서 주소 정보만 찾을 수 있네요. 식당을 여신지가 얼마 되지 않았거나, 식당 이름이 바뀌었는 데 오래되지 않아서 일 것 같습니다. 아무튼... 아침 곰탕 (가격 15,000원에 비해서는?)은 넉넉했던 거 같습니다. 


 


도착 첫날 택시 기사님이 말씀해 주신 것으로 유추되는 식당이기는 한 데,  추천을 받아 갈 만큼은 아닌 것 같은 생각이 들었습니다. 


 


3일차 아침



https://naver.me/5HEk6YTW



 


네이버 지도 - 주소


경상북도 울릉군 울릉읍 도동리 307-24


map.naver.com




 


 


3일 차 점심


울릉도에서 먹는 왕갈비탕은 어땠을 까요?  맛나게 잘 먹었습니다. 점심시간을 지난 시간 이기는 했는 데, 혼자 다니는 여행객이 그렇게 보였는지 아무튼 맛난 갈비탕을 먹고 왔습니다. 양이 무지하게 많거나 하지는 않았습니다.  가격은 15,000원이었습니다.


3일차 점심



https://goo.gl/maps/epkD1y5iRAKBLsTn9



 


대풍식당 · 경상북도 울릉군 북면 527-45


경상북도 울릉군 북면 527-45


www.google.com




 


 


3일 차 저녁


울릉도에 왔으니 회를 한 접시 먹으라는 여보님의 말대로 가고 싶기는 했으나, 혼자 먹기에는 부담스러울 것 같아 회 대신 초밥집을 가 보았습니다.  저동항 근처에 있고 숙소와도 가까운 곳에 위치해서  가 보았는 데, 깔끔하게 주시는 것이 일상생활을 하던 도심에서 먹는 것과 별반 다르지 않았습니다.  식당 내부도 깔끔했고요. 이 식당도 외부에서 볼 때와 다른 인상을 주기 때문에 들어가 보시는 것을 추천드립니다.  다른 메뉴도 있기는 했는 데, 저는 23,000원을 내고 스페셜이라고 먹었던 것 같습니다.


3일차 저녁



https://goo.gl/maps/PgYaG5jNXx4uNTxb9



 


독도초밥 · 경상북도 울릉군 울릉순환로 214-1 KR


★★★★★ · 일본 음식점


www.google.com




 


 


3일 차 야참


핫도그를 간판을 보고 갔던 카페입니다. '뉴욕 뉴욕'이라는 제목의 카페인데,  구글맵에서 찾기는 했는 데 카페가 아닌 펍(?)으로 조회가 됩니다. 핫도그 메뉴가 많았는 데, 아~ 그러고 보니 치킨 등등도 메뉴에서 본 것 같은 기억이 납니다. 아무튼 한 끼 식사가 될 수 도 있을 듯 한 양인데, 저녁으로 먹었던 초밥이 그렇게 배을 채우지는 못 했나 봅니다. 아메리카노와 불고기 핫도그까지 10,800원으로 먹었습니다. 


3일차 저녁에 커피와 핫도그



https://goo.gl/maps/52rNcHtLzgvYyL2T9



 


뉴욕뉴욕 · 경상북도 울릉군 울릉읍 봉래길 5-17


★☆☆☆☆ · 술집


www.google.com




 


돌아오는 날 아침


돌아오는 날 아침은 첫날 먹었던 미당이라는 식당에서 같은 메뉴를 먹었습니다. 그렇다고 해서 그 메뉴가 매우 흡족해서는 아니고, 전날 커피를 늦게 마신 탓에 잠을 제대로 잘 수 없어서 배를 놓칠까 싶어 아침부터 부랴 부랴 이동했기 때문입니다.


 


돌아오는 날 점심 겸 저녁


배에 타자 마자는 피곤이 몰려와서 잠을 자는 통에 점심은 건너뛰었습니다. 그리고 16시 30분부터 운영하는 저녁 식사를 위해서 배안에서 운영하는 식당엘 갔었습니다. 가격은 20,000원이라는 하나, 미당에서 먹었던 것보다 조금 못한 수준이었습니다.  배안에서는 선택의 여지가 없기 때문에 그냥 먹어야 했습니다.  다만, 좋았던 것은 돌아오는 배편이 울릉도에서 서쪽을 을 향해 옵니다. (물론 정서 쪽은 아니지만,)  배가 포항에 도착하는 시간이 저녁 시간이기 때문에 배 안 8층에 가면  있는 카페에서 일몰을 볼 수 있다는 것입니다. 다만, 이날은 날씨가 흐린 탓에 제대로 보지는 못 했습니다.


돌아오는 배에서의 점심



 


배안 8층 카페에서 아메리카노



 


배안에서 보는 일몰



 


이상으로 울릉도에서 먹었던 혼밥(?)에 대한 리뷰였습니다.


 





오늘의 이야기



#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase

🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 "혹시나~" 하면서 봤거든 ㅋㅋ

근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨

그것도 구글 Gemini로다가!

그래서 앱 하나 만들었지
👉 "로또 예상번호 by Gemini" 🎱

AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨

재미로 해도 좋고…
혹시 모르는 거잖아? 😏


https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127




오늘의 이야기

입도 (入島')


겨울에 울릉도를 가는 건 어떤 의미 인지 모릅니다. 이번에 가게 된 것은 시간이 허락한 듯하여 추운 겨울에 길을 나섰습니다.

울릉도에 데려다 준 여객선


가는 방법은 강릉, 묵호, 포항 등등 여러곳에서 출발하는 배편을 이용하는 것으로 가능하다고 되어 있습니다. 2025년쯤에는 비행기를 타고 가게 될지도 모르지만, 2022년 현재는 배편을 이용하는 것이 유일한 방법입니다.

그중에 제일 큰 배편을 찾아 떠나게 되었습니다. 출발은 23시 30분 포항 영일만 항 (배편은 주기적인 검사를 위해 휴항을 하는 경우가 있으므로 출발 전 사전 확인이 필요합니다.)

https://island.haewoon.co.kr/







가보고 싶은 섬(여객선 예약예매)



island.haewoon.co.kr




예약 사이트에서 또는 앱에서 가고 싶은 섬을 선택하고 배편을 예매하면 됩니다. 가는 배편에 특성에 따라서 달라지는 것은 일정을 잡는 방법이 달라집니다. 이 배편은 아침 7시 무렵 울릉도 사동항에 도착하기 때문에 첫날부터 열심히 여행을 해야 합니다. 돌아오는 배편이 12시 30분에 울릉도 사동항에서 출발하기 때문에 돌아오는 날은 아무 일정도 하지 못할 수 있습니다.


준비


가는 방법 : 배편,
누구랑 : 혼자서
현지 교통편 : 걸어서 또는 대중교통으로
현지 숙소 : 야놀자에서 예약
현지 교통 : 야심 차게 도보 여행을 준비

간단한 준비를 했습니다. 아무것도 알아보지 않은 채 말입니다. 이 것이 불러올 파장은 뭐...

영일만항 여객 휴게소(?) 2022.12월 초 기준


포항 영일만항구는 2022년 12월 기준으로는 계속해서 공사를 하고 있는 항만입니다. 해서 원활하게 이용할 수 있는 교통편이 없습니다.

자가용을 이용하거나, 주차 공간은 많아 보입니다. 또는 크루즈 선사에서 운영하는 셔틀을 이용하는 방법이 있습니다. 셔틀은 출발/도착 배 시간에 맞게 포항 시내 또는 포항역과의 연계가 되어 있으니 사전에 알아보시면 쉽게 이동할 수 있습니다.

코레일에서 운영하는 연계 상품을 이용하는 것도 좋은 방법 일 듯 합니다.

https://www.letskorail.com/ebizprd/prd_rent/railship/ulleungdo/w_htm15840.do







레츠코레일 LetsKorail


한국철도공사, 레츠코레일, 승차권 예매, 기차여행상품, 운행정보 안내


www.letskorail.com




울릉도의 첫 느낌


드디어 도착했습니다.

참 11월 말 부터 다음해 3월까지는
독도가는 배편은 없습니다.  알아보고 가세요.





오늘의 이야기


#스하리1000명프로젝트

스치니들!
내가 만든 이 앱은, 내 폰에 오는 알림 중에서 중요한 키워드가 있는 경우
등록해둔 친구에게 자동으로 전달해주는 앱이야 📲

예를 들어, 카드 결제 알림을 와이프나 자녀에게 보내주거나
이번 달 지출을 달력처럼 확인할 수도 있어!

앱을 함께 쓰려면 친구도 설치 & 로그인해줘야 해.
그래야 친구 목록에서 서로 선택할 수 있으니까~
서로 써보고 불편한 점 있으면 알려줘 🙏

👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao





오늘의 이야기

Geofencing (지오펜싱)


여러 번 지오펜싱에 대한 포스팅을 해 보았습니다. 이번에도 다시 이 포스팅을 하게 된 것은 지오펜싱에 대한 부족했던 이해를 추가로 적어 두고자 합니다. 


 


지오펜싱이 활용된 앱 샘플



적어 두고자 하는 내용은 지오펜싱을 하기 위해서 설정을 하기는 했어도 지오펜싱이 동작하지 않는 경우 때문입니다.


 


지오펜싱이 트리거 되지 않는다.


아래 이슈의 내용은 지오펜싱이 트리거 되지 않을 현상에 대한 이야기가 나와 있습니다.  앱을 구현하는 동안 GoogleMap이 표출된 상태에서는 지오펜싱 트리거가 잘 동작 합니다.  


 


https://issuetracker.google.com/issues/218335535



 


Google Issue Tracker


 


issuetracker.google.com




그러나 GoogleMap 이 살아 있지 못하는 경우 트리거가 되지 않는 현상이 발생하게 됩니다. 그래서 구글링을 해서 얻은 결론은 위 링크의 글에서 참고했습니다. 


 


LocationManager의 활용


아래 코드와 같이 locationManager을 이용해서 현재 위치를 받아오는 기능을 활성화하는 것입니다.  이렇게 하게 되면 사용자가 GoogleMap 을 열어 놓고 있지 않게 되어도 geofencing 이 trigger 되어 언제든 지 휴대장치의 위치 정보를 수집할 수 있게 됩니다.  


	val criteria = Criteria().apply {
accuracy = Criteria.ACCURACY_FINE
isAltitudeRequired = false
isBearingRequired = false
isSpeedRequired = false
isCostAllowed = true
powerRequirement = Criteria.POWER_LOW
}

lateinit var locationManager : LocationManager
var locationProvider : String? = null

val locationListener = object : LocationListener {
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
super.onStatusChanged(provider, status, extras)
// provider의 상태가 변경될때마다 호출
// deprecated
}

override fun onLocationChanged(location: Location) {
// 위치 정보 전달 목적으로 호출(자동으로 호출)

val longitude = location.longitude
val latitude = location.latitude

Log.d("Location", "Latitude : $latitude, Longitude : $longitude")
}

override fun onProviderEnabled(provider: String) {
super.onProviderEnabled(provider)
// provider가 사용 가능한 생태가 되는 순간 호출
}

override fun onProviderDisabled(provider: String) {
super.onProviderDisabled(provider)
// provider가 사용 불가능 상황이 되는 순간 호출
}
}

...

locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
locationProvider = locationManager.getBestProvider(criteria, true)

val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)

if(location != null) {
val accuracy = location.accuracy
val latitude = location.latitude
val longitude = location.longitude
}

// 매개변수로 위치 정보 제공자, LocationListener 호출 주기, 변경 위치 거리의 정보, LocationListener
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000
, 100.0f, locationListener)

 


이제 위치 정보가 변하는 것을 이용해서 원하는 기능을 구현해 볼 수 있을 것 같습니다.  다음부터는 이런 기능 오류에 대한 대처는 잘 될 수 있을 것으로 생각됩니다.


 


 


 


 





오늘의 이야기

GoogleMap 그려보기


오늘은 jetppack compose 환경에서 구글 지도를 활용하면서 조심해야 할 것 하나를 정리해 두고자 합니다.  이전 포스팅에서 구글 지도를 jetpack compose에 올리는 부분은 기술해 두었으니 참고하시면 될 것 같습니다


https://billcorea.tistory.com/243



 


안드로이드 앱 만들기 : GoogleMap (feat Jetpack Compose)


앱을 만들다 보면 지도가 들어가는 앱을 만들게 되는 경우가 있다. GoogleMap API 등을 이용해서 앱을 만들게 되는 데, 이번에는 Jetpack Compose 기반의 GoogleMap 을 구현해 볼까 한다. 아직은 예전 java 코


billcorea.tistory.com




 


오늘의 발견 이슈


material diaglog box 등을 활용해 보기 위해서 themes.xml 을 구성해 보았던 기억이 있습니다.


 


    <style name="Theme.bespeak1003" parent="Theme.AppCompat.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/softBlue</item>
<!-- Customize your theme here. -->
<item name="colorAccent">@color/softBlue_30</item>
<item name="android:textColor">@color/softBlue</item>
<item name="android:fontFamily">@font/nanumgothic_regular</item>
<item name="android:textSize">20sp</item>
<item name="android:windowBackground">@color/lime200</item>
<item name="android:colorBackground">@color/softGreen</item>
<!-- <item name="android:background">@color/lime200</item>-->
<item name="background">@color/lime200</item>
</style>

이 부분이 앱의 기본 theme 을 기술한 부분인데요. jetpack compose을 사용하게 되는 경우에는 theme.kt 등에서 따로 compose에서 사용할 theme을 기술하게 됩니다. 그런데, 위에 기술된 android:background 항목은 지워져 있는 데, 그 부분을 기술했더니만... 


 


GoogleMap의 배경색이 채워지고 지도가 보이지 않는 그런 현상을 발견하게 되었습니다.  그래서 결국은 저 부분을 지우고 실행하게 되었습니다. 


 


지우기 전 모습




 


그냥 배경으로나 사용해 보고자 지정했던 색으로 다 채워지고 지도가 나오지 않았습니다.


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


정상적인 실행 모습




 


 


 이제 제대로 지도가 나오고 있는 것을 확인해 볼 수 있었습니다.


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


다음부터는 이런 경우가 발생하게 되더라도 당황하지 않고 수정을 할 수 있을 듯합니다. 


 





오늘의 이야기


#스하리1000명프로젝트,
Soms is het moeilijk om met buitenlandse werknemers te praten, toch?
Ik heb een eenvoudige app gemaakt die helpt! Jij schrijft in jouw taal, en anderen zien het in hun taal.
Het vertaalt automatisch op basis van instellingen.
Superhandig voor makkelijke chats. Neem eens een kijkje als je de kans krijgt!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416




오늘의 이야기

이전 포스팅에서 SMS 또는 LMS을 읽어오는 부분에 대해서는 기술한 바 있습니다. 이여서 하는 이야기는 MMS을 확인해 보는 방법입니다. 이전 포스팅으로 MMS가 읽어져 오는 것으로 이해를 하고 있었습니다만... 실제로는 그것이 아니라는 특히 국내에서 출시된 개선된(?) 안드로이드를 사용하는 경우 그런 기능으로는 정보를 다 가지고 오지 못하는 부분이 있다는 것을 알게 되었습니다.


 


MMS 수신 이벤트 확인


국내향 안드로이드의 경우는 SMS와 달리 MMS의 경우는 수신을 했다고 해도 Event 를 감지할 수 없었습니다. 그래서 대안으로 처리한 것은 알림 수신을 이용하는 것입니다. (알림 수신에 대해서는 이전 포스팅을 참고해 주세요)


 


import android.annotation.SuppressLint
import android.app.Notification
import android.content.ContentResolver
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import androidx.annotation.RequiresApi
.....
import java.io.BufferedReader
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.*


class MyNotificationListener : NotificationListenerService() {

val TAG = "MyNotificationListener"
val MMS_URI: Uri = Uri.parse("content://mms-sms/conversations/")
val mmsRcvNumbers = mutableListOf<MmsBean>()

override fun onNotificationRemoved(sbn: StatusBarNotification) {
super.onNotificationRemoved(sbn)
Log.e(
TAG, "onNotificationRemoved ~ " +
" packageName: " + sbn.packageName +
" id: " + sbn.id
)
}

/**
* MMS 발송자 전화 번호 알아 내기
*/
@SuppressLint("Range")
private fun getAddressNumber(id: Int): String? {
val selectionAdd = "msg_id=${id}"
val uriStr = "content://mms/${id}/addr"
val uriAddress = Uri.parse(uriStr)
val cAdd = contentResolver.query(
uriAddress, null,
selectionAdd, null, null
)
var name: String? = ""
try {
if (cAdd!!.moveToFirst()) {
do {
val number = cAdd.getString(cAdd.getColumnIndex("address"))
if (number != null) {
try {
number.replace("-", "").toLong()
name = number
} catch (nfe: NumberFormatException) {
if (name == null) {
name = number
}
}
}
} while (cAdd.moveToNext())
}
if (cAdd != null) {
cAdd.close()
}
} catch (e : Exception) {

}
return name
}

/**
* MMS 의 본문 내용 읽어 오기
*/
private fun getMMsPart(mId: String?): String {
var rValue = ""
var selectionPart: String = "mid=" + mId;
var uriPart : Uri = Uri.parse("content://mms/part");
var cur : Cursor? = contentResolver.query(uriPart, null, selectionPart, null, null);
if (cur != null) {
if (cur.moveToFirst()) {
do {
rValue = getMmsBody(cur)
} while (cur.moveToNext())
}
}
return rValue
}

/**
* MMS Body read
*/
private fun getMmsBody(partCursor: Cursor): String {
val partId = partCursor.getString(partCursor.getColumnIndexOrThrow("_id"))
val data = partCursor.getString(partCursor.getColumnIndexOrThrow("_data"))
return if (data != null) {
getMessageText(contentResolver, partId)
} else {
partCursor.getString(partCursor.getColumnIndexOrThrow("text"))
}

}

/**
* MMS body get Text
*/
private fun getMessageText(contentResolver: ContentResolver, id: String): String {
val partUri = Uri.parse("content://mms/part/$id")
val stringBuilder = StringBuilder()
val inputStream = contentResolver.openInputStream(partUri)

if (inputStream != null) {
val inputStreamReader = InputStreamReader(inputStream, "UTF-8")
val bufferedReader = BufferedReader(inputStreamReader)
var temp = bufferedReader.readLine()
while (temp != null) {
stringBuilder.append(temp)
temp = bufferedReader.readLine()
}
inputStream.close()
}

return stringBuilder.toString()
}

@SuppressLint("Range")
@RequiresApi(Build.VERSION_CODES.S)
override fun onNotificationPosted(sbn: StatusBarNotification) {
super.onNotificationPosted(sbn)

val projection = arrayOf("_id", "ct_t")
val query: Cursor? = contentResolver.query(MMS_URI, projection, null, null, null)
mmsRcvNumbers.clear()
if (query != null) {
if (query.moveToFirst()) {
do {
var mId = query.getString(0)
var fromAddr = getAddressNumber(mId.toInt())
if (!"".equals(fromAddr)) {
var mmsBean = MmsBean(mId.toInt(), fromAddr.toString())
var mesg = getMMsPart(mId)
mmsBean.mesg = mesg
// Log.e(TAG, "mesg = ${mesg}")
mmsRcvNumbers.add(mmsBean)
}
Log.e(TAG, "sms id=$mId [$fromAddr]")
} while (query.moveToNext())
}
}
if (mmsRcvNumbers.size > 0) {
mmsRcvNumbers.sortByDescending { orderItem -> orderItem.mId }
}

var sdf = SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale("ko", "KR"))
val extras = sbn.notification.extras

try {

var title = extras.getString(Notification.EXTRA_TITLE).toString()
var content = "" + extras.getCharSequence(Notification.EXTRA_TEXT)
if (extras.getCharSequence(Notification.EXTRA_SUB_TEXT) != null) {
content += " " + extras.getCharSequence(Notification.EXTRA_SUB_TEXT)
}
var number = ""
if (mmsRcvNumbers.size > 0) {
number = mmsRcvNumbers.get(0).rcvNumber
content = mmsRcvNumbers.get(0).mesg
}

Log.e(
TAG, "onNotificationPosted ~ " +
"\n packageName: " + sbn.packageName +
"\n id: " + sbn.id +
"\n postTime: " + sdf.format(sbn.postTime) +
"\n title: " + title +
"\n number: " + number +
"\n content : " + content
)




} catch (e: Exception) {
Log.e(
TAG, "error = ${e.localizedMessage}"
)
}
}

}

코드에서 보는 것과 같이 Notification Receiver을 활용해 contentResolver 을 이용 content://mms-sms/conversations의 정보를 읽어옵니다. 이 정보를 활용해서 mms의 정보를 열어 보는 방식으로 구현이 되었습니다.


 


이 부분을 조금 더 활용해 본다면, sms 수신 데이터의 정보도 읽어 올 수 있도록 구현이 될 것 같습니다. 


나중에 기회가 된다면 그 부분도 구현을 해 보도록 하겠습니다.


 


 





오늘의 이야기

초기화면



이 글은 주문이요(bespeak) 앱 사용자를 위한 사용자 설명서입니다.

이 앱의 기획의도는 매장 테이블에 있는 간편 결제 키오스크를 보고 만들기 시작 헸습니다. 스마트폰 간편 결제만 사용한다고 하면 키오스크를 만들기 위해서 따로 뭔가를 준비하거나 할 필요가 없습니다.

이 앱은 payapp.kr을 간편 결제 서비스를 연동하고 있습니다.
이 앱은 qrcode 인증을 통해서 휴대폰 간편 결제를 할 수 있도록 지원하는 앱입니다.

이 앱을 사용하기 전에 꼭 payapp.kr 에서payapp.kr에서 회원 가입 및 사용자 인증을 진행한 이후에 사용할 수 있습니다. (그렇다고 해서 아직은 payapp 와의 어떤 관계도 없습니다. 혹시 나중에 리셀러로 참여할지도 모릅니다. 현재는 payapp.kr에서 3.4% 부가세 별도의 수수료를 지불하면 웬만한 카드사는 다 가맹점으로 사용할 수 있습니다. 참 온라인 판매는 보증보험이 필요하다고 합니다. )

이 앱은 스마트폰 간편 결제만 지원하고 있습니다. 다른 결제 방식에 대해서는 추가 upgrade는 검토 후 진행 여부가 결정될 수 있습니다.

사용하지 않는 스마트 단말만 있으면 됩니다. 단, wifi 는 연결될 수 있어야 합니다. 통신을 해야 합니다.





Ver.0.3.4 개선 사항


관리자 화면 수정 사항



Ver 0.3.4 에서 부터는 페이앱 사용자 가입 이라는 링크가 추가 됩니다. 


 


해당 링크를 통해서 페이앱에 가입 하고 이 앱을 사용하시는 분들께는 간편결제 수수료가 3% (부가세 별도)로 적용 됩니다. 


 


해당 링크를 통해 페이앱에 가입 하신 경우에는 nar961450@gmail.com 을 알려 주세요.


 


간편결제 수수료를 적용해 드립니다. 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


앱 사용자 등록 하기


앱을 설치하고 나서 처음 시작할 때 나오는 화면 입니다.


최초 실행시 사용자 등록 화면



** 이 메일은 사용자 구분을 하기 위한 정보로만 사용됩니다. 나중에 관리를 위해서도 필요합니다. 등록된 이메일 주소를 활용해서 메일링을 하거나 할 생각은 없습니다.

** 비밀번호는 이앱의 사용자 등록을 위해서만 사용 됩니다. 최초 화면에서 비밀번호를 등록 하면 이후에는 수정이 불가 합니다. 이후 비밀번호를 분실한 경우에는 개발자에게 메일로 알려 주시면 변경해 드립니다.
(테스트를 위해 예시 화면과 같이 입력 하는 경우에는 변경하실 수 없습니다.)

** 페이앱 사용자 ID
payapp에 가입하게 되면 등록한 사용자 ID가 있어야 결제를 받은 것들에 대해서 대금 수령 등을 할 수 있습니다. 이 부분에 대해서는 payapp의 사용자 등록을 참고하세요.

** T.No
테이블 번호로 사용됩니다. 매장 안에 테이블이 여러 개 있는 경우 번호를 달리 해야 나중에 주문 내역 관리에 도움이 됩니다.

** 주방 데스크 여부
해당 단말을 주방에 설치하는 경우에만 체크해 주세요.
주문이 완료되면 해당 정보를 목록 형태로 조회할 수 있도록 지원됩니다.

현재 표시된 내용은 샘플이므로 그대로 저장을 해서 테스트해 보셔도 됩니다.
테스트시에 결제가 진행된 것은 15분 이후 정도에 자동 취소가 진행됩니다. (혹은 목록에서 취소 처리를 할 수 있습니다.)


요구되는 권한


이 앱에서 사용 되는 중요 권한은 아래와 같습니다. ** 위치 정보, 항상 허용까지 필요, ** 카메라 사용 권


요구되는 권한



** 위치 정보 : 위치 정보는 이앱에서 사용 되는 권한입니다. 이 권한은 이앱이 설치된 휴대장치가 지정된 위치(사업장 위치등등)을 이탈 하는 경우 해당 휴대장치의 위치정보를 관리자가 사용하는 앱에게 알림을 전달 하기 위해서만 사용 됩니다. 또한, 항상 허용을 요청하는 이유도 해당 휴대장치의 위치 정보를 지속적으로 확인하기 위해서만 사용 됩니다.

** 위치 정보( 항상 허용 포함) 중요한 개인정보에 해당 하기 때문에 이 앱에서 제시하고 있는 것 처럼 개인정보를 취급함에 있어 주의를 다하며 절대로 개인정보를 수집 하거나 부당하게 공유하지 않습니다.
https://billcorea.tistory.com/m/294



 


주문이요 앱 사용자를 위한 개인정보 처리 지침


은(는) 「개인정보 보호법」 제30조에 따라 정보주체의 개인정보를 보호하고 이와 관련한 고충을 신속하고 원활하게 처리할 수 있도록 하기 위하여 다음과 같이 개인정보 처리방침을 수립·공개


billcorea.tistory.com




** 카메라 사용 권한 요청 : 상품 등록 화면으로 들어갔을 때 관리자의 경우에는 이미지 찾기 또는 카메라 촬영을 위해서 카메라 사용 권한을 물어 보게 됩니다. 권한을 승인 하지 않는 경우 상품 등록을 진행할 수 없으므로, 반드시 카메라 사용 권한을 허가해 주어야 합니다.


관리자를 위한 화면


관리 화면



관리화면에서 주의할 부분은 다음과 같습니다.
* 이메일 . 비밀번호는 이앱에서 입력되는 자료를 조회할 사용자 계정이기 때문에 분실 되지 않도록 관리 되어야 합니다. 비밀번호를 분실한 경우는 현재까지는 개발자에게 조치를 요청해야 합니다. (이후 개선을 통해서 비밀번호 변경을 할 수 있도록 할 예정 입니다.)
* 페이앱 사용자 ID : payapp.kr 페이앱에서 사용자 등록한 계정을 사용 하여야 합니다. 변경하는 경우 거래가 되지 않을 수 있으므로 관리에 주의가 필요 합니다
* T.No : 테이블 구분하여 관리 하고자 하는 경우에 사용 됩니다. 사용자의 필요에 따라서 등록 관리할 수 있습니다.
* 장치 위치 설정을 진행하세요 를 클릭 하면 위 그림 중에 2번째 그림과 같은 화면에 나옵니다.
이 때에는 화면에서 사업장 위치를 길게 클릭 하면 해당 위치를 사업장 위치로 선택 되게 됩니다.
* 알림 버튼 : 알림 버튼을 클릭 하면 주기적(최소 15분 간격으로)적으로 앱이 설치된 휴대장치의 위치 정보를 확인하게 됩니다. (파란색이 되는 지 확인 하여야 합니다. 중지된 경우는 검정색으로 나옵니다.)
* 장치 위치 설정을 진행하세요 옆에 파란색 휴대장치 아이콘 클릭시 에는 위 그림에서 3번쨰 그림이 나옵니다. 이 화면에서는 휴대장치가 위치를 이탈한 경우 해당 위치를 표시하도록 하고 있습니다.


처음 화면


처음화면



사용자 계정 등록 후 처음 화면으로 넘어오면 이렇게 보입니다.

먼저 하단의 메뉴 구성은
** 주문
사용자가 주문을 하기 위해서 선택합니다.

** 상품
상품의 상세 조회 시 또는 관리자의 경우 상품을 등록할 때 사용합니다.

** 관리
앱을 시작한 이후 관리를 위해서 사용하거나, 주문 목록을 보고자 하는 경우에 볼 수 있습니다.

이제 상품 목록을 보기 위해서 refresh 버튼을 클릭해 봅니다.
사용자가 로그인되어 있다면 상품 목록이 보입니다.










로그인을 하기 위해서 비밀번호를 입력해야 합니다. 비밀번호는 최초 실행시 등록한 비밀번호를 기준으로 관리 되며, 추후 비밀번호 변경 기능등은 추가 지원될 예정입니다.

(테스트 계정 nana1029@billcorea.com 의 비밀번호는 1qazZAQ! 입니다)


상품 등록하기


앱에서 상품을 등록하기 위해서는 로그인 이후 상품 메뉴로 이동합니다.




상품등록을 하기 위한 화면은 위와 같이 4단계에 걸쳐 진행이 되어야 합니다.
* 먼저 화면 상단의 지문인식 버튼을 클릭합니다. (이때 pin 이 등록된 경우 pin으로도 인증이 가능합니다.) 스마트폰에 등록된 지문으로 인증이 완료되어야 다음으로 진행이 가능합니다.
** 다음은 상품 이미지 촬영을 위해서 카메라 권한을 획득하여야 합니다. 상품 이미지 안에 있는 카메라 권한 획득 버튼을 클릭하여 권한 획득을 하세요.
** 상품 이름부터 순차적으로 내용을 입력하고, 저장 버튼을 클릭하면 자료가 저장됩니다.
** 지문 인식이나 PIN 확인은 앱을 설치한 폰에 등록된 바이오 인증을 활용 합니다. (but 절대 그 비밀번호를 알아서 확인이 되는 것이 아니고 안드로이드에서 지원하는 기능으로 체크 되는 지만 활용하고 있습니다.)

이후 초기 화면에서 등록된 내용을 조회해 보고 수정이 필요한 경우 이미 왼쪽 상단의 수정 버튼을 클릭하여 다시 수정할 수 있습니다.


상품 판매하기


이제 등록된 상품을 팔아 보도록 하겠습니다. 등록된 상품의 카테고리는 일반 음식점 기준으로 되어 있습니다. 주메뉴, 사이드 메뉴, 음료/주류로 분류된 메뉴판을 볼 수 있습니다.


상품판매



상품 판매 화면의 모습입니다. 화면 상단에는 회색의 카드 모양 결제 버튼과 파란색의 다시 읽어오기 버튼이 존재합니다

** 다시 읽어오기 (파란색 버튼)을 클릭하면 화면에 메뉴들이 조회 됩니다. 메뉴는 등록하는 화면에서 보았던 것처럼 3가지 분류로 등록된 메뉴들을 조회해 볼 수 있습니다.

** 메뉴 화면의 쇼핑카드 모양을 클릭 하면 주문량이 늘고 가격이 자동 산출됩니다. 가격이 산출되면 회색 모양이 카드 버튼이 파란색으로 활성화됩니다.

** 메뉴 선택이 끝났으면 이제 파란색 카드 버튼을 클릭해서 결제를 시작해 보겠습니다.

** 직원의 도움이 필요한 경우 파란색 벨을 클릭 하면 직원의 화면으로 호출 안내가 전달 됩니다.

** 도움말 버튼을 클릭 하면 이 사용자 메뉴얼 페이지를 볼 수 있습니다.









결제 진행해 보기


결제는 QR 코드가 보이면 그걸 고객(결제할 사람)의 스마트폰에 있는 카메라 앱으로 보여 주면 삼성폰의 경우는 카메라 앱에서 QR코드를 인식해서 URL 링크 팝업이 나타납니다. 인식이 되지 않는 다면 QR Scaner 앱을 실행시켜서 해야 합니다.


결제 흐름



결제하기 전에 고객의 휴대전화 번호를 입력하도록 안내하고 있습니다. 고객의 실적 집계를 구현할 수 있는 기초 자료가 되기 하고, 일단 취소가 되어야 하는 경우 필요한 정보로 사용됩니다. 전화번호 입력이 되고 나면 다음은 QR코드가 있는 화면으로 넘어갑니다. 아래로 내려 보면 고객(결제할 사람)이 따라 해야 하는 부분을 이미지로 표시해 두었습니다.

결제가 되고 나면 앱에서는 목록 앞에 결제된 건에 대해서 파란색 카드 모양으로 활성화됩니다. 이때 취소를 하고 싶다면 파란색 카드 버튼을 클릭하면 취소를 진행할 수 도 있습니다.


취소 처리



결제 취소가 되는 경우는 이전 화면으로 돌아갑니다. 다시 선택을 하고 결제를 진행하여야 합니다.


주방 Order 모아 보기


주방화면



 


** 관리 화면에서는 등록된 주문 목록이 전체가 조회됩니다. (단, 등록된 날자가 오늘은 경우만 조회 됩니다. 24시를 넘어가는 경우 어제 날자 오더는 볼 수 없습니다.)

** 오더 조회 시간에 대한 의견을 주시면 수정을 해 보도록 하겠습니다.

** 목록이 나오지 않는 경우에는 파란색 메뉴판 버튼을 클릭해서 조회를 할 수 있습니다.

** 느낌표 안내 버튼은 앱의 기능에 대한 간략한 정보를 전달합니다.

** 물음표 안내 버튼은 사용설명서 페이지 (이 페이지)로 이동하도록 하고 있습니다.

** 로그아웃 버튼은 앱을 종료합니다. 다시 앱을 실행하면 로그인을 새로 해야 합니다.

** 파란색 지문 버튼은 관리자를 위한 추가 입력사항 (처음에 입력했던 정보)를 수정할 수 있는 화면이 보입니다.

** 지문 인식이나 PIN 확인은 앱을 설치한 폰에 등록된 바이오 인증을 활용 합니다. (but 절대 그 비밀번호를 알아서 확인이 되는 것이 아니고 안드로이드에서 지원하는 기능으로 체크 되는 지만 활용하고 있습니다.)


주방에 알림 처리


주방에 알림 팝업







테이블에서 오더가 발생하면 주방 데스크로 선정한 단말에는 알림이 발생됩니다.

** 이 화면에서도 결제된 건은 결제에 파란 카드 버튼이 나오고,

** 결제 대기 중이거나, 취소된 경우는 회색 카드 버튼이 나타납니다.

** 파란 카드 버튼일 때는 클릭하면 취소를 진행할 수 있습니다.

** 오더는 오늘 중으로 발생된 것만 조회가 되고 있습니다. 추후 영업시간 등으로 조회 시간을 개선해볼 예정입니다.

** 제목 줄을 클릭하면 순서 정렬를 해 볼 수 있습니다. 예를 들어 상품명을 클릭 하면 상품명(내부 코드 기준) 순으로 정렬을 할 수 있습니다. 한번더 클릭 하면 역순 정렬도 진행됩니다.
보시기 편하도록 변경해 보세요.







직원호출 기능 추가


앱이 업데이트(ver.0.1.5 ~) 가 되면서 추가 되는 기능 입니다.


호출 서비스



상품 구매 화면 상단의 호출 버튼을 클릭 하면 직원 호출 여부를 확인하고, 확인을 클릭 하면 주방 단말로 설정된 휴대 장치로 알림을 전달 합니다. 알림이 도착 하면 알림을 표시 하는 팝업이 나타나고 휴대폰의 뒤로 가기를 클릭해서 해당 화면에서 나가면 관리 페이지에서 해당 정보를 확인할 수 있습니다.

호출 내역의 버리기 버튼을 클릭 하면 호출 이력을 삭제 합니다.


판매 리스트 엑셀로 받기


이 기능은 관리 페이지의 3번째 보고서 버튼을 클릭 하면 실행 됩니다.


매출내역 이메일 통지 받기



최근 7일간의 매출 내역을 엑셀 등으로 받고 싶은 경우에 시용할 수 있습니다. 버튼을 클릭 하면 내부적으로 최근 7일 동안 발생한 오더 리스트를 엑셀에 목록으로 저장 하고, 저장된 파일을 공유 하는 처리가 진행 됩니다. 엑셀이 첨부 되어 진행이 되어야 하기 때문에 꼭 이메일로 발송 될 수 있도록 처리를 부탁 드립니다.

2022.12.03 현재까지 적용된 기능에 대한 설명을 마칩니다. 이 앱을 이용해 보고 싶다거나, 개선이 필요한 부분이 있다고 생각되시는 부분이 있으시면 6k2emg@gmail.com으로 메일을 보내 주시면 확인하는 데로 회신해 드리겠습니다. 다만, 즉시적인 응답은 안될 수 도 있습니다. 감사합니다.

수정된 버전에 출시 되었습니다.
https://play.google.com/store/apps/details?id=com.billcoreatech.bespeak1003&pli=1



 


주문이요, 미니키오스크 - Google Play 앱


매장안에 있는 테이블에서 주문을 실시간으로 받고 주방으로 전달해 앱 입니다. 나만의 키오스크를 마련해 보세요


play.google.com




 





오늘의 이야기

이번 여행에는 차편(자체, 렌터카)을 준비하지 않았습니다. 혼자 하는 여행이기도 했지만, 아무 준비도 없이 떠난 여행이었기 때문에요. 울릉군청 홈페이지 울릉군청 홍보대사(?)도 아니면서 울릉군청 홈페이지 링크를 달아 놓은 이유는 딱 하나... 정보가...