Compose Google Map

Davidยท2024๋…„ 5์›” 4์ผ
0
post-thumbnail

๐Ÿ—บ๏ธ ์ง€๋„๋ฅผ ์ด์šฉํ•œ ์„œ๋น„์Šค ๊ฐœ๋ฐœ


ํšŒ์‚ฌ์—์„œ ์ด๋ฒˆ์—
โœŒ๐Ÿป์ง€๋„ ๊ธฐ๋ฐ˜โœŒ๐Ÿป์˜ ๋ฐ˜๋ ค๊ฒฌ ์œ ์‹ค ๋ฐ ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ
๊ฐœ๋ฐœํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์™”์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ €ํฌ ์•ฑ์— ์ƒํ™ฉ์€
๋ฐ”ํ…€๋„ค๋น„๊ฒŒ์ด์…˜, ๋งˆ์ดํŽ˜์ด์ง€, ์นด๋ฉ”๋ผ ํ™”๋ฉด์„ ์ œ์™ธํ•œ
ํ™”๋ฉด์€ ๋ชจ๋‘ ์ปดํฌ์ฆˆ๋กœ ์ „ํ™˜์ด ์™„๋ฃŒ๋œ ์ƒํƒœ์ด๊ณ 

๋ฐ”ํ…€ ๋„ค๋น„๊ฒŒ์ด์…˜์— '๋™๋„ค' ํƒญ์ด ์ถ”๊ฐ€๋˜๋Š” ์ƒํ™ฉ์—์„œ
ํ•ด๋‹น ํ™”๋ฉด๋„ ์ปดํฌ์ฆˆ๋กœ ๊ฐœ๋ฐœ๋˜๋ฉด
์ถ”ํ›„ ์ปดํฌ์ฆˆ ํ†ตํ•ฉ์— ํŽธ๋ฆฌํ•œ ์ƒํ™ฉ์ธ๋ฐ

๊ตฌ๊ธ€๋งต ์ปดํฌ์ฆˆ์— ๋Œ€ํ•œ ์ž๋ฃŒ๊ฐ€ ๋ณ„๋กœ ์—†๊ณ 
์žˆ์–ด๋„ ๊ธฐ์ดˆ์ ์ธ ์‚ฌ์šฉ๋ฒ• ๋ฐ–์— ์—†์–ด์„œ
๊ธฐ์ˆ ์„ ํ•„์š”ํ•œ ์ŠคํŽ™์— ๋งž๊ฒŒ ๊ฒ€ํ† ๋ฅผ ํ•ด๋ณด์•˜๋Š”๋ฐ์š”.

๊ฒ€ํ† ํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐœ๊ฒฌํ•œ
์‚ฌ์šฉ๋ฒ•๊ณผ ์ฃผ์˜ํ•  ์  ๋“ฑ์„
๊ณต์œ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿš€ Compose Google Map


๐Ÿ“Œ android-maps-compose dependencies

// Compose - map
implementation "com.google.android.gms:play-services-maps:$rootProject.googleMapVersion"
implementation "com.google.android.gms:play-services-location:$rootProject.googleLocation"
implementation "com.google.maps.android:maps-compose:$rootProject.composeMapVersion"
// (Optional)
implementation "com.google.maps.android:maps-compose-utils:$rootProject.composeMapVersion"

๐Ÿ“Œ GoogleMapAPIKey ์„ค์ •

  • MAPS_API_KEY=YOUR_API_KEY๊ฐ€ ์ €์žฅ๋œ ๊ณณ์„ ์…‹ํŒ…
  • ComposeMap ์„ ์‚ฌ์šฉํ•˜๋Š” build.gradle.kts > secrets ๋ฅผ ์‚ฌ์šฉ

plugins {
    ...
    id(libs.plugins.secret.gradle.plugin.get().pluginId)
}

android {
    ...
}

dependencies {
    ...
    implementation(libs.bundles.compose.map)
}

secrets {
    // To add your Maps API key to this project:
    // 1. Add this line to your local.properties file, where YOUR_API_KEY is your API key:
    // MAPS_API_KEY=YOUR_API_KEY
    defaultPropertiesFileName = "local.properties"
}

๐Ÿ’๐Ÿป ๊ตฌ๊ธ€๋งต ์ปดํฌ์ฆˆ 3์š”์†Œ

CameraPositionState

  • ์ง€๋„์˜ ์นด๋ฉ”๋ผ ์ƒํƒœ๋ฅผ ๋‹ด๋‹น
