아래 내용은 네이버 지도 앱으로 특정 위치(좌표)를 표시하려는 기능을 구현하는 과정에서 발생한 문제와, 이를 해결하는 과정을 정리한 글입니다.
기존 코드는 다음과 같은 방식으로, 기기에 런처 아이콘이 있는 앱들을 전부 조회(queryIntentActivities)한 뒤,
결과 목록이 비어 있으면 “네이버 지도 설치 필요”로 판단하여 마켓으로 이동하고,
그렇지 않으면 “네이버 지도 실행”을 시도했습니다.
val installCheck = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
)
} else {
context.packageManager.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.GET_META_DATA
)
}
if (installCheck.isEmpty()) {
// 네이버 지도 없다고 판단 → 플레이스토어
} else {
// 네이버 지도 있다고 판단 → 인텐트 실행
}
문제는 실제로 네이버 지도 앱이 삭제되었는데도 installCheck 결과가 비어 있지 않은 경우가 발생한다는 점이었습니다.
예를 들어, 런처에 존재하는 다른 앱들(카메라, 갤러리 등)이 목록에 남아서 “목록이 비어 있지 않다”고 판단되어,
실제로는 네이버 지도가 없는데도 네이버 지도 인텐트를 실행하려고 시도하면서 앱이 강제 종료되는 이슈가 생겼습니다.
문제를 근본적으로 해결하기 위해, 특정 패키지(네이버 지도)가 존재하는지를 직접 확인하도록 코드를 수정했습니다.
안드로이드에서는 특정 패키지가 설치되어 있는지 판단하려면 PackageManager.getPackageInfo (또는 안드로이드 13 이상의 getPackageInfo(packageName, PackageManager.PackageInfoFlags))를 사용하는 것이 가장 간단하다고하여 사용했습니다.
수정된 코드
private fun openPlaceNaverMap(
latitude: Double,
longitude: Double,
placeName: String,
context: Context
) {
val url = "nmap://place?lat=$latitude&lng=$longitude&name=$placeName&appname=${context.packageName}"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
addCategory(Intent.CATEGORY_BROWSABLE)
}
// 1) "com.nhn.android.nmap" 패키지 존재 여부 확인
val isInstalled = try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.getPackageInfo(
"com.nhn.android.nmap",
PackageManager.PackageInfoFlags.of(0)
)
} else {
@Suppress("DEPRECATION")
context.packageManager.getPackageInfo("com.nhn.android.nmap", 0)
}
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
// 2) 설치되어 있지 않다면 → Play 스토어로 이동
if (!isInstalled) {
val marketIntent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("market://details?id=com.nhn.android.nmap")
}
context.startActivity(marketIntent)
} else {
// 3) 설치되어 있다면 → 네이버 지도 앱 실행
context.startActivity(intent)
}
}
try 구문 안에서 getPackageInfo("com.nhn.android.nmap", 0)를 호출했을 때 NameNotFoundException이 발생하지 않으면(= 앱이 존재) true, 예외가 발생하면(= 앱이 설치되지 않음) false를 반환합니다.
그 결과에 따라 Play 스토어로 이동할지, 네이버 지도 앱을 실행할지를 나눠 처리할 수 있습니다.
네이버 지도 스킴(nmap://place)으로 장소 정보를 담은 Intent를 준비한다.
getPackageInfo로 네이버 지도 패키지(com.nhn.android.nmap)의 설치 여부를 판단한다.
설치되어 있다면 → 해당 Intent를 통해 네이버 지도 앱을 실행한다.
설치되어 있지 않다면 → Play 스토어(또는 마켓)으로 이동하여 앱 설치를 유도한다.
queryIntentActivities는 런처 아이콘이 있는 모든 앱을 가져오는 로직이므로, 앱이 “삭제”되었음에도 다른 앱들로 인해 리스트가 비어있지 않아 오탐 발생.
특정 패키지명(com.nhn.android.nmap)을 직접 getPackageInfo로 조회하여, 앱 설치 여부를 정확히 판단.
“런처 아이콘 조회” 대신 “패키지명 조회” 를 통해, 네이버 지도 존재 여부를 명확히 체크해야 한다.
이렇게 코드를 바꾸면, 실제로 네이버 지도 앱이 삭제된 경우에는 즉시 예외가 발생해 “앱이 없다”고 올바르게 판단하며, 강제 종료 없이 플레이스토어로 안전하게 이동할 수 있습니다.
이 방법은 네이버 지도뿐 아니라 특정 패키지가 설치되어 있는지 확인할 때도 동일하게 사용할 수 있어,
스킴 호출 전에 반드시 앱 설치 여부를 체크해야 하는 로직에 유용합니다.