안드로이드 인텐트(Intent)와 컴포넌트 간 통신
안드로이드 인텐트(Intent)와 컴포넌트 간 통신
안드로이드에서 Intent란 수행할 작업을 기술하는 메시징 객체입니다. 같은 프로세스 내의 컴포넌트든, 전혀 다른 애플리케이션에 속한 컴포넌트든, Intent는 이들 사이의 통신을 담당하는 핵심 메커니즘 역할을 합니다. Intent에는 수행할 액션(action)과 해당 액션이 대상으로 하는 데이터가 함께 포함되며, 시스템은 이 정보를 바탕으로 어떤 컴포넌트가 요청을 처리해야 하는지 결정합니다.
안드로이드의 4대 컴포넌트(Activity, Service, BroadcastReceiver, ContentProvider) 사이의 통신 대부분이 Intent를 통해 이루어지므로, 인텐트의 동작 원리를 정확히 이해하는 것은 안드로이드 개발자에게 매우 중요합니다. 이 챕터를 학습하고 나면 다음 내용을 명확하게 설명할 수 있게 됩니다.
- 안드로이드 컴포넌트 기반 아키텍처에서
Intent가 수행하는 역할 - 명시적(explicit)
Intent와 암시적(implicit)Intent의 차이점 및 컴포넌트 해석 방식 - 시스템이 인텐트 필터(intent filter)를 활용하여 암시적
Intent를 해석하는 과정 Intent가 extras, URI, 카테고리를 통해 전달할 수 있는 데이터의 종류Intent기반 통신의 보안 모범 사례(best practices)
명시적 인텐트(Explicit Intent)와 직접 컴포넌트 지정
명시적 Intent는 대상 클래스 이름을 직접 지정하여, 어떤 컴포넌트가 처리해야 하는지 명확하게 선언합니다. 호출자가 이미 목적지를 특정했으므로 시스템이 별도로 매칭 컴포넌트를 탐색할 필요가 없습니다.
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("item_id", 42)
startActivity(intent)
생성자에 Context와 Class를 전달하면 내부적으로 ComponentName이 설정됩니다. 시스템은 이 컴포넌트 이름을 읽어 매니페스트에서 해당 Activity를 찾은 뒤 곧바로 시작합니다. 별도의 해석(resolution) 단계를 거치지 않으므로 동작이 빠르고 예측 가능합니다.
명시적 Intent는 단일 애플리케이션 내에서 Activity 간 내비게이션을 처리하는 표준 메커니즘입니다. 호출자가 대상을 직접 지정하기 때문에 어떤 컴포넌트가 요청을 처리할지에 대한 모호함이 전혀 없습니다. 반면, 다른 애플리케이션의 정확한 클래스 이름을 알아야만 앱 경계를 넘을 수 있는데, 이는 현실적으로 어렵고 두 앱을 강하게 결합시키는 원인이 됩니다. 따라서 외부 앱과의 통신에는 뒤에서 살펴볼 암시적 Intent를 활용하는 것이 일반적입니다.
암시적 인텐트(Implicit Intent)와 인텐트 해석
암시적 Intent는 특정 컴포넌트를 지정하지 않습니다. 대신 수행할 **액션(action)**을 선언하고, 선택적으로 데이터, MIME 타입, 카테고리 정보를 포함합니다. 시스템은 설치된 모든 애플리케이션의 매니페스트에 선언된 인텐트 필터를 검사하여 매칭되는 컴포넌트를 찾습니다.
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://developer.android.com")
startActivity(intent)
해석 과정은 세 가지 요소를 기준으로 매칭합니다. 첫째, 액션 문자열이 인텐트 필터에 나열된 액션 중 하나와 일치해야 합니다. 둘째, 데이터 URI의 스킴(scheme), 호스트(authority), 경로(path)가 필터의 데이터 사양과 일치해야 합니다. 셋째, 카테고리가 필터에 포함되어 있어야 하며, startActivity()에 전달되는 모든 암시적 Intent에는 CATEGORY_DEFAULT가 자동으로 추가됩니다.
매칭되는 컴포넌트가 여러 개인 경우, 시스템은 사용자가 원하는 앱을 선택할 수 있도록 선택기(chooser) 다이얼로그를 표시합니다. 매칭되는 컴포넌트가 하나도 없으면 ActivityNotFoundException이 발생합니다. startActivity() 호출 전에 resolveActivity()로 사전 검사를 수행하면 이러한 크래시를 방지할 수 있습니다.
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "Hello")
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}