// ์ดˆ๊ธฐ ์„ค์ •
val cameraPositionState = rememberCameraPositionState()
val cameraPositionState = rememberCameraPositionState {
   this.position = CameraPosition.fromLatLngZoom(LatLng target, float zoomLevel)        
}
// ์นด๋ฉ”๋ผ ์ œ์–ด
LaunchedEffect(key) {
   cameraPositionState.position = CameraPosition.fromLatLngZoom(latlng, zoom)
}

MapProperties

  • ์ง€๋„์˜ Property ๋ฅผ ์„ค์ • ๋‹ด๋‹น
  • ์ง€๋„ UI์—์„œ ๋‚ด ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ • ์—ฌ๋ถ€ ๋ฐ ์คŒ ์„ค์ • ๋“ฑ๋“ฑ
val properties by remember {
        mutableStateOf(
            MapProperties(
                isMyLocationEnabled = true,
                minZoomPreference = getMinZoomLevelWithin3KM(windowWidthSize)
            )
        )
}

MapUiSettings

  • ์ง€๋„์˜ UI ์„ค์ • ๋‹ด๋‹น
  • ์ง€๋„์—์„œ ์คŒ ํ‘œ์‹œ ์—ฌ๋ถ€, ๋‚ด ์œ„์น˜ ํ‘œ์‹œ ์—ฌ๋ถ€, ์Šคํฌ๋กค ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๋“ฑ ์„ค์ • ๋‹ด๋‹น
val uiSettings by remember {
     mutableStateOf(
         MapUiSettings(
            myLocationButtonEnabled = true, 
            zoomControlsEnabled = false,
            rotationGesturesEnabled = false
         )
     )
}

์œ„์˜ ์š”์†Œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ
GoogleMap ์ปดํฌ์ €๋ธ” ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ›‘ ๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๊ตฌ๊ธ€๋งต์—์„œ ํ˜„์žฌ ๋‚ด ์œ„์น˜๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ • ์‹œ๋Š”

"์œ„์น˜ ๊ถŒํ•œ์„ ๋ฐ›์€ ์ƒํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค"


๋งŒ์•ฝ ๊ถŒํ•œ์„ ๋ฐ›์ง€ ์•Š์€ ์ƒํƒœ์—์„œ
MapProperties์™€ MapUiSettings ๋กœ ๋‚ด ์œ„์น˜ ์ถ”์ 
ํ—ˆ์šฉ ๊ฐ€๋Šฅ ์„ค์ • ์‹œ
๐Ÿ› SecurityException ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ—๏ธ ์œ„์น˜๊ถŒํ•œ ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ UI ๊ตฌ์„ฑ

ํฐ ํ‹€์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
โœ… ์œ„์น˜ ๊ถŒํ•œ์˜ ๊ฐ’ ๋ณ€๊ฒฝ์— ๋”ฐ๋ผ ํ—ˆ์šฉ์ด ๋๋Š”์ง€ ํ™•์ธ
โœ… ์œ„์น˜ ๊ถŒํ•œ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ UI ๊ตฌ์„ฑ

์œ„์˜ ๊ตฌ์„ฑ์„ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด
๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.


๐Ÿ“ Marker ๊ทธ๋ฆฌ๊ธฐ

๋งˆ์ปค๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ๋Š”
์œ„๋„(latitude)์™€ ๊ฒฝ๋„(longitude)๊ฐ€ ํ•„์š” ํ•ฉ๋‹ˆ๋‹ค.
GoogleMapCompose ์—์„œ๋Š” ์œ„๋„ ๊ฒฝ๋„๋ฅผ
MarkerState๋กœ ๊ฐ์‹ธ์„œ ์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด MarkerState ์ž์ฒด๋Š”
Wrapper ํด๋ž˜์Šค์ด๊ณ 
position์ด ์œ„๋„๊ฒฝ๋„(LatLng) ๋ฅผ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์–ด๋–ค ๋งˆ์ปค๋ฅผ ๋งŒ๋“ ๋‹ค โžก๏ธ MarkerState ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋ผ๊ณ  ์ดํ•ดํ•˜์‹œ๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋งˆ์ปค๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋Š”
GoogleMap ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ 
contents ๋žŒ๋‹ค์•ˆ์— Marker๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.


๐Ÿ’…๐Ÿป ๐Ÿ“ Custom Marker ๊ทธ๋ฆฌ๊ธฐ

๊ธฐํš์—์„œ๋Š” ๋‹น์—ฐํžˆ(?!) ๊ธฐ๋ณธ ๋งˆ์ปค๋งŒ ์‚ฌ์šฉํ•˜๊ฒŒ ๊ธฐํšํ•˜์ง€ ์•Š๊ณ 
์ปค์Šคํ…€ํ•œ ๋””์ž์ธ์˜ ๋งˆ์ปค๋ฅผ ๊ธฐํš ํ•˜์…จ์Šต๋‹ˆ๋‹ค.

