'Intent Filter'에 해당되는 글 1건

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

 안드로이드는 저에게 굉장히 생소한 플랫폼입니다. 기존 어플리케이션과는 다른 라이프 사이클, 서로 다른 어플리케이션이 상대방 구성요소를 자유롭게 활용할 수 있는 점, 공통된 자원 접근 경로로서 Uri 의 적극적인 활용 등등... 여러가지 생소한 개념을 포함하고 있습니다.


 그중에서도 Intent 와 Intent Filter 그리고 Intent Routing 관련 기능은 어떻게 이런일이 가능할까? 라고 스스로에게 물어보면, 명쾌히 답할 수 없는 그런 애매한 문제였습니다. 그러다 마침, 참가중인 안드로이드 스터디 모임에서, 관련 내용을 발표하기 위해 Intent 와 Intent Filter 그리고 Intent Routing 에 대해서, 나름대로 정리할 기회가 생겼습니다. 그 내용을 공유해 봅니다.

1. Intent?
 인텐트는 '의도' 라고 번역됩니다. 또한 기능적으로 말하면 '메세지' 라고 할 수 있습니다. 예를 들어 'Intent.ACTION_VIEW' 값을 갖는 인텐트는 무언가를 '본다' 라는 의도를 내포한 '메세지' 라고 할 수 있습니다. 이 메세지는 안드로이드의 어플리케이션 컴포넌트(Activity / Service / BroadcastReceiver)들 사이의 의사 소통 수단 중 하나로 사용됩니다. 


<짜장면을 시키기 위해서는 중국집에 전화를 한 후에 주문을 전달해야 합니다.>

 그런데 여기서 중요한 것은 '메세지' 자체 만으로 어떤 일을 할 수 있는 건 아니라는 점입니다. '메세지' 가 힘을 발휘하는 건, 누군가가 그 '메세지' 를 읽고, 해당 '메세지' 의 내용을 직접 수행할 때 입니다. 짜장면을 배달 시키는 과정을 생각해보면 이해하기 쉽습니다. 예를들어, 내가 자취방에 앉아 아무리 '짜장면 배달해 주세요!' 라고 혼자 소리쳐도  결코 짜장면이 배달되어 오지는 않습니다. 중국집에 전화를 걸어, 내 주소를 말하고, 짜장면을 배달해 달라고 정확한 메세지를 전달하면, 중국집 주방장이 짜장면을 만들고, 그 후에야 짜장면이 오토바이에 실려 집까지 배달 오게 됩니다.

2. Intent Filter?
 인텐트는 어떤 의도를 나타내는 '메세지' 입니다. 메세지가 힘을 갖기 위해서는 누군가에게 전달되야 합니다. 인텐트 필터는 '필터' 라는 말이 의미하는대로, 나는 특정 '의도'를 포함하는 메세지를 받고 싶다라고 정의하는 방법이라고 할 수 있습니다. 예를 살펴보면 훨씬 쉽게 알 수 있습니다. 

<intent-filter android:label="@string/resolve_edit">
 
<action android:name="android.intent.action.VIEW" />
   
<action android:name="android.intent.action.EDIT" />
    <category android:name="android.intent.category.DEFAULT"/>              <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
<intent-filter>
   
<action android:name="android.intent.action.INSERT" />
   
