다른 앱으로 사용자 보내기

Android의 가장 중요한 특징 중 하나는 앱에서 실행하려는 '작업'에 따라 사용자를 다른 앱으로 보낼 수 있는 것입니다. 예를 들어, 지도에 표시할 비즈니스 주소가 앱에 있는 경우 지도를 표시하는 활동을 앱에서 빌드하지 않아도 됩니다. 대신, Intent를 사용하여 주소 보기 요청을 만들면 됩니다. 그러면 Android 시스템에서 지도에 주소를 표시할 수 있는 앱을 시작합니다.

첫 번째 클래스인 첫 앱 빌드에서 설명했듯이 자체 앱 내에서 활동 간에 이동하려면 인텐트를 사용해야 합니다. 일반적으로 시작하려는 구성요소의 정확한 클래스 이름이 정의된 명시적 인텐트를 사용하여 활동 간에 이동합니다. 하지만 '지도 보기'와 같이 별도의 앱에서 작업을 실행하려면 암시적 인텐트를 사용해야 합니다.

이 과정에서는 특정 작업을 위한 암시적 인텐트를 만드는 방법과 이 인텐트를 사용하여 다른 앱에서 작업을 실행하는 활동을 시작하는 방법을 설명합니다. 또한, 암시적 인텐트에 관한 런타임 검사를 포함하는 것이 중요한 이유를 알아보려면 여기에 삽입된 동영상을 참고하세요.

암시적 인텐트 빌드

암시적 인텐트는 시작할 구성요소의 클래스 이름을 선언하는 대신에 실행할 작업을 선언합니다. 작업은 보기, 수정, 보내기 또는 가져오기와 같이 원하는 동작을 지정합니다.

인텐트 작업을 데이터와 연결

또한, 인텐트에는 보려는 주소, 보내려는 이메일 메시지 등 작업과 관련된 데이터가 포함되기도 합니다. 만들려는 인텐트에 따라 데이터가 Uri 또는 다른 여러 데이터 유형 중 하나이거나 인텐트에 데이터가 전혀 필요하지 않을 수도 있습니다.

데이터가 Uri인 경우 간단한 Intent() 생성자를 사용하여 작업 및 데이터를 정의할 수 있습니다.

다음 예에서는 전화번호를 지정하는 Uri 데이터를 사용하여 인텐트를 만들고 전화 통화를 시작하는 방법을 보여줍니다.

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

앱이 startActivity()를 사용하여 이 인텐트를 호출하면 전화 앱은 지정된 전화번호로 전화를 겁니다.

다음은 몇 가지 다른 인텐트와 이러한 인텐트의 작업 및 Uri 데이터 쌍입니다.

지도 보기

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

웹페이지 보기

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

인텐트에 데이터 추가

다른 종류의 암시적 인텐트는 다른 데이터 유형(예: 문자열)을 제공하는 '추가' 데이터가 필요합니다. 다양한 putExtra() 메서드를 사용하여 하나 이상의 추가 데이터를 덧붙일 수 있습니다.

기본적으로 시스템은 포함된 Uri 데이터를 바탕으로 인텐트에서 필요한 알맞은 MIME 유형을 결정합니다. Uri를 인텐트에 포함하지 않는 경우 일반적으로 setType()을 사용하여 인텐트와 연결된 데이터 유형을 지정해야 합니다. MIME 유형을 설정하면 인텐트를 수신할 활동 종류도 함께 지정됩니다.

다음은 원하는 작업을 지정하기 위해 추가 데이터를 사용하는 인텐트입니다.

첨부파일이 포함된 이메일 보내기

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

캘린더 일정 만들기

참고: 캘린더 일정에 사용되는 이 인텐트는 API 수준 14 이상에서만 지원됩니다.

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