๊ธฐํš์—์„œ๋Š” ๋งˆ์ปค ๋””์ž์ธ์ด
โœŒ๐Ÿป์ด๋ฏธ์ง€โœŒ๐Ÿป์™€ โœŒ๐Ÿปํ…์ŠคํŠธโœŒ๐Ÿป๊ฐ€
๋“ค์–ด๊ฐ„ ์กฐํ•ฉ์˜ ๋งˆ์ปค์˜€์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๋Š”
์šฐ๋ฆฌ ์„œ๋ฒ„์— ์˜ฌ๋ฆฐ ์ด๋ฏธ์ง€ or ๊ณต๊ณต API ์— ๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€๋ฅผ
๋ฐ›์•„์˜ค๋Š” ์ŠคํŽ™์ด์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ๊ธฐํš์˜ Custom Marker ๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•ด
์–ด๋–ค ์„ค๊ณ„๋“ค๊ณผ ํ…Œํฌ๋‹‰์ด ํ•„์š” ํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ“„ Marker Model ์„ค์ •

  • ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์ฃผ๋Š” ์œ„๋„, ๊ฒฝ๋„๋ฅผ LatLng ํ˜•ํƒœ๋กœ Mapping
  • Mapping ๋œ LatLng ํ˜•ํƒœ์˜ ์œ„์น˜ ํ”„๋กœํผํ‹ฐ๋ฅผ Marker ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก MarkerState๋กœ Wrapping


๐Ÿ“ MarkerComposable

  • ํ•ด๋‹น ์ปดํฌ์ €๋ธ”์€ key์˜ ๋ณ€๊ฒฝ์ด ์žˆ์–ด์•ผ๋งŒ contents ๊ฐ€ Recomposition ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ๊ธฐํš์„ ๋ณด์‹œ๋ฉด
Marker๋Š” ์ด๋ฏธ์ง€๋ฅผ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„
Rendering ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ €ํฌ ํšŒ์‚ฌ๋Š”
Remote Image ์‚ฌ์šฉ ์‹œ
Coil Library ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ์š”.

content์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์„ฑํ•ด์„œ
Rendering ์„ ์ง„ํ–‰ํ•˜๋ฉด

๐Ÿšจ๋„คํŠธ์›Œํฌ ์ด๋ฏธ์ง€๊ฐ€ ํ•ญ์ƒ ์‹คํŒจ๋กœ ๋ณด์˜€์Šต๋‹ˆ๋‹ค.๐Ÿšจ
๐Ÿ‘‰๐Ÿป ๋“ฑ๋ก๋œ ์ด์Šˆ

๐Ÿš€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
๐Ÿ“Œ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹œ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ๋งŒ Recomposition
๐Ÿ“Œ key ๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ• (8์›” ์ดํ›„ ์ถ”๊ฐ€๋œ ๋ฐฉ๋ฒ•)

์œ„ ๋ฐฉ๋ฒ•์œผ๋กœ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป๐Ÿ‘‡๐Ÿป


๐Ÿš€ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹œ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ๋งŒ Recomposition

๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ViewModel ์—์„œ๋Š”
๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฏธ์ง€ ๋กœ๋“œ๋ฅผ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ > UI์—์„œ ๋ฐ”๋ผ๋ณด๋Š” ์ƒํƒœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝ(retryCount++)
  • ์„ฑ๊ณตํ•œ ๋ฐ์ดํ„ฐ > UI์—์„œ ๋ฐ”๋ผ๋ณด๋Š” ์ƒํƒœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝ(isLoadedImage = true)
  • ์œ„์˜ Recomposition ์„ ์œ ๋ฐœํ•˜๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์€ ์ง€๋„๊ฐ€ ์›€์ง์ผ ๋•Œ ์ทจ์†Œ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋กœ์ง์ด์•ผ ํ•จ
    • ์ทจ์†Œ๋Š” cooperative ํ•˜๊ฒŒ ์ž‘๋™ํ•ด์•ผ ํ•จ



UI์˜ Screen ์—์„œ๋Š”

  • VM ์—์„œ ํ˜ธ์ถœํ•œ ๋งˆ์ปค ๋ฐ์ดํ„ฐ ๊ทธ๋ฆฌ๊ธฐ
  • ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋“œ
  • ์œ„์น˜ ์ด๋™์— ๋”ฐ๋ฅธ ๋งˆ์ปค api ํ˜ธ์ถœ ๋ฐ ์ด๋ฏธ์ง€ ๋กœ๋“œ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ ์ „์†ก
  • ์ด๋™ ์‹œ ์ด์ „์— ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ทจ์†Œ

