목차
- 새 프로젝트 생성
- 이름: Find me
- 패키지: com.example.findme
- EmptyViewsActivity로 생성하고 모듈 build.gradle.kts에 View Binding 적용
- 생성된 MainActivity에도 ViewBinding 적용
Android application의 권한
- Application이 제한된 데이터에 접근하거나 제한된 동작을 해야 하는 경우 권한 (Permission)을 획득해야 한다.
- 단, 묵시적 Intent를 이용해 다른 앱을 통해 해당 동작을 할 경우 권한 요청은 해당 앱이 처리해야 하며 내 앱이 직접 권한을 얻을 필요는 없다.
- 내 어플에서 카메라 권한을 받지않고 설치되어져 있는 카메라 어플은 이미 “카메라”권한을 받았기 때문에 해당 어플에게 요청을 하고 나는 받기만 하면된다.
- 사진, 동영상 촬영, 음성인식 등은 특별한 이유가 없다면 해당 앱에게 요청하는 것이 편하다.
- 권한의 종류
- 설치 시간 권한(Normal Permissions): 사생활과 관련 없고 다른 앱에게 미치는 영향이 적은 권한. AndroidManifest.xml에 선언하며 앱이 설치되면 자동으로 권한이 부여된다.
- 런타입 권한(Dangerous Permissions): 위험한 권한 사생활 정보에 접근하거나 다른 앱의 실행에 영향을 끼칠 수 있는 권한. 선언도 하고 사용자에게 직접 권한을 부여받아야 한다.
- 예 ) 위치, 파일, 캘린더, 주소록
- 한 번 부여한 권한이라도 사용자가 설정 메뉴에서 취소할 수 있기 때문에 관련 기능을 사용하기 전에는 항상 권한 획득 여부를 확인해야 한다.
- API version 23 미만의 운영체제는 위험한 권한도 선언만으로 사용할 수 있다. version 23부터는 실시간 확인이 필요하다.
일반 권한과 위험 권한
- Android에 정의 된 권한 리스트는 위 링크 참조
- 위 API 정보 상에 Protection level: dangerous 로 표기된 항목이 위험한 권한.
- 예) 사용자의 위치 정보, 연락처 정보 등 개인 정보와 다른 앱의 실행에 관여할 수 있는 권한들

UI 작업
- activity_main.xml
- 전체 사이즈의 WebView
- 아이디는 webView

MainActivity
package com.lunadev.findme
import android.os.Bundle
import android.webkit.WebViewClient
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.lunadev.findme.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.webView.webViewClient = WebViewClient()
binding.webView.settings.javaScriptEnabled = true
binding.webView.loadUrl("<https://www.google.co.kr/maps/?hl=ko>")
}
}
Permissons - Internet
- Internet Permission이 없으면 인터넷 기능이 불가능
- AndroidManifest.xml에 다음 문구를 추가하고 다시 실행
- INTERNET은 Normal Permission이다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
....


Location
- Dangerous Permission
- Foreground: Activity가 화면에 출력되는 동안 위치 정보가 필요할 때. 한 번만 또는 정해진 시간 동안만 필요할 때. 현재 위치 표시
- Background: 앱이 지속적으로 사용자 위치를 파악해야 할 때. 예를 들어 가족 위치 공유 앱, IoT 앱에서 사용자가 집을 나가는지 확인, 주변 장소 추천 등
- 정밀도
- Coarse Location: 대략적인 위치. 3km 이내.
- Fine Location: 정밀한 위치. 50m 이내. coarse location과 함께 요청해야 함.
권한 설정 추가
- AndroidManifest.xml에 다음 항목 추가
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
...
위치 권한을 요청받아 해당 위치를 지도에 표시
package com.lunadev.findme
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import android.webkit.WebViewClient
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.lunadev.findme.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
// 권한 신청
private val requestPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()) { // 하나의 권한을 신청한다
if (it) getLocation() // 허락했을 경우 it이 true 반환됨
}
private fun getLocation() {
// 특별한 구글 API key 없이 Device의 기본 기능을 이용해 위치 정보를 얻음
if (PackageManager.PERMISSION_GRANTED == checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)) {
val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
val provider = LocationManager.GPS_PROVIDER
val location = locationManager.getLastKnownLocation(provider)
if (location != null) {
displayLocation(location)
}
locationManager.requestLocationUpdates(provider, 3000L, 100f) { result ->
displayLocation(result)
}
}
}
private fun displayLocation(location: Location) { // 특별한 구글 API Key없이 Url의 query String을 통해 화면에 표시해보기
val latitude = location.latitude
val longitude = location.longitude
Log.d("MyLocation", "latitude: $latitude, longitude: $longitude")
val url = "<https://www.google.co.kr/maps/?hl=ko&q=$latitude,$longitude>"
binding.webView.loadUrl(url);
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.webView.webViewClient = WebViewClient()
binding.webView.settings.javaScriptEnabled = true
binding.webView.loadUrl("<https://www.google.co.kr/maps/?hl=ko>")
// 내 권한 확인
if(PackageManager.PERMISSION_GRANTED !=
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)){
requestPermission.launch(android.Manifest.permission.ACCESS_COARSE_LOCATION)
} else {
getLocation()
}
}
}
- 위험 권한은 사용할 때마다 권한을 확인해야 하며 필요하면 요청해야한다.


