어르신이 현재 위치 주변의 병원·약국·편의점·경찰서 등 주요 장소를 쉽게 찾고, 잠금화면/홈 안내 화면에서 큰 글씨와 음성으로 이동 안내를 받을 수 있도록 만든 Android 앱입니다.
최근 구현 기준으로 앱은 단순 장소 추천을 넘어 실제 도보/대중교통 경로 안내, 즐겨찾기와 홈 하트 고정 통합, 새로고침 강제 재조회, 휴대폰 재부팅 후 홈 안내 알림 진입까지 지원합니다.
| 영역 | 기술 |
|---|---|
| 언어 | Kotlin |
| UI | Android View System, XML, ViewBinding |
| 지도 | Google Maps SDK for Android |
| 장소 | Google Places API (New) |
| 경로 | Google Routes API |
| 네트워크 | Retrofit, Moshi, OkHttp |
| 로컬 DB | Room, KSP |
| 인증/프로필 | Firebase Authentication, Cloud Firestore |
| 위치 | FusedLocationProviderClient, Foreground Service |
| 음성 안내 | Android TextToSpeech |
| 비동기 | Kotlin Coroutines, Flow |
| 최소 SDK | 24 |
| 타겟 SDK | 34 |
- 현재 위치 권한 요청 및 위치 기반 지도 이동
- Google Places API로 주변 장소 조회
- 병원, 편의점, 경찰서, 지하철 등 카테고리 매핑
- 카테고리·검색 반경·영업 상태 기반 필터 적용
- 지도 마커 및 하단 장소 목록 표시
- 장소 상세 화면에서 사진/리뷰/거리/도보 시간 표시
- Google Maps 길찾기 딥링크 지원
- Firebase 로그인/회원가입
- 온보딩에서 이름, 연령대, 선호 장소 저장
- Firestore 프로필 + 로컬 캐시 기반 추천
- 방문 빈도, 선호 카테고리, 거리 기반 추천 점수 계산
- Room에 최근 방문 장소 저장
- 5분 이내 동일 장소 중복 방문 기록 방지
- Android 정책을 고려해 MyPage 버튼/부팅 알림 클릭으로 안내 화면 진입
- 현재 시간/날짜 표시
- 최근 방문 장소 + 주변 추천 장소 표시
- 거리순/추천순/방문 횟수순 정렬
- 전체/병원/편의점/경찰서 필터
- 방향 화살표 + 남은 거리 표시
- TTS 기반 방향 안내
- 장소 상세 진입
- 하트 버튼으로 즐겨찾기/고정 상태 변경
즐겨찾기와 HomeActivity 하트 고정은 같은 상태를 사용합니다.
- PlaceDetailActivity에서 즐겨찾기 추가 → HomeActivity 하트 표시
- HomeActivity에서 하트 선택 → MyPage 즐겨찾기 목록에 표시
- MyPage 최근 장소에서 하트 선택 → HomeActivity와 즐겨찾기에 동시 반영
- 대표 고정 장소는 주기적 TTS 안내에 사용
핵심 저장소: AppPreferences.favoritePlaceIds, AppPreferences.pinnedPlaceId
Routes API 응답을 기반으로 도보-only, 버스, 지하철 경로를 구분합니다.
- 목적지까지 도보 안내
- 방향 화살표와 남은 거리 유지
- 목적지까지의 안내 문구를 TTS로 재생
- 정류장까지 도보 안내
- 정류장 근처에서 다음 행동 안내 표시
- 버스 번호, 방면, 이동 정류장 수, 하차 정류장 안내
[탑승했어요],[내렸어요],[다시 듣기]버튼 제공- 하차 후 목적지까지 도보 안내 전환
- 역/출구까지 도보 안내
- 역 근처에서 노선, 방면, 이동 역 수, 하차역 안내
- Routes 안내 문구에 출구 번호가 있으면 진입/하차 출구 안내 반영
- 출구 정보가 없으면 역 기준으로 안전하게 fallback
- 탑승 전에는 방향 화살표 유지
- 탑승 중에는 도보 화살표를 숨겨 오해 방지
- 하차 후 목적지까지 도보 안내 전환
관련 코드:
RoutesRepository.kt— Routes API 호출 및Guide생성HomeActivity.kt— 안내 상태 전환, 거리 기반 탑승 안내 표시RecentPlaceAdapter.kt— 카드 내 안내 설명/버튼 바인딩RecentPlace.kt— 카드 UI 모델
새로고침 버튼을 누르면 단순 UI 갱신이 아니라 실제로 강제 재조회합니다.
동작 순서:
- 현재 위치 확인 중 표시
- 기존 경로 작업/가이드/검증 캐시 초기화
- 주변 장소 다시 조회
- 추천 목록 다시 정렬
- Routes API 경로 다시 계산
- 완료/실패 상태 문구와 Toast 표시
위치 획득 실패 시 마지막 저장 위치가 있으면 해당 위치 기준으로 재계산합니다.
휴대폰이 재부팅되면 BOOT_COMPLETED를 받아 알림을 표시합니다.
- 알림 제목: 위치 안내를 시작할까요?
- 알림 클릭 시
HomeActivity실행 - Android 13 이상에서는 알림 권한 필요
- 앱을 한 번 이상 실행한 뒤부터 부팅 알림이 정상 동작
관련 코드:
BootCompletedReceiver.ktAndroidManifest.xml의RECEIVE_BOOT_COMPLETED,POST_NOTIFICATIONS
- 홈 화면 AppWidget에서 위치 갱신 상태 표시
- Foreground Service 기반 위치 추적 구조 포함
- 위치 업데이트 브로드캐스트로 HomeActivity 안내 갱신
app/src/main/
├── AndroidManifest.xml
├── java/com/example/seniorlocationapp/
│ ├── MainActivity.kt
│ ├── AuthGuardActivity.kt
│ ├── LoginActivity.kt
│ ├── SignupActivity.kt
│ ├── OnboardingActivity.kt
│ ├── MapActivity.kt
│ ├── HomeActivity.kt
│ ├── MyPageActivity.kt
│ ├── PlaceDetailActivity.kt
│ ├── SearchResultsActivity.kt
│ ├── FilterActivity.kt
│ ├── SettingsActivity.kt
│ ├── BootCompletedReceiver.kt
│ ├── adapter/
│ │ ├── RecentPlaceAdapter.kt
│ │ ├── FavoritePlaceAdapter.kt
│ │ ├── MapPlaceAdapter.kt
│ │ ├── PlaceAdapter.kt
│ │ └── SearchResultAdapter.kt
│ ├── data/
│ │ ├── AppPreferences.kt
│ │ ├── PlacesRepository.kt
│ │ ├── RoutesRepository.kt
│ │ ├── UserRepository.kt
│ │ ├── UserProfileCache.kt
│ │ ├── RecommendationScorer.kt
│ │ ├── CategoryMapping.kt
│ │ └── CategoryDisplay.kt
│ ├── db/
│ │ ├── AppDatabase.kt
│ │ ├── dao/
│ │ │ ├── PlaceDao.kt
│ │ │ └── RecentPlaceDao.kt
│ │ └── entity/
│ │ ├── PlaceEntity.kt
│ │ └── RecentPlaceEntity.kt
│ ├── location/
│ │ ├── LocationHelper.kt
│ │ ├── LocationTrackingManager.kt
│ │ ├── LocationTrackingService.kt
│ │ ├── LocationUpdateBroadcast.kt
│ │ └── HeadingProvider.kt
│ ├── model/
│ │ ├── PlaceDto.kt
│ │ ├── RouteDto.kt
│ │ ├── RecentPlace.kt
│ │ ├── SearchResult.kt
│ │ ├── ScoredPlace.kt
│ │ └── UserProfile.kt
│ ├── network/
│ │ ├── PlacesApiClient.kt
│ │ ├── PlacesApiService.kt
│ │ ├── RoutesApiClient.kt
│ │ └── RoutesApiService.kt
│ ├── util/
│ │ ├── AccessibilityUiHelper.kt
│ │ ├── DistanceFormatter.kt
│ │ ├── KoreanPlaceName.kt
│ │ ├── NavigationCueHelper.kt
│ │ ├── PermissionHelper.kt
│ │ └── RemoteImageLoader.kt
│ ├── viewModel/
│ │ └── FilterViewModel.kt
│ └── widget/
│ └── LocationAppWidgetProvider.kt
└── res/
├── layout/
│ ├── activity_home.xml
│ ├── activity_map.xml
│ ├── activity_place_detail.xml
│ ├── activity_my_page.xml
│ └── item_recent_place.xml
├── drawable/
├── menu/
├── values/
└── xml/
앱의 핵심 안내 화면입니다.
담당 역할:
- 잠금화면 위 표시 설정
- 현재 위치 수신 및 경로 갱신 판단
- 주변 장소/최근 방문 장소 추천 목록 구성
- 정렬/카테고리 필터 처리
- RoutesRepository에서 받은
Guide를RecentPlaceUI 모델로 변환 - 방향 화살표, 거리, TTS 안내 문구 생성
- 대중교통 단계 상태 관리
APPROACHING: 역/정류장까지 이동 중BOARDED: 탑승 중ALIGHTED: 하차 후 도보 안내
[탑승했어요],[내렸어요],[다시 듣기]처리- 새로고침 강제 재조회 처리
중요 상태:
routeGuides: MutableMap<String, RoutesRepository.Guide>
transitStages: MutableMap<String, TransitStage>
nearbyPlaces: List<PlaceEntity>
latestRecommendations: List<RecentPlace>Google Routes API 전담 계층입니다.
담당 역할:
- 도보/대중교통 경로 요청
- 가까운 장소는 도보 경로 우선
- 대중교통 경로에서 첫 탑승 단계 추출
- 버스/지하철 구분
- 출발 정류장/역, 도착 정류장/역, 노선명, 방면, 정류장 수 추출
- 안내 문구 생성
- 경로 캐시 저장/복원
핵심 모델:
data class Guide(
val summary: String,
val instruction: String,
val firstFlow: FirstFlow,
val transitLine: String?,
val transitHeadsign: String?,
val departureStopName: String?,
val arrivalStopName: String?,
val stopCount: Int,
val transitInstruction: String?,
val ridingInstruction: String?,
val alightInstruction: String?
)HomeActivity와 MyPage의 장소 카드 UI를 담당합니다.
담당 역할:
- 방향 아이콘/거리 표시
- 장소명/요약 표시
- 하트 버튼 표시
- 대중교통 안내 설명 표시
- 탑승/하차/다시 듣기 버튼 이벤트 전달
사용자별 SharedPreferences 래퍼입니다.
담당 역할:
- 사용자 설정 저장
- 글씨 크기, 음성 안내, 위치 갱신 주기 저장
- 마지막 위치 캐싱
- 즐겨찾기 ID Set 관리
- HomeActivity 하트 고정과 즐겨찾기 상태 통합
핵심 규칙:
toggleFavorite(placeId)가 즐겨찾기와 홈 하트 상태를 함께 변경pinnedPlaceId는 주기적 음성 안내용 대표 장소로 사용
지도 중심 화면입니다.
담당 역할:
- Google Map 초기화
- 현재 위치 표시
- 주변 장소 조회 및 마커 표시
- 카테고리/즐겨찾기 탭 처리
- 장소 선택 시 PlaceDetailActivity 진입
프로필, 최근 방문, 즐겨찾기 목록 화면입니다.
담당 역할:
- Firebase/캐시 프로필 표시
- 최근 방문 목록 표시
- 최근 방문 하트 토글
- 즐겨찾기 목록 표시
- HomeActivity 미리보기 진입
휴대폰 재부팅 후 홈 안내 화면으로 들어갈 수 있는 알림을 표시합니다.
담당 역할:
Intent.ACTION_BOOT_COMPLETED수신- 알림 채널 생성
- 알림 클릭 시 HomeActivity 실행 PendingIntent 연결
앱 실행
↓
MainActivity
↓
LoginActivity / SignupActivity
↓
OnboardingActivity
↓
MapActivity
├─ 현재 위치 확인
├─ 주변 Places 조회
├─ 지도 마커 표시
└─ 장소 선택 → PlaceDetailActivity
MyPageActivity
├─ 프로필 확인
├─ 최근 방문 확인
├─ 즐겨찾기 확인
└─ HomeActivity 진입
HomeActivity
├─ 주변 추천/최근 방문 목록 표시
├─ 도보 방향 화살표 안내
├─ TTS 다시 듣기
├─ 대중교통 탑승 전 안내
├─ 탑승했어요 → 탑승 중 안내
├─ 내렸어요 → 목적지 도보 안내
└─ 하트 → 즐겨찾기/고정 동기화
휴대폰 재부팅
↓
BootCompletedReceiver
↓
알림 표시
↓
알림 클릭 → HomeActivity
활성화할 API:
- Maps SDK for Android
- Places API (New)
- Routes API
API 키 제한:
- Android 앱 제한 사용
- 패키지명과 SHA-1 등록
필요 항목:
- Firebase Authentication 이메일/비밀번호 로그인 활성화
- Cloud Firestore 활성화
app/google-services.json배치
프로젝트 루트의 local.properties에 다음 값을 설정합니다.
MAPS_API_KEY=YOUR_GOOGLE_MAPS_API_KEY
DEBUG_SHA1=AA:BB:CC:DD:...SHA-1 확인:
./gradlew signingReportManifest 주요 권한:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />설명:
- 위치 권한: 주변 장소 추천, 경로 안내
- 알림 권한: Android 13 이상 부팅 후 홈 안내 알림
- 부팅 권한: 재부팅 후 알림 표시
- Foreground Service 위치 권한: 백그라운드 위치 추적 구조
Debug 빌드:
./gradlew assembleDebugAPK 위치:
app/build/outputs/apk/debug/app-debug.apk
실기기 설치:
adb install -r app/build/outputs/apk/debug/app-debug.apk앱 실행:
adb shell monkey -p com.example.seniorlocationapp 1- 인증: 이메일 회원가입 → 온보딩 저장 → 로그아웃 → 이메일 로그인까지 확인합니다.
- 지도 기본 흐름: 위치 권한 허용 후 현재 위치 이동, 주변 장소 마커, 하단 추천 3곳 표시를 확인합니다.
- 필터: 지도 상단
필터버튼 → 카테고리/반경/영업중 옵션 적용 → 지도 마커와 추천 목록이 조건에 맞게 갱신되는지 확인합니다. - 검색/상세: 장소 검색 → 결과 탭/거리순 확인 → 상세 화면에서 사진, 평점, 리뷰, 거리, 길찾기 버튼을 확인합니다.
- 즐겨찾기 동기화: 상세 화면 하트 추가 → MyPage 즐겨찾기 표시 → HomeActivity 하트/고정 상태 반영을 확인합니다.
- 홈 안내: MyPage의
잠금화면 보기버튼으로 HomeActivity 진입 → 큰 글씨 시간, 추천 목록, 정렬/카테고리 칩, 새로고침 상태 문구를 확인합니다. - 음성/대중교통 안내: HomeActivity에서 방향 영역을 눌러 TTS를 확인하고, 대중교통 경로에서는
[탑승했어요]→[내렸어요]→[다시 듣기]흐름을 확인합니다. - 백그라운드/위젯: 설정에서 위치 업데이트 간격 변경 → 위젯의 마지막 업데이트 시간과 HomeActivity 안내 갱신 여부를 확인합니다.
- 재부팅 알림: 앱을 한 번 실행하고 알림 권한을 허용한 뒤 재부팅 → “위치 안내를 시작할까요?” 알림 클릭 시 HomeActivity 진입을 확인합니다.
- 로그인 UI 정리: 로그인 화면에 미구현 소셜 로그인 버튼이 보이지 않고 이메일 로그인/회원가입만 노출되는지 확인합니다.
증분 리소스 캐시가 깨진 경우가 있습니다.
./gradlew clean
./gradlew assembleDebug확인 항목:
- Google Cloud에서 Maps SDK, Places API, Routes API 활성화 여부
- API 키의 Android 앱 제한 패키지명/SHA-1 일치 여부
local.properties의MAPS_API_KEY설정 여부- 설정 변경 후 5~10분 대기
- 앱을 한 번 이상 실행했는지 확인
- Android 13 이상에서 알림 권한을 허용했는지 확인
- 일부 제조사 배터리 최적화 정책에 따라 부팅 알림이 지연/제한될 수 있음
- 위치 권한이 허용되어 있는지 확인
- 기기의 GPS/위치 서비스 활성화 확인
- 실내/지하에서는 GPS 정확도가 낮을 수 있음
- 지하철 출구 번호는 Routes API 안내 문구에 포함될 때만 추출합니다.
- 지하철 탑승 중에는 GPS가 불안정할 수 있어 사용자의
[탑승했어요],[내렸어요]수동 버튼을 함께 사용합니다. - Android 정책상 재부팅 직후 Activity를 직접 띄우기보다 알림 클릭 방식으로 HomeActivity에 진입합니다.
MainActivity라우팅 정책은 최종 배포 전 로그인/온보딩 상태에 맞게 점검이 필요합니다.
학습 및 데모 목적의 프로젝트입니다.