์œ„ ์ฝ”๋“œ๋Š” ๋งˆ์ปค๊ฐ€ ์›€์ง์ธ ํ›„์— VM์— ๋งˆ์ปค๋“ค์„ ํ˜ธ์ถœํ•˜๋Š” Request ๋ฅผ ์š”์ฒญํ•˜๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.

  • ์นด๋ฉ”๋ผ์˜ ํฌ์ง€์…˜์„ ๋ฐ”ํƒ•์œผ๋กœ ํ”Œ๋กœ์šฐ emit
  • ํ˜ธ์ถœ ์กฐ๊ฑด์€ ์ด๋™ ํ›„, ์คŒ ์•„์›ƒ ํ›„, ์ƒˆ๋กœ๊ณ ์นจ ๋˜์–ด์•ผ ํ•  ๋•Œ
  • ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ์ดํ„ฐ ์š”์ฒญ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด debounce

โœŒ๐Ÿป์ถ”๊ฐ€๋กœโœŒ๐Ÿป

  • ์ด๋™ ์ค‘์— ๋ฏธ์ฒ˜ ์™„๋ฃŒ๋˜์ง€ ๋ชป ํ•œ Job๋“ค์€ ๋ชจ๋‘ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋Š” ๋งต ์ด๋™ ์‹œ ํผํฌ๋จผ์Šค ๊ฐœ์„ ์„ ์œ„ํ•œ ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค.


์œ„ ์ฝ”๋“œ๋Š” VM์œผ๋กœ๋ถ€ํ„ฐ ๋งˆ์ปค ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ด๋ ค์˜ฌ ๋•Œ preload ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค,

  • ๊ฐ ๋งˆ์ปค๋งˆ๋‹ค ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ preload ํ•ฉ๋‹ˆ๋‹ค.
  • ๐Ÿ“Œ ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ allowHardware(false)๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ์  ์ž…๋‹ˆ๋‹ค.
    • ์ด์œ ๋Š” ๋งˆ์ปค๋ฅผ ์ปค์Šคํ…€ํ•˜๊ฒŒ ๊ทธ๋ฆด ๋•Œ GoogleMap Sdk ์—์„œ BitmapDescriptor ๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ
      ์ปดํฌ์ฆˆ์—์„œ BitmapDescriptor ๊ฐ์ฒด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด์„œ Bitmap์„ ์–ป์–ด์•ผํ•˜๊ณ 
      Bitmap(์ปค์Šคํ…€ํ•˜๊ฒŒ ๊ทธ๋ ค์ง„)์„ ์–ป๊ธฐ์œ„ํ•ด Canvas๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ
      ์ด ๋•Œ, hardware bitmap ์„ ์ด์šฉํ•  ๋•Œ broken case์— ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

      ๊ทธ๋ž˜์„œ ๋งŒ์•ฝ false๋กœ ์„ค์ •์„ ์•ˆ ํ•˜๋ฉด
      Fatal Exception: java.lang.IllegalArgumentException: Software rendering doesn't support hardware bitmaps
      ๋ฅผ ๋งˆ์ฃผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


์œ„ ์ฝ”๋“œ๋Š” ๋งˆ์ปค๋ฅผ ๋ฐ›์•„์™€์„œ GoogleMap์— Rendering ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  • ํ•˜์œ„ ๋ฒ„์ „์„ ํ˜ธํ™˜์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ filter ์กฐ๊ฑด์— isUndefinedCategory.not() ์„ ์กฐ๊ฑด์œผ๋กœ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

  • ์•„์ดํ…œ๋งˆ๋‹ค CustomMarker๋ฅผ ๊ทธ๋ ค์ค๋‹ˆ๋‹ค. > ์ด ๋•Œ, coil ์— SubcomposeAsyncImage๋ฅผ ์‚ฌ์šฉ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์„ ๊ทธ๋ฆฐ ํ›„ image ๋กœ๋“œ์— ์„ฑ๊ณตํ•œ ๋ฐ์ดํ„ฐ์™€ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฅ˜ํ•˜์—ฌ vm์— ์ „์†ก ํ•ฉ๋‹ˆ๋‹ค.


