[Android Intent] 외부 앱 실행 실패 시 Play Store로 보내는 fallback 설계
Android 앱에서 지도앱, 전화앱, 브라우저, Play Store 같은 외부 앱을 실행해야 하는 경우가 있습니다. 길찾기 버튼을 누르면 지도앱을 열고, 고객센터 번호를 누르면 전화앱을 열고, 외부 링크는 브라우저로 연결하는 식입니다.
이때 해당 앱이 설치되어 있다는 가정을 하면 안 됩니다. 사용자의 기기에는 카카오맵이 없을 수도 있고, 특정 브라우저가 비활성화되어 있을 수도 있습니다. Play Store 앱이 없는 환경도 있을 수 있습니다.
그래서 외부 Intent를 실행하기 전에는 처리 가능한 앱이 있는지 확인하고, 실패했을 때 어떤 fallback을 보여줄지 정해야 합니다. 외부 앱 연동은 버튼 하나처럼 보이지만, 실제로는 설치 여부, 스킴 검증, 사용자 안내까지 함께 설계해야 하는 기능입니다.
이 글에서는 Android 앱에서 외부 앱을 실행할 때 확인하면 좋은 기준을 정리해보겠습니다. 외부 앱 연동을 구현할 때 놓치기 쉬운 Intent 검증, fallback, Play Store 이동, 사용자 안내 기준을 중심으로 살펴보겠습니다.
왜 fallback 설계가 필요한가
외부 앱 실행은 앱 내부 화면 이동보다 변수가 많습니다. 설치 여부, OS 버전, 기본 앱 설정, URI 형식, 스킴 허용 여부에 따라 결과가 달라질 수 있습니다.
예외 처리가 없으면 버튼을 눌렀을 때 앱이 종료되거나 아무 반응이 없는 것처럼 보일 수 있습니다. 사용자 입장에서는 기능이 없는 것인지, 앱이 고장난 것인지 구분하기 어렵죠.
| 상황 | 문제 | fallback 방향 |
|---|---|---|
| 지도앱 미설치 | 길찾기 실행 실패 | Play Store 또는 웹 지도 안내 |
| 스킴 오류 | 잘못된 앱 실행 시도 | 허용된 스킴만 실행 |
| 브라우저 없음 | 외부 링크 열기 실패 | 사용자 안내 메시지 |
| 마켓 앱 없음 | Play Store 실행 실패 | 웹 Play Store URL fallback |
막상 구현 흐름을 따라가다 보면 외부 앱 실행은 성공 케이스보다 실패 케이스가 더 중요해집니다. 개발 기기에서는 필요한 앱이 모두 설치되어 있어 잘 동작해도, 실제 사용자 기기에서는 전혀 다른 결과가 나올 수 있습니다.
Intent 실행 전 확인할 것
핵심은 임의 스킴을 그대로 실행하지 않는 것입니다. 앱 내부에서 만든 버튼이라도 값이 서버나 웹뷰에서 내려온다면 반드시 검증해야 합니다.
아래 코드는 외부 앱을 실행하기 전에 허용된 스킴인지 확인하고, 처리 가능한 앱이 없을 때 fallback을 시도하는 예시입니다.
fun openExternalApp(context: Context, uriText: String, marketUrl: String) {
val uri = Uri.parse(uriText)
val allowedSchemes = setOf("https", "kakaomap", "nmap", "market")
if (uri.scheme !in allowedSchemes) {
Toast.makeText(context, "지원하지 않는 링크입니다.", Toast.LENGTH_SHORT).show()
return
}
val intent = Intent(Intent.ACTION_VIEW, uri)
val canOpen = intent.resolveActivity(context.packageManager) != null
if (canOpen) {
context.startActivity(intent)
return
}
val fallbackIntent = Intent(Intent.ACTION_VIEW, Uri.parse(marketUrl))
if (fallbackIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(fallbackIntent)
} else {
Toast.makeText(context, "실행할 수 있는 앱이 없습니다.", Toast.LENGTH_SHORT).show()
}
}
예제에서는 resolveActivity()로 처리 가능한 앱이 있는지 확인합니다. 그리고 실행 가능한 앱이 없으면 marketUrl을 이용해 fallback을 시도합니다.
실제 구현에서는 Android 패키지 가시성 정책도 함께 확인해야 할 수 있습니다. 특히 target SDK에 따라 외부 앱 조회가 제한될 수 있으므로, 필요한 경우 AndroidManifest에 <queries> 설정을 추가해야 합니다.
허용할 스킴을 제한해야 하는 이유
외부 링크나 스킴이 서버, 웹뷰, 원격 설정에서 들어온다면 더 조심해야 합니다. 임의의 URI를 그대로 startActivity()에 넘기면 의도하지 않은 앱 실행이나 위험한 경로 접근으로 이어질 수 있습니다.
| 스킴 | 사용 예시 | 주의점 |
|---|---|---|
https |
브라우저, 웹 지도, 정책 페이지 | 허용 도메인 검토 필요 |
tel |
전화 앱 실행 | 전화번호 형식 검증 필요 |
market |
Play Store 이동 | 웹 Play Store fallback 필요 |
kakaomap, nmap |
지도앱 실행 | 미설치 fallback 필요 |
javascript, file |
일반 외부 실행에 부적합 | 차단하는 편이 안전 |
스킴 검증은 외부 앱 연동의 기본 안전장치입니다. 특히 웹뷰나 서버 응답에서 받은 링크라면 허용할 스킴과 도메인을 allowlist로 제한하는 편이 좋습니다.
Play Store fallback 기준
Play Store로 보내는 fallback은 편리하지만 모든 상황의 정답은 아닙니다. 사용자가 단순히 웹으로 볼 수 있는 정보라면 웹 fallback이 더 자연스러울 수 있습니다.
반대로 지도앱의 길찾기처럼 네이티브 앱 경험이 중요한 기능은 마켓 안내가 적절할 수 있습니다. 다만 사용자를 바로 마켓으로 보내기보다, 가능하면 확인 다이얼로그를 두는 편이 좋습니다.
| 기능 | 1차 실행 | fallback |
|---|---|---|
| 길찾기 | 설치된 지도앱 | Play Store 또는 웹 지도 |
| 외부 링크 | 브라우저 | 안내 메시지 또는 웹뷰 |
| 전화 걸기 | 전화 앱 | 전화번호 복사 안내 |
| 앱 리뷰 | market 스킴 |
웹 Play Store |
운영 관점에서는 사용자의 선택권도 중요합니다. 데이터 요금이 발생하거나 앱 설치가 필요한 흐름이라면 안내 없이 바로 이동시키기보다, 한 번 확인하고 이동하는 방식이 더 안정적입니다.
사용자 안내 문구
외부 앱 실행에 실패했을 때 오류라고만 보여주면 사용자는 무엇을 해야 할지 알기 어렵습니다. 가능하면 다음 행동을 예측할 수 있는 문구를 보여주는 편이 좋습니다.
- 실행하려는 앱이 설치되어 있지 않은지 안내한다.
- 스토어로 이동할지 사용자가 선택할 수 있게 한다.
- 웹에서 볼 수 있는 정보라면 웹 fallback을 제공한다.
- 전화 앱 실행 실패 시 전화번호 복사 같은 대체 행동을 제공한다.
- 책임을 사용자에게 돌리는 표현은 피한다.
예를 들어 지도앱이 없을 때는 아래처럼 안내할 수 있습니다.
지도앱이 설치되어 있지 않아 스토어로 이동할 수 있습니다.
스토어로 이동하시겠어요?
단순히 오류가 발생했다는 문구만 보여주면 사용자는 앱 문제인지, 외부 앱 문제인지 알기 어렵습니다. 외부 앱 연동에서는 실패 원인과 다음 행동을 함께 안내하는 것이 좋습니다.
테스트 기준
외부 앱 연동은 개발 기기에서 한 번 성공했다고 끝내기 어렵습니다. 설치 여부와 기본 앱 설정에 따라 결과가 달라지기 때문에 실패 케이스를 함께 확인해야 합니다.
- 처리 가능한 앱이 있을 때 정상적으로 외부 앱이 실행되는지 확인한다.
- 외부 앱이 설치되어 있지 않을 때 fallback이 동작하는지 확인한다.
- Play Store 앱이 없을 때 웹 URL fallback이 동작하는지 확인한다.
- 허용하지 않은 스킴은 실행하지 않고 안내 메시지를 보여주는지 확인한다.
- 전화 앱 실행 실패 시 전화번호 복사 같은 대체 흐름이 있는지 확인한다.
- 서버나 웹에서 받은 링크에 관리자 URL, 토큰, 내부 파라미터가 포함되지 않는지 확인한다.
- target SDK 기준으로 필요한
<queries>설정이 있는지 확인한다.
자주 하는 실수
1. startActivity()를 바로 호출하는 경우가 있습니다. 개발 기기에는 필요한 앱이 설치되어 있어서 잘 동작해도, 실제 사용자 기기에서는 실패할 수 있습니다.
2. 외부 링크를 그대로 실행하는 경우도 있습니다. javascript:, file:, 알 수 없는 커스텀 스킴까지 허용하면 위험할 수 있습니다. 허용할 스킴을 제한하는 편이 좋습니다.
3. Play Store fallback만 준비하는 경우가 있습니다. 일부 기기에서는 Play Store 앱을 사용할 수 없을 수 있으므로 웹 Play Store URL이나 안내 메시지도 함께 준비해야 합니다.
4. 실패 안내 문구가 너무 모호한 경우도 있습니다. 외부 앱이 없어서 실패한 것인지, 링크가 잘못된 것인지, 사용자가 무엇을 할 수 있는지 알려주는 편이 좋습니다.
결론
외부 앱 연동은 버튼 하나처럼 보이지만, 실제로는 설치 여부, 스킴 검증, fallback, 사용자 안내가 함께 필요한 기능입니다. 지도앱이나 마켓 이동처럼 앱 밖으로 나가는 흐름은 실패했을 때 사용자가 이해할 수 있는 안내까지 설계해야 합니다.
좋은 구조는 외부 Intent 실행 전에 허용된 스킴인지 확인하고, resolveActivity()로 처리 가능한 앱이 있는지 검사한 뒤, 실패 시 안전한 fallback을 제공하는 것입니다. Play Store 이동이 필요한 경우에도 마켓 앱이 없을 수 있으므로 웹 fallback까지 준비해두는 편이 좋습니다.
외부 앱 실행은 사용자의 기기 환경에 크게 영향을 받습니다. 정상 실행만 확인하기보다 앱 미설치, 잘못된 스킴, 브라우저 없음, 마켓 앱 없음 같은 실패 흐름을 함께 테스트해야 더 안정적인 사용자 경험을 만들 수 있습니다.