- 새 프로젝트 생성
- 이름: Find me
- 패키지: com.example.findme
- EmptyViewsActivity로 생성하고 모듈 build.gradle.kts에 View Binding 적용
- 생성된 MainActivity에도 ViewBinding 적용
Android application의 권한
- Application이 제한된 데이터에 접근하거나 제한된 동작을 해야 하는 경우 권한 (Permission)을 획득해야 한다.
- 단, 묵시적 Intent를 이용해 다른 앱을 통해 해당 동작을 할 경우 권한 요청은 해당 앱이 처리해야 하며 내 앱이 직접 권한을 얻을 필요는 없다.
- 내 어플에서 카메라 권한을 받지않고 설치되어져 있는 카메라 어플은 이미 “카메라”권한을 받았기 때문에 해당 어플에게 요청을 하고 나는 받기만 하면된다.
- 사진, 동영상 촬영, 음성인식 등은 특별한 이유가 없다면 해당 앱에게 요청하는 것이 편하다.
- 권한의 종류
- 설치 시간 권한(Normal Permissions): 사생활과 관련 없고 다른 앱에게 미치는 영향이 적은 권한. AndroidManifest.xml에 선언하며 앱이 설치되면 자동으로 권한이 부여된다.
- 런타입 권한(Dangerous Permissions): 위험한 권한 사생활 정보에 접근하거나 다른 앱의 실행에 영향을 끼칠 수 있는 권한. 선언도 하고 사용자에게 직접 권한을 부여받아야 한다.
- 예 ) 위치, 파일, 캘린더, 주소록
- 한 번 부여한 권한이라도 사용자가 설정 메뉴에서 취소할 수 있기 때문에 관련 기능을 사용하기 전에는 항상 권한 획득 여부를 확인해야 한다.
- API version 23 미만의 운영체제는 위험한 권한도 선언만으로 사용할 수 있다. version 23부터는 실시간 확인이 필요하다.
일반 권한과 위험 권한
- Android에 정의 된 권한 리스트는 위 링크 참조
- 위 API 정보 상에 Protection level: dangerous 로 표기된 항목이 위험한 권한.
- 예) 사용자의 위치 정보, 연락처 정보 등 개인 정보와 다른 앱의 실행에 관여할 수 있는 권한들

UI 작업
- activity_main.xml
- 전체 사이즈의 WebView
- 아이디는 webView

MainActivity
package com.lunadev.findme
import android.os.Bundle
import android.webkit.WebViewClient
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.lunadev.findme.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.webView.webViewClient = WebViewClient()
binding.webView.settings.javaScriptEnabled = true
binding.webView.loadUrl("<https://www.google.co.kr/maps/?hl=ko>")
}
}
Permissons - Internet
- Internet Permission이 없으면 인터넷 기능이 불가능
- AndroidManifest.xml에 다음 문구를 추가하고 다시 실행
- INTERNET은 Normal Permission이다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
....


Location
- Dangerous Permission
- Foreground: Activity가 화면에 출력되는 동안 위치 정보가 필요할 때. 한 번만 또는 정해진 시간 동안만 필요할 때. 현재 위치 표시
- Background: 앱이 지속적으로 사용자 위치를 파악해야 할 때. 예를 들어 가족 위치 공유 앱, IoT 앱에서 사용자가 집을 나가는지 확인, 주변 장소 추천 등
- 정밀도
- Coarse Location: 대략적인 위치. 3km 이내.
- Fine Location: 정밀한 위치. 50m 이내. coarse location과 함께 요청해야 함.
권한 설정 추가
- AndroidManifest.xml에 다음 항목 추가
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
...
위치 권한을 요청받아 해당 위치를 지도에 표시
package com.lunadev.findme
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import android.webkit.WebViewClient
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.lunadev.findme.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
// 권한 신청
private val requestPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()) { // 하나의 권한을 신청한다
if (it) getLocation() // 허락했을 경우 it이 true 반환됨
}
private fun getLocation() {
// 특별한 구글 API key 없이 Device의 기본 기능을 이용해 위치 정보를 얻음
if (PackageManager.PERMISSION_GRANTED == checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)) {
val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
val provider = LocationManager.GPS_PROVIDER
val location = locationManager.getLastKnownLocation(provider)
if (location != null) {
displayLocation(location)
}
locationManager.requestLocationUpdates(provider, 3000L, 100f) { result ->
displayLocation(result)
}
}
}
private fun displayLocation(location: Location) { // 특별한 구글 API Key없이 Url의 query String을 통해 화면에 표시해보기
val latitude = location.latitude
val longitude = location.longitude
Log.d("MyLocation", "latitude: $latitude, longitude: $longitude")
val url = "<https://www.google.co.kr/maps/?hl=ko&q=$latitude,$longitude>"
binding.webView.loadUrl(url);
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.webView.webViewClient = WebViewClient()
binding.webView.settings.javaScriptEnabled = true
binding.webView.loadUrl("<https://www.google.co.kr/maps/?hl=ko>")
// 내 권한 확인
if(PackageManager.PERMISSION_GRANTED !=
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)){
requestPermission.launch(android.Manifest.permission.ACCESS_COARSE_LOCATION)
} else {
getLocation()
}
}
}
- 위험 권한은 사용할 때마다 권한을 확인해야 하며 필요하면 요청해야한다.