์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€
๐Ÿš€ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹œ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ๋งŒ Recomposition ๋กœ
ํ•ด๊ฒฐํ•œ ๋ฐฉ๋ฒ• ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ๋ฐฉ๋ฒ•๋“ค๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ๊นŒ์ง€
๋งŽ์€ ๊ณ ๋ ค์™€ ๋ณตํ•ฉ์ ์ธ ์ดํ•ด๊ฐ€ ํ•„์š” ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ƒํƒœ์— ๋Œ€ํ•œ ์ดํ•ด
  • ์ฝ”๋ฃจํ‹ด ์ทจ์†Œ์— ๋Œ€ํ•œ ์ดํ•ด
  • API ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๋น„์šฉ ์ตœ์†Œํ™”
  • Map ์—์„œ Camera position ๊ณผ ์ด๋ฅผ Stream Data๋กœ ํ™œ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌ(flow)
  • coil์— ๋Œ€ํ•œ ์ดํ•ด


๐Ÿ“Œ key ๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ• (8์›” ์ดํ›„ ์ถ”๊ฐ€๋œ ๋ฐฉ๋ฒ•)

์œ„์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ฑ์„ ์„œ๋น„์Šค ํ›„
์ง€์†์ ์œผ๋กœ ๊ฐœ์„ ํ•  ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผ ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ”ผ์ฒ˜ ๊ฐœ๋ฐœ์ด ๋๋‚˜๊ณ  ์ฐจ๋ถ„ํžˆ ์กฐ๊ธˆ์”ฉ
๋ถ„์„์„ ์‹œ์ž‘ ํ–ˆ์—ˆ๋Š”๋ฐ์š”.

์ด๋ฏธ์ง€ ๋กœ๋“œ๊ฐ€ ์‹คํŒจ๊ฐ€ ๋‚˜์™”๊ณ 
๊ทธ ์ดํ›„์— ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—
๊ทธ๋Ÿฌ๋ฉด ๋กœ๋“œ๋ฅผ ์‹คํŒจํ•œ ๋ฐ์ดํ„ฐ์— ํ•œํ•ด์„œ
Recomposition์„ ์œ ๋„ํ•˜์—ฌ ํ•ด๊ฒฐ์„ ํ–ˆ๋Š”๋ฐ

Recomposition์— ๊ด€์ ์œผ๋กœ ๊ณ„์† ์ƒ๊ฐํ•ด๋ณด๋‹ˆ
๊ด€์ ์„ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ
์ข€ ๋” ๋„“ํ˜€์„œ ๊ตฌ๊ธ€๋งต์œผ๋กœ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ
ํ•ด๋‹น ๊ตฌ๊ธ€๋งต์—์„œ Recomposition์ด ๋ฐœ์ƒํ•˜์—ฌ
์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์ฑ„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ๋„ ์ „์—
๋ฆฌ์ปดํฌ์ง€์…˜์ด ๋˜๊ณ 
๊ทธ๋Ÿฌ๋ฉด ์ด๋ฏธ์ง€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋กœ์ง์ด
์ทจ์†Œ ๋œ๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
์™œ๋ƒ๋ฉด ์‹ค์ œ๋กœ coil ๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด

ImageLoader App Package ๐Ÿ— Cancelled - https://์ด๋ฏธ์ง€์ฃผ์†Œ
๋กœ ์ฐํžˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ƒ๊ฐ์„ ์ • ๋ฐ˜๋Œ€๋กœ
Recomposition์„ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ๋ณด์žฅํ•˜๋ฉด ์–ด๋–จ๊นŒ
๋ผ๋Š” ์ƒ๊ฐ์„ ํ–ˆ๊ณ 

์ด๋ฅผ key๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„ ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ key๋ฅผ ์ด์šฉํ•จ์œผ๋กœ์„œ
๊ตฌ๊ธ€๋งต contents์—์„œ ์‚ฌ์šฉํ•˜๋Š”
CircleMarkerComponent๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ
markerItem.id๊ฐ€ ํ‚ค๊ฐ€ ๋˜์–ด โœŒ๐Ÿปํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰์„ ํ•˜๊ณ โœŒ๐Ÿป

ํ•ด๋‹น AsyncPainter๋ฅผ statefull ํ•œ ๊ตฌ์กฐ๋กœ ๊ฐ€์ ธ ๊ฐ€๋ฉด์„œ
AsyncPainter๊ฐ€ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ
MarkerComposable ์„ Recomposition์„ ํ•˜๋ฉด

์ด๋ฏธ์ง€ ๋กœ๋“œ๋Š” ์ทจ์†Œ๊ฐ€ ์•ˆ ๋˜๊ณ 
์ด๋ฏธ์ง€ ๋กœ๋“œ ์ƒํƒœ or ๋งˆ์ปค ์•„์ดํ…œ์ด ๋ณ€ํ™”ํ•  ๋•Œ๋งŒ
MarkerUI๋ฅผ ์ƒํƒœ์— ๋งž์ถฐ์„œ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



