Android Intent (인텐트)

홍성덕·2024년 9월 18일

Intent(인텐트)는 다른 앱 컴포넌트(Activity, Service, BroadcastReceiver)에 작업을 요청할 때 사용할 수 있는 메시징 객체(messaging object)이다.

인텐트 타입

명시적 인텐트 (Explicit intents)

명시적 인텐트는 어떤 어플리케이션의 어떤 컴포넌트가 인텐트를 처리할 것인지 컴포넌트 이름을 명시적으로 지정하는 방식이다. 앱 내의 컴포넌트 이름(클래스명)은 명확하게 알고 있기 때문에 보통 앱 내에서 컴포넌트를 시작할 때 사용한다. 예를 들어 사용자의 액션에 반응하여 새로운 액티비티를 시작하거나, 백그라운드에서 파일을 다운로드 받기 위해 서비스를 시작하는 예시가 있다.

암시적 인텐트 (Implicit intents)

암시적 인텐트는 특정 컴포넌트를 지정하지 않고, 대신 수행할 일반적인 작업(action)을 선언하여 다른 앱의 컴포넌트가 이를 처리할 수 있도록 하는 방식이다. 예를 들어 지도에서 사용자의 위치를 표시하고 싶을 때, 암시적 인텐트를 사용하여 다른 지도 앱을 통해 사용자의 위치를 표시할 수 있다.

인텐트 동작 방식

위 그림은 액티비티의 시작 예시인데, Activity A가 인텐트 객체를 시스템에 전달하며, 시스템은 이 인텐트를 Activity B에 전달한다. 명시적 인텐트라면 보통 Activity B가 앱 내에 있는 또다른 액티비티일 것이고, 암시적 인텐트라면 보통 Activity B가 다른 앱에 있는 액티비티일 것이다.

하지만 명시적 인텐트와 암시적 인텐트는 시스템에서 처리되는 방식에 차이가 있다.

명시적 인텐트를 사용하는 경우, 시스템은 즉시 해당 컴포넌트를 시작하고 인텐트 객체를 전달한다. 특정 컴포넌트의 이름이 명확하게 지정되어 있기 때문에 암시적 인텐트처럼 추가적인 검색 과정이 필요 없다.

암시적 인텐트를 사용하는 경우, 시스템은 인텐트의 내용을 기기에 설치된 다른 앱의 매니페스트 파일에 선언된 인텐트 필터와 비교하여 적절한 컴포넌트를 찾는다. 적절한 컴포넌트를 발견하면 시스템은 해당 컴포넌트를 시작하고 인텐트 객체를 전달한다. 여러 개의 인텐트 필터가 호환되는 경우 시스템은 사용자에게 어느 앱을 사용할 것인지 선택할 수 있는 대화 상자를 표시한다.

인텐트 필터란?

인텐트 필터는 앱의 매니페스트 파일에 선언된 표현식으로, 해당 컴포넌트가 수신하고자 하는 인텐트 유형을 지정합니다. 예를 들어, 액티비티에 대해 인텐트 필터를 선언하면, 다른 앱에서 특정 종류의 인텐트를 사용하여 해당 액티비티를 시작할 수 있다. 반대로, 액티비티에 대해 인텐트 필터를 선언하지 않으면 명시적 인텐트로만 시작할 수 있다.
즉 암시적 인텐트를 사용하여 컴포넌트를 시작하려면, 매니페스트 파일에서 실행하려는 컴포넌트에 인텐트 필터가 선언되어 있어야 한다는 의미이다.

인텐트 사용 사례

가장 기본적인 3가지 사용 사례가 존재한다.

1. 액티비티(Activity) 시작

가장 흔히 사용하는 사례이다. startActivity()를 통해서 인텐트를 시스템에 전달하여 새로운 액티비티를 시작할 수 있다.

// 명시적 인텐트
startActivity(Intent(context, ImageDetailActivity::class.java))

// 암시적 인텐트
val intent = Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("https://www.naver.com")
}
startActivity(intent)

위의 예시에서 명시적 인텐트는 앱 내의 ImageDetailActivity를 실행할 것이다. 하지만 암시적 인텐트에는 컴포넌트 이름이 명확히 지정되어 있지 않고 대신 Intent.ACTION_VIEW로 액션을 열고자 하는 웹 페이지의 URL을 지정하였다. 그러면 시스템은 해당 인텐트와 다른 앱 매니페스트 파일에 선언된 인텐트 필터와 비교하여 다른 앱의 컴포넌트를 실행할 것이다. 여러 개의 인텐트 필터가 호환되는 경우 대화상자를 표시하여 선택을 요구할 것이다.
위 예시의 경우 브라우저 앱을 실행할 것이고, 기기에는 보통 기본 브라우저 앱이 설정되어 있기 때문에 기본 브라우저 앱으로 웹 페이지가 열릴 것이다.

2. 서비스(Service) 시작

서비스는 유저 인터페이스(UI) 없이 백그라운드에서 작업을 수행하는 컴포넌트이다. 음악 재생, 파일 다운로드 등의 예시가 있다.

// 명시적 인텐트
startService(Intent(this, MusicService::class.java))

안드로이드 공식 가이드에서는 암시적 인텐트를 사용하여 서비스를 시작하는 것은 보안상 위험하므로 명시적 인텐트를 사용하라고 권장한다. 이유가 무엇일까?

서비스 시작 시 암시적 인텐트를 사용한다면 시스템은 여러 앱 중 해당 작업을 수행할 수 있는 Service를 찾아서 시작할 것이다. 그러면 원치 않는 Service가 실행될 위험이 있다. 그리고 서비스는 UI를 가지고 있지 않은 컴포넌트이기 때문에 사용자 입장에서도 어떤 서비스가 시작되는지 명확하게 알 수 없다.
그래서 명시적 인텐트를 사용하여 서비스를 시작하여, 다른 앱의 서비스 컴포넌트가 인텐트 객체를 가로챌 위험을 없애야 한다.

3. 브로드캐스트 전달

브로드캐스트(Broadcast)는 어떤 앱이든 수신할 수 있는 메시지이다. 보통 시스템 부팅 또는 장치 충전 시작과 같은 시스템 이벤트에 대한 브로드캐스트를 많이 떠올리는데, 안드로이드 앱에서도 브로드캐스트 메시지를 전달할 수 있다. sendBroadcast() 또는 sendOrderedBroadcast()에 인텐트를 전달하여 다른 앱에 브로드캐스트를 전달할 수 있다.

// 명시적 인텐트
sendBroadcast(Intent(this, MyBroadcastReceiver::class.java))

// 암시적 인텐트
Intent().also { intent ->
    intent.setAction("com.example.broadcast.MY_NOTIFICATION")
    intent.putExtra("data", "Nothing to see here, move along.")
    sendBroadcast(intent)
}

사실 BroadcastReceiver로 시스템 이벤트를 받아서 처리한 적은 있는데 직접 브로드캐스트를 전달한 적은 없어서 위의 예시가 맞는 건지 정확히는 모르겠다. 혹시라도 나중에 예시가 부적절하다는 것을 알게 되면 수정할 예정이다.


참고자료

profile
안드로이드 주니어 개발자

0개의 댓글