참고: Intent를 최대한 구체적으로 정의하는 것이 중요합니다. 예를 들어, ACTION_VIEW 인텐트를 사용하여 이미지를 표시하려면 MIME 유형을 image/*로 지정해야 합니다. 그러면 다른 유형의 데이터를 '볼' 수 있는 앱(예: 지도 앱)은 이 인텐트를 통해 트리거되지 않습니다.

인텐트로 활동 시작

Intent를 만들고 추가 정보를 설정했다면 startActivity()를 호출하여 시스템으로 보냅니다.

Kotlin

startActivity(intent)

Java

startActivity(intent);

인텐트를 수신할 수 있는 앱이 없는 상황 처리

많은 인텐트가 기기에 설치된 다른 앱(예: 전화, 이메일, 캘린더 앱)에 의해 성공적으로 처리되더라도, 앱에서는 앱의 인텐트를 처리할 수 있는 활동이 없는 상황을 대비해야 합니다. 인텐트를 호출할 때마다 앱의 인텐트를 처리할 수 있는 활동이 없을 때 발생하는 ActivityNotFoundException을 포착할 준비를 해야 합니다.

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

이 예외를 포착한 후 앱에서 취해야 할 조치를 결정합니다. 다음 단계는 호출을 시도했던 인텐트의 구체적인 특성에 따라 다릅니다. 예를 들어, 인텐트를 처리할 수 있는 특정 앱을 알고 있다면 사용자가 앱을 다운로드하도록 링크를 제공합니다. Google Play에 있는 제품에 링크 거는 방법을 자세히 알아보세요.

명확성 대화상자

시스템에서 인텐트를 처리할 수 있는 활동을 두 개 이상 식별하면 그림 1과 같이 사용자가 앱을 선택할 수 있도록 대화상자('명확성 대화상자'라고도 함)가 표시됩니다. 인텐트를 처리할 수 있는 활동이 하나밖에 없으면 시스템은 바로 활동을 시작합니다.

화면 하단에 패널이 표시됩니다. 이 패널에는 인텐트를 처리할 수 있는 여러 앱이 나열됩니다.

그림 1. 인텐트를 처리할 수 있는 앱이 둘 이상 있을 경우 표시되는 선택 대화상자의 예

전체 예

다음은 지도 보기 인텐트를 생성하여 인텐트를 처리할 수 있는 앱이 있는지 확인하고 앱을 시작하는 방법을 보여주는 전체 예입니다.

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

앱 선택기 표시

그림 2. 선택기 대화상자

IntentstartActivity()에 전달하여 활동을 시작할 때 인텐트에 응답하는 앱이 둘 이상인 경우 사용자는 기본으로 사용할 앱을 선택할 수 있습니다(대화상자 하단의 체크박스 선택, 그림 1 참고). 이 방법은 사용자가 일반적으로 항상 동일한 앱을 사용하여 웹페이지를 열거나(사용자가 주로 하나의 웹브라우저만 사용) 사진을 찍는(사용자가 주로 하나의 카메라만 선호) 등의 작업을 실행하는 경우 유용합니다.

하지만, 실행할 작업을 여러 앱에서 처리할 수 있고 사용자가 매번 다른 앱을 선호한다면(예: '공유' 작업과 같이 사용자가 항목을 공유할 수 있는 앱을 여러 개 가진 경우) 그림 2와 같이 명시적으로 선택기 대화상자를 표시해야 합니다. 선택기 대화상자는 사용자가 작업에 사용할 앱을 매번 선택하도록 합니다(사용자가 작업에 사용할 기본 앱을 선택할 수 없음).

선택기를 표시하려면 createChooser()를 사용하여 Intent를 만들고 startActivity()에 전달합니다. 예를 들면 다음과 같습니다.

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

이 예에서는 createChooser() 메서드에 전달된 인텐트에 응답하는 앱의 목록을 대화상자에 표시합니다. 작업이 ACTION_SEND 또는 ACTION_SEND_MULTIPLE이 아닌 경우 title 매개변수가 제공될 수도 있습니다.