๐Ÿ‘†๐Ÿป๐Ÿ—บ๏ธ Gesture Tracking

Compose Google Map ์—์„œ
Gesture ๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”
CameraPositionState ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋งŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด
์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด ํ•œ์ •์ ์ž…๋‹ˆ๋‹ค.

์ด์— ์นด๋ฉ”๋ผ๊ฐ€ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค
Gesture ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋Š”
Effect API ๋ฅผ ์„ค๊ณ„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ œ๊ฐ€ ํ•„์š”ํ•œ ์ •๋ณด๋Š” zoom-in, zoom-out, moving ์ด ํ•„์š”ํ–ˆ๊ณ 

"API ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ƒํƒœ + ์ƒํƒœ๋ฅผ ๋‚ด๋ถ€์—์„œ ์ €์žฅํ•˜์—ฌ ๋น„๊ต + ๊ฐ’ ๋น„๊ต"

MapGestureToken ์„ ์™„์„ฑ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ›‘ ์ ์ด Google-Map์—์„œ
์ œ์Šค์ฒ˜๋ฅผ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์œ„์™€ ๊ฐ™์ด ์ œ์Šค์ฒ˜๋ฅผ ๋ถ„๋ฅ˜ํ•œ ๋ชฉ์ ์€
API ํ˜ธ์ถœ ์ตœ์†Œํ™” ์ž…๋‹ˆ๋‹ค.

zoom-in ํ•  ๋•Œ๋Š” ์ด๋ฏธ ํ•ด๋‹น ๋ฐ˜๊ฒฝ์—
๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋ฏ€๋กœ
๋‹ค์‹œ ๋กœ๋“œํ•  ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์œ„์™€๊ฐ™์ด ํŠธ๋ž˜ํ‚นํ•จ์œผ๋กœ์„œ
๋ฐ์ดํ„ฐ ๋กœ๋“œ์™€ ๋ Œ๋”๋ง์„
์กฐ๊ธˆ ๋” ํšจ์œจ์ ์œผ๋กœ
๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ ์œ„์น˜์— ๋Œ€ํ•ด์„œ


ํ•ด๋‹น ๊ธฐํš์—์„œ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ณณ์€
์ด 3๊ตฐ๋ฐ ์ž…๋‹ˆ๋‹ค.

  • ์ง€๋„ ์ฒ˜์Œ ์ง„์ž… ์‹œ
  • ์‹ ๊ณ /๋ชฉ๊ฒฉ ๊ธ€ ์ž‘์„ฑ ์‹œ
  • ๊ฒŒ์‹œ๊ธ€ ์•Œ๋ฆผ ๋ฐ›๋Š” ์žฅ์†Œ ์„ค์ • ์‹œ

์œ„์˜ ๋กœ์ง์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ
์ƒ๊ฐํ•ด๋ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์šฐ์„  ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์ด ๋งŽ์œผ๋‹ˆ
    โœ… ๋กœ์ง์„ ํ•˜๋‚˜๋กœ ํ†ต์ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ๋˜ํ•œ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋กœ์ง์€
    UI๊ฐ€ ์•„๋‹Œ ViewModel์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š”๋ฐ
    โœ… ์ด ๋•Œ, ํ…Œ์ŠคํŠธ๋ฅผ ํŽธํžˆ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด
    ์ƒ์„ฑ์ž Inject ํ•ด์ฃผ๋Š” ๊ตฌ์กฐ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  • ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํด๋ž˜์Šค์˜
    ๋ณ€๊ฒฝ์„ ๊ณ ๋ คํ•˜์—ฌ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ
    โœ… ์ถ”์ƒํ™”์— ์˜์กดํ•˜๊ฒŒ bindingํ•˜์—ฌ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.



์œ„์˜ ์ฝ”๋“œ๋Š” ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
์œ„๋„ ๊ฒฝ๋„๋ฅผ ์ŠคํŠธ๋ฆผ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.(flow)



์œ„ ์ฝ”๋“œ๋Š” DI ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค.
์•ฑ ์ „์ฒด์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์•„๋‹Œ
ํ•ด๋‹น ํ™”๋ฉด์˜ ViewModel ์ƒ๋ช…์ฃผ๊ธฐ๋กœ
๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ฅผ
์ถ”์ƒํ™”์— ์˜์กดํ•  ์ˆ˜ ์žˆ๊ฒŒ @binds ํ•ฉ๋‹ˆ๋‹ค.


์œ„ ์ฝ”๋“œ๋Š” ์œ„์—์„œ ์„ค๊ณ„ํ•œ interface ๋ฅผ
ViewModel ์—์„œ constructor Inject ํ•˜์—ฌ