<category android:name="android.intent.category.DEFAULT" />
 
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>

 첫번째 인텐트 필터는 VIEW 혹은 EDIT 라는 액션 값을 갖고, DEFAULT 카테고리라는 값을 갖으며, 구글의 Note 타입 데이터를 갖는 메세지를 수신하겠다고 선언하는 인텐트 필터입니다. 또한, 두번째 인텐트 필터는 INSERT 라는 액션 값을 갖고, DEFAULT 라는 카테고리 값을 갖으며, 구글 Note 목록 형식의 데이타 타입을 갖는 인텐트를 수신하겠다는 뜻이지요.

 인텐트는 보통 다섯 가지 구성요소 (Component/Action/Data/Category/Extra) 로 이루어 지고, 각각의 구성요소가 저마다 우선순위가 있고, 여러가지 미리 정의된 값들이 있긴 합니다만 (상세한 내용은 구글 개발자 사이트를 참고 하시면 좋습니다.), 본질적으로는 어떤 '의도' 를 내포하는 '메세지' 에 불과합니다. 또한, 인텐트 필터는 여러가지 메세지중 특정 '의도' 를 갖은 '메세지' 만을 받겠다는 선언에 불과한 것이지요.

 예를 들어, 개인의 휴대폰 번호는 나와 관계된 메세지만을 수신하는 인텐트 필터로 생각 할 수 있겠고, 도미노 피자의 주문 센터는 전국 어느 매장이든 관계 없이 도미노 피자를 주문하고자 하는 메세지를 수신하기 위해 큰 범위의 인텐트 필터를 갖고 있다고 생각할 수 있겠습니다. 

3. Intent Routing?
  인텐트는 '의도를 갖는 메세지' 인텐트 필터는 '특정 의도를 수신하겠다는 선언' 이라고 한다면, 인텐트와 인텐트 필터를 서로 연결 해주는 과정이 필요합니다. 그 것이 바로 인텐트 라우팅 과정이라고 할 수 있습니다. 

  즉, 인텐트 라우팅이란, 특정 인텐트가 주어지면, 해당 인텐트 - 의도 에 가장 잘 부합하는 인텐트 필터를 갖은 단 하나의 컴포넌트를 찾아주는 일입니다. 이때, 메세지 자체에 해당 메세지를 전달해야하는 수신처(컴포넌트 이름)가 명확하게 명시되어 있다면, 별다른 고민없이 해당 컴포넌트에 인텐트를 전달하면 됩니다. 이런 경우를 명시적 인텐트(Explicit Intent)라고 합니다. 만일 그렇지 않을 경우, 추가적으로 주어진 단서(Action/Data/Category)를 기반으로 가장 적합한 하나의 컴포넌트를 찾아내야 합니다. 이른바 암시적 인텐트(Implicit Intent) 입니다.


<기본적으로 인텐트는 반드시 하나의 컴포넌트에게만 전달되어야 한다> 

 이 과정은 몇 가지 규칙에 의해 이루어 지는데, (예를 들어, 인텐트에 액션 값이 명시되어 있다면, 인텐트 필터에 해당 액션 값이 명시되어 있어야 한다. 등등) 모든 규칙을 적용한 후에도, 해당 '의도'를 정확하게 만족시키는 컴포넌트가 여러개일 경우, 사용자에게 여러 후보 중 하나만 고르라고 위와 같은 UI 가 나타납니다. 

4. Behind the Scenes
 인텐트에 관련되어 가장 놀라운 점은, 특정 인텐트를 전달하고자 할 때, 해당 인텐트를 전달받아야 하는 대상 컴포넌트가 생명주기 상 어떤 단계에 있건 관계없이 (컴포넌트가 작동중인 상태이던 그렇지 않던...) 해당 인텐트를 수신할 수 있다는 점입니다. 

 예를 들어, 개발자가 'ACTION_VIEW' 라는 액션 값을 갖고, 'image/jpeg' 라는 타입을 갖는 인텐트를 하나 생성해서, startActivity() 함수를 통해 해당 인텐트를 전달 한다면, 이미지 뷰어 엑티비티가 화면에 나타납니다. 해당 엑티비티가 이미 실행중이던, 그렇지 않던 관계 없이 말이지요. 비유하자면, 휴대폰이 꺼져있어도 만일 누군가가 나에게 전화를 걸면 휴대폰이 자동으로 켜지는 것과 비슷한 일입니다. 

 이러한 일은 어떻게 가능할까요?

 답은 어쩌면 뻔하면서도 단순합니다. 안드로이드 어플리케이션 프레임워크단에서 세 가지 중요한 일을 수행해 주고 있기 때문입니다. 첫째로 각각의 컴포넌트들이 어떤 메세지를 수신하고자 하는지 그 내용(인텐트 필터) 를 모두 모아서 하나의 주소록처럼 관리하는 일을 수행합니다. 두 번째는, 각 컴포넌트들이 전송하는 인텐트를 우선 수신한 후, 보관된 주소록을 바탕으로 대상 컴포넌트를 찾는 역할을 수행합니다. 마지막으로, 인텐트를 수신해야할 해당 컴포넌트의 상황에 따라 적절한 일을 수행합니다. (예를 들어 작동중이 아닌 컴포넌트는 새롭게 시작시키고, 이미 백그라운드에서 작동중인 컴포넌트인 경우 포그라운드로 옮겨 주는 등...) 


<인텐트 메카니즘에서 핵심 역할을 수행하는 것은 ActivityManager 와 PackageManager 이다>


 안드로이드 플랫폼에서 첫번째 일을 수행하는 것은 PackageManagerService 이고, 두번째와 세번째 일을 수행하는 것은 ActivityManagerService 입니다. 또한 이 두개의 서비스는 시스템 서비스로, 안드로이드 플랫폼이 시작되면 항상 실행되는, 시스템 프로세스 내에서 상주하고 있습니다. 

 PackageManager 는 최초 실행 시, 안드로이드플랫상에서 어플리케이션이 설치되는 특정 경로들(system/app, data/app 등등)을 검색해, 설치된 APK 파일들을 모두 모은 후, 해당 패키지 파일에 포함되어 있는 메니페스트 파일의 내용을 파싱합니다. 특정 패키지에 들어있는 Activity / Service / BroadcastReceiver 들의 각종 권한 정보, 인텐트 필터정보 등등을 모두 수집하여 메모리 상에 관리합니다. 또한, 새롭게 패키지가 추가되거나 삭제될 때 발생하는 Broadcast Intent 를 수신하며, 관리하고 있는 주소록을 업데이트하는 일도 동시에 수행합니다.

 ActivityManger 는 한층 더 다양한 일을 수행합니다. 안드로이드 어플리케이션 컴포넌트가 인텐트를 전달하기 위해 사용하는 API 는 크게 startActivity / startService / sendBroadcast 세 가지로 나누어 집니다. 그리고, 이러한 API 가 호출될 때, 최종적으로 호출되는 API 는 ActivityManagerService 단의 API 들입니다. 세가지 API 모두 IBinder 를 통해 Remote Server 의 API 를 호출하는 샘입니다. 다시말해, 안드로이드 플랫폼 상에서 발생하는 모든 인텐트는 우선적으로 ActivityManagerService 에 전달되는 것이지요. 

 ActivityManagerService 는 인텐트를 수신 받으면, PackageManagerService 에 해당 인텐트에 가장 잘 부합하는 컴포넌트가 무엇인지 물어 봅니다. 그리고 그 결과를 바탕으로, 인텐트를 타켓 컴포넌트에게 전달해 줍니다. ActivityManagerService 는 말 그대로, 작동중인 컴포넌트들의 상태 정보 추가로, 활성화된 패키지들의 상태 정보들을 모두 관리하고 있기 때문에, 타겟 컴포넌트의 현재 상태를 확인 할 수 있습니다. 때문에, 특정 컴포넌트가 잠들어 있는 상태라면 해당 컴포넌트를 되살린 후에, 인텐트를 전달하게 됩니다. (DHL 도 울고 갈만큼 투철한 서비스 정신입니다.)


<전화한통으로 원하는 메세지를 상대방에게 확실하게 전달하는 방법>

 즉, 개념적으로 살펴 보자면, 모든 '인텐트' 는 특정 컴포넌트에게 직접 전달되는게 아니고, 택배회사와 같은 ActivityManager 와 PackageManager 를 통해, 위탁 전달된다고 생각 할 수 있습니다. 

블로그 이미지

By훈트

,