펜딩 인텐트는 내장된 인텐트를 외부 앱에서 실행되도록 하기 위해 사용한다.
주요 사용 사례는 다음과 같다.
- 사용자가 알림/앱 위젯으로 액션을 수행할 때 실행되는 인텐트를 선언
- 향후 지정된 시간에 실행되는 인텐트를 선언
펜딩 인텐트를 생성할 때는 다음 메서드 중 하나를 사용한다.
getActivity()
액티비티를 시작하는 인텐트 생성getService()
서비스를 시작하는 인텐트 생성getBroadcast()
브로드캐스트 리시버를 시작하는 인텐트 생성
각 메서드는 현재 앱의 컨텍스트, 실행할 인텐트, 인텐트의 사용 방식을 나타내는 플래그 값을 인자로 받는다.
가변성 설정하기
앱이 안드로이드 12 이상 버전을 타겟팅할 경우 각 PendingIntent
객체에 다음 두 플래그로 가변성을 설정해야 한다.
그렇지 않으면 IllegalArgumentException
이 발생한다.
PendingIntent.FLAG_MUTABLE
펜딩 인텐트를 가변형으로 설정한다.PendingIntent.FLAG_IMMUTABLE
펜딩 인텐트를 불변형으로 설정한다. 이렇게 하면 다른 앱에서 인텐트를 수정하지 못한다.
val pendingIntent = PendingIntent.getActivity(
applicationContext,
REQUEST_CODE,
intent,
/* 플래그 */ PendingIntent.FLAG_IMMUTABLE
)
하지만 가변형으로 설정해야 하는 경우가 있다.
- 알림에서 답장 기능을 지원
답장 기능은 답장과 관련된PendingIntent
객체 안의 클립 데이터를 변경해야 한다.
이런 요청을 하려면 보통fillIn()
에FILL_IN_CLIP_DATA
플래그를 전달한다. requestLocationUpdates()
또는 이와 유사한 API를 호출하여 디바이스의 위치 정보를 요청
가변형 펜딩 인텐트를 사용하면 시스템이 위치 수명 주기 이벤트를 나타내는 엑스트라를 추가할 수 있다.
이런 이벤트는 위치 변경을 포함하며 프로바이더를 사용할 수 있게 한다.AlarmManager
를 사용하여 알람을 예약
가변형 펜딩 인텐트를 사용하면 시스템이EXTRA_ALARM_COUNT
엑스트라를 사용할 수 있다.
이 엑스트라는 반복되는 알람이 발생이 횟수를 나타낸다.
이를 포함하면 인텐트는 디바이스가 슬립 등의 상태에서 알림이 여러 번 발생했는지 여부를 앱에 알릴 수 있다.
앱에서 가변형 인텐트 객체를 생성한다면 명시적 인텐트를 사용하는 것을 권장한다.
그렇게 하면 다른 앱에서 PendingIntent
를 호출하고 제어를 돌려받았을 때 언제든지 앱의 동일한 컴포넌트가 시작된다.
외부 앱이 내부 앱의 펜딩 인텐트를 사용할 수 있는 방법을 더 잘 정의하려면 펜딩 인텐트에 명시적 인텐트를 사용해야 한다.
이렇게 하려면 다음 단계를 따라야 한다.
- 기초 인텐트에 액션, 패키지, 컴포넌트 필드가 설정되었는지 확인한다.
- 펜딩 인텐트를 생성할 때 안드로이드 6.0(API 레벨 23)에 추가된
FLAG_IMMUTABLE
을 사용한다.
이 플래그를 사용하면PendingIntent
를 수신하는 앱이 빈 속성을 추가하지 못한다.
앱의minSdkVersion
이 22 이하이면 안전성과 호환성을 위해 다음처럼if
문을 사용하여 빌드 버전을 분기해야 한다.
if (Build.VERSION.SDK_INT >= 23) { // FLAG_IMMUTABLE로 펜딩 인텐트 생성 } else { // 펜딩 인텐트를 생성하는 기존 코드 }
인텐트 검사
액티비티를 시작하는 암시적 인텐트를 수신하면 시스템은 해당 인텐트에 가장 적합한 액티비티를 탐색한다.
이때 각 액션, 데이터 , 카테고리 정보와 인텐트 필터를 비교한다.
액션 테스트
인텐트 필터는 0개 이상의 <action>
태그를 선언할 수 있다.
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
</intent-filter>
이 필터를 통과하려면 인텐트 객체에 지정된 액션은 필터에 나열된 것 중 하나와 일치해야 한다.
필터에 액션이 지정되어 있지 않으면 인텐트에는 일치시킬 항목이 없는 것이므로 필터를 통과하지 못한다.
하지만 인텐트에 액션이 지정되어 있지 않으면 필터가 적어도 하나의 액션을 포함하면 통과한다.
카테고리 테스트
인텐트 필터는 0개 이상의 <category>
태그를 선언할 수 있다.
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
필터를 통과하려면 인텐트의 모든 카테고리는 필터 안의 것과 일치해야 한다.
반면 인텐트 필터는 인텐트에 지정된 카테고리보다 더 많이 선언할 수 있다.
그러므로 카테고리가 지정되지 않은 인텐트는 인텐트 필터에 어떤 카테고리가 선언되어 있던 항상 필터를 통과할 수 있다.
안드로이드는 startActivity()
와 startActivityForResult()
에 전달되는 모든 암시적 인텐트에 CATEGORY_DEFAULT
를 지정한다.
액티비티가 암시적 인텐트를 수신하도록 하려면 인텐트 필터가 android.intent.category.DEFAULT
카테고리를 포함해야 한다.
데이터 테스트
인텐트 데이터를 지정하기 위해 다음처럼 인텐트 필터는 0개 이상의 <data>
태그를 선언할 수 있다.
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
</intent-filter>
각 <data>
태그에 URI 구조 및 MIME 타입을 지정할 수 있다.
URI 구조는 다음 4가지 속성으로 나뉘어 있다.
<scheme>://<host>:<port>/<path>
예를 들어 "content://com.example.project:200/folder/subfolder/etc"
라는 URI에서 scheme
은 "content"
, host
는 "com.example.project"
, port
는 "200"
, path
는 "folder/subfolder/etc"
이다.
이 속성들은 모두 선택 항목이지만 서로 종속적이다.
scheme
을 지정하지 않으면host
는 무시된다.host
를 지정하지 않으면port
는 무시된다.scheme
과host
를 모두 지정하지 않으면path
는 무시된다.
인텐트 안의 URI를 필터와 비교할 때는 필터에 지정된 속성의 부분만 비교한다. 예를 들면 다음과 같다.
- 필터에
scheme
만 지정된 경우 해당scheme
만 일치하면 URI가 테스트를 통과한다. - 필터에
scheme
이 지정되고path
는 지정되지 않은 경우 동일한scheme
만 포함하면path
에 관계없이 URI가 테스트를 통과한다. - 필터에
scheme
,path
가 지정된 경우 두 부분이 모두 동일한 URI만 테스트를 통과한다.
path
를 지정할 때 *
를 사용하여 경로명의 일부분만 일치하도록 요구할 수 있다.
데이터 테스트는 인텐트 안 URI와 MIME 타입을 필터에 지정된 것과 비교한다. 비교 규칙은 다음과 같다.
- URI와 MIME 타입 모두 지정되지 않은 경우 필터 역시 URI와 MIME 타입 모두 지정하지 않아야 통과한다.
- URI는 지정되고 MIME 타입은 지정되지 않은 경우 인텐트는 URI가 필터의 것과 일치하고 필터가 MIME 타입을 지정하지 않은 경우에만 통과한다.
- MIME 타입은 지정되고 URI는 지정되지 않은 경우 필터가 동일한 MIME 타입을 가지지만 URI를 지정하지 않은 경우만 필터를 통과한다.
- URI와 MIME 타입 모두 지정된 인텐트는 MIME 타입이 필터의 것과 일치하는 경우 테스트를 부분적으로 통과한다.
그리고 URI가 필터에 지정된 것과 일치하거나,content:
및file:
URI를 포함하고 필터가 URI를 지정하지 않은 경우도 그렇다.
바꿔 말하자면 컴포넌트는 필터에 MIME 타입만 나열된 경우만content:
및file:
데이터를 지원하는 것으로 간주된다.
따라서content:
및file:
을scheme
으로 지정하지 않고 MIME 타입만 지정해도 컨텐트 프로바이더에서 로컬 데이터를 가져올 수 있다.
인텐트가 URI나 MIME 타입을 지정하지만 <intent-filter>
태그 안에 <data>
태그가 없으면 데이터 테스트를 통과하지 못한다.
다음 예시는 <data>
가 컴포넌트가 컨텐츠 프로바이더로부터 이미지 데이터를 가져온다는 것을 나타낸다.
<intent-filter>
<data android:mimeType="image/*" />
</intent-filter>
일반적으로 URI는 지정하지 않고 MIME 유형만 지정한다.
사용 가능한 데이터는 대부분 컨텐츠 프로바이더가 제공하기 때문이다.
MIME 타입과 scheme
을 지정하는 것도 일반적인 사용법이다.
다음 예시는 컴포넌트가 액션을 수행하기 위해 네트워크에서 비디오 데이터를 가져올 수 있다는 것을 나타낸다.
<intent-filter>
<data android:scheme="http" android:mimeType="video/*" />
</intent-filter>
인텐트 매칭
PackageManager
에 있는 일련의 queryXXX()
메서드는 특정 인텐트를 허용하는 모든 컴포넌트를 반환한다.
이와 마찬가지로 resolveXXX()
메서드는 인텐트에 응답할 수 있는 최적의 컴포넌트를 판별한다.
예를 들어 queryIntentActivities()
는 인자로 전달받은 인텐트를 수행할 수 있는 모든 액티비티의 리스트를 반환한다.
이 메서드들은 컴포넌트를 반환할 뿐 활성화하지는 않는다.
'Android' 카테고리의 다른 글
액티비티 (4) : 액티비티 테스트 (0) | 2022.05.09 |
---|---|
액티비티 (3) : 액티비티 상태 변화 관리 (0) | 2022.04.08 |
액티비티 (2) : 액티비티의 수명 주기 (0) | 2022.04.08 |
액티비티 (1) : 액티비티 만들기 (0) | 2022.04.06 |
인텐트 (1) : 인텐트와 인텐트 필터 (0) | 2022.04.04 |