UI์—์„œ ์‚ฌ์šฉํ•˜๋Š”
currentPositionAtOnce ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋กœ์จ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋กœ์ง์„
์ „๋ถ€ ๋ดค์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ๋Š” ์œ„์™€ ๊ด€๋ จํ•ด์„œ
์œ ์ €๊ฐ€ GPS ์œ„์น˜๋ฅผ ์‹œ์Šคํ…œ์ ์œผ๋กœ off ํ•˜์—ฌ
๋ฐœ์ƒํ•œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…์— ๋Œ€ํ•ด
์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ“ก GPS, GNSS ์„ค์ •์— ๋Œ€ํ•ด์„œ


์ง€๋„ ์•ฑ์„ ์ถœ์‹œํ•˜๊ณ  ์–ผ๋งˆ ์ง€๋‚˜์ง€ ์•Š์•„
๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๊ฐ€
Sentry ์— ์ข…์ข… ๋ฐœ์ƒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์—๋Ÿฌ ๋ฐœ์ƒ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•˜์—ฌ
์ด๋Š” ์ปดํฌ์ฆˆ ์ด์Šˆ๊ฐ€ ์•„๋‹Œ๊ฑธ๋กœ ์ƒ๊ฐํ–ˆ๊ณ 

๋‚œ๋…ํ™” ๋œ ์ฝ”๋“œ(b1.a)๋ฅผ
progarud mapper๋ฅผ ํ†ตํ•ด์„œ
ํŒŒ์•…ํ•ด๋ณด๋‹ˆ '๋™๋„ค ํƒญ' ๋ถ€๋ถ„์ด์˜€์Šต๋‹ˆ๋‹ค.

์ด์— ๋™๋„คํƒญ์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ๋ฐœ์ƒํ–ˆ๋˜ ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ
์ƒ๊ฐํ•˜๋ฉด์„œ ์žฌํ˜„์„ ํ•ด๋ณด์•˜๋”๋‹ˆ
๋™์ผํ•œ ์˜ค๋ฅ˜ ์žฌํ˜„์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๐Ÿ› ์—๋Ÿฌ ๋‚ด์šฉ

  • ์œ ์ €๊ฐ€ ๋งต์— ์ง„์ž…ํ–ˆ์„ ๋•Œ ์ตœ์ดˆ๋กœ ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ค๊ณ  > ํ•ด๋‹น ์œ„์น˜๋กœ ์ด๋™์‹œ์ผœ์•ผ ํ•จ
  • ์ด ๋•Œ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ GPS ์„ค์ •์ด ์•ˆ ๋˜์–ด ์žˆ์–ด์„œ ์—๋Ÿฌ ๋ฐœ์ƒ

๐Ÿ’ซ ํ•ด๊ฒฐ ํ”„๋กœ์„ธ์Šค

  • ์œ„์น˜ ๊ถŒํ•œ์„ ์ƒํƒœ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • GPS ๊ถŒํ•œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํŠธ๋ž˜ํ‚น (on, off)
  • ๊ถŒํ•œ์ด ์—†์„ ๋•Œ GPS๋ฅผ ์‹œ์Šคํ…œ์ ์œผ๋กœ ์š”์ฒญํ•˜์—ฌ on, off ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌ
  • ํ•ด๊ฒฐ ๊ฒฐ๊ณผ

โš™๏ธ ์œ„์น˜ ๊ถŒํ•œ์„ ์‹œ์Šคํ…œ์ ์œผ๋กœ ์š”์ฒญํ•˜์—ฌ on, off

  • LocationRequest์„ ํ†ตํ•ด API ์„ค์ •
  • ์œ„์น˜๊ด€๋ จ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ๊ธ€ API > SettingClicent ํ• ๋‹น
  • LocationSettingsRequest ์„ค์ •
  • fail Listener๋ฅผ ์„ค์ •ํ•˜์—ฌ ResolvableApiException ์œผ๋กœ intentSenderRequest ์–ป๊ธฐ
    - intentSenderRequest ๋ฅผ ํ†ตํ•ด์„œ launcher ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ

requestGPS ํ˜ธ์ถœ ๋ถ€

  • ์œ„์น˜ ๊ถŒํ•œ ํผ๋ฏธ์…˜ ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•จ์— ๋”ฐ๋ผ ํƒ์ง€ํ•˜์—ฌ ์œ„์น˜ ์„ค์ •์ด ์•ˆ ๋์„ ๊ฒฝ์šฐ ์‹œ์Šคํ…œ ์š”์ฒญ
  • ์œ ์ €๊ฐ€ ํŒ์—…์—์„œ ์„ ํƒํ•œ ๊ฒฐ๊ณผ๋ฅผ grantedGPS์— ์ €์žฅ



๐Ÿ‘€ GPS ์„ค์ •์—ฌ๋ถ€ ํ™•์ธ (Feat. GNSS)

์œ ์ €๊ฐ€ ์‹œ์Šคํ…œ์ ์œผ๋กœ '์œ„์น˜' ๋ฅผ
offํ•œ ๊ฒฝ์šฐ ๊ถŒํ•œ ์š”์ฒญ์„ ์œ„ํ•ด
ํŠธ๋ž˜ํ‚น์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋Š” GPS Listener๋ฅผ ํ†ตํ•ด
์„ค์ • ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ
ํ˜„์žฌ Deprecated ๋˜์–ด
GNSS Listener๋กœ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก GNSS ๋ž€
Global Navigation Satellite System ์˜ ์•ฝ์–ด์ด๋ฉฐ
๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด GPS ๋Š” ๋ฏธ๊ตญ ์œ„์„ฑ์ธ๋ฐ
๋ฏธ๊ตญ ์™ธ์— ์ค‘๊ตญ, ๋Ÿฌ์‹œ์•„ ์œ ๋Ÿฝ ๋“ฑ ์œ„์„ฑ์„ ๋„์šฐ๋ฉด์„œ
์ด๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ๋ช…์นญ์œผ๋กœ GNSS ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋Š” GNSS Callback ์„
Flow๋กœ ๋ณ€ํ™˜ํ•œ ๋กœ์ง์ž…๋‹ˆ๋‹ค.

flow ๋กœ ๋ณ€ํ™˜๋œ ๋กœ์ง์€
์•„๋ž˜์˜ LaunchedEffect ์—์„œ
observing ํ•˜๋Š” ๋กœ์ง์œผ๋กœ
์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์„ค๋ช…ํ•œ GNSS ๋ฐ SettingClient API๋ฅผ ํ†ตํ•ด
์‚ฌ์šฉ์ž๊ฐ€ '์œ„์น˜' ๋ฅผ ์‹œ์Šคํ…œ์ ์œผ๋กœ on,off ํ–ˆ์„ ๋•Œ
ํŠธ๋ž˜ํ‚นํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€
๊ณต์œ  ํ–ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ‘‹๐Ÿป ํฌ์ŠคํŒ…์„ ๋งˆ์น˜๋ฉฐ

์ปดํฌ์ฆˆ ๊ตฌ๊ธ€๋งต์„ ๊ฒ€ํ† ํ•˜๊ณ  ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ
๋ถˆ์•ˆ์ •ํ•˜๊ฑฐ๋‚˜ ๋ฏธ ๊ตฌํ˜„๋œ ๋ถ€๋ถ„๋“ค์„
์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€์— ์ตœ๋Œ€ํ•œ ์ดˆ์ ์„ ๋งž์ถฐ์„œ
๊ณต์œ  ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๋™๋„คํƒญ์€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด๋ผ
์•ž์œผ๋กœ๋„ ๋งŽ์€ ํ™•์žฅ๊ณผ ์ˆ˜์ •์ด
์ด๋ค„์งˆ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. (๋‘๊ทผ๋‘๊ทผ ๐Ÿคฃ)

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ๋˜์–ด
๊ตฌ์กฐ์ ์ธ ์ธก๋ฉด์œผ๋กœ ๊น”๋”ํ•˜์ง€ ์•Š์€๋ฐ
๋” ์ปค์ง€๊ธฐ ์ „์— ๊ตฌ์กฐ์ ์œผ๋กœ
๋ฆฌํŒฉํ† ๋ง๋„ ์ง„ํ–‰ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
(ํ•ด์•ผํ•  ์ผ์ด ์‚ฐ๋”๋ฏธ๋ผ์„œ ์ข‹์Šต๋‹ˆ๋‹ค ๐Ÿคฎ)

์ด์ƒ ๋งˆ์ผ“์— ๋ฐฐํฌ๋˜๊ณ  ์šด์˜๋˜๊ณ  ์žˆ๋Š”
์ปดํฌ์ฆˆ ๊ตฌ๊ธ€๋งต ์‹คํ–‰ ํŒŒ์ผ์„ ์˜ฌ๋ฆฌ๋ฉด์„œ
ํฌ์ŠคํŒ…์„ ๋งˆ์น˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ™‡๐Ÿปโ€โ™‚๏ธ

profile
๊ณต๋ถ€ํ•˜๋Š” ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด