Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

Android 11에서 패키지 공개 상태의 사용 사례

이 문서에서는 앱이 다른 앱과 상호작용하는 사용 사례의 일반적인 예를 보여줍니다. 각 섹션에서는 Android 11에서 발생하는 패키지 공개 상태 동작 변경사항과 호환되도록 앱을 업데이트하는 방법을 안내합니다.

앱이 Android 11을 타겟팅하고 암시적 인텐트를 사용하여 다른 앱에서 활동을 시작한다면 가장 간단한 방법은 인텐트를 호출하고 사용 가능한 앱이 없는 경우 ActivityNotFoundException 예외를 처리하는 것입니다.

앱의 일부가 UI 표시와 같이 startActivity() 호출이 성공할 수 있는지 아는 것에 의존하는 경우 앱 매니페스트의 <queries> 요소에 요소를 추가합니다. 일반적으로 이 새 요소는 <intent> 요소입니다.

URL 열기

이 섹션에서는 Android 11을 타겟팅하는 앱에서 URL을 여는 방법을 설명합니다. 앱이 URL을 여는 방법에 따라 다음 하위 섹션의 예 중 하나를 따르세요.

브라우저 또는 다른 앱에서 URL 열기

URL을 열려면 웹 URL 로드 방법에 관한 섹션에 설명된 대로 ACTION_VIEW 인텐트 작업이 포함된 인텐트를 사용합니다. 이 인텐트를 사용하여 startActivity()를 호출하면 다음 중 하나가 발생합니다.

  • URL이 웹브라우저 앱에서 열립니다.
  • URL이 URL을 딥 링크로 지원하는 앱에서 열립니다.
  • 명확성 대화상자가 표시되고 이 대화상자로 사용자는 URL을 여는 앱을 선택할 수 있습니다.
  • 기기에 URL을 열 수 있는 앱이 설치되어 있지 않으므로 ActivityNotFoundException이 발생합니다. 특이한 경우입니다.

    ActivityNotFoundException이 발생하면 앱에서 포착하고 처리하는 것이 좋습니다.

앱에서 암시적 인텐트를 사용하여 URL을 열기 때문에 앱 매니페스트에 <queries> 요소를 추가하지 않아도 됩니다.

브라우저가 사용 가능한지 확인

때에 따라서는 앱에서 URL을 열려고 하기 전에 기기에 사용 가능한 브라우저가 최소 하나 이상 있는지 또는 특정 브라우저가 기본 브라우저인지 확인하는 것이 좋습니다. 이때 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" />
</intent>

그런 다음 queryIntentActivities()를 호출하고 웹 인텐트를 인수로 전달하면 반환되는 목록에 사용 가능한 브라우저 앱이 포함됩니다.

맞춤 탭에서 URL 열기

맞춤 탭을 사용하면 앱이 브라우저의 디자인과 분위기를 맞춤설정할 수 있습니다. 앱 매니페스트에서 <queries> 요소를 추가하거나 변경할 필요 없이 맞춤 탭에서 URL을 열 수 있습니다.

그러나 기기에 맞춤 탭을 지원하는 브라우저가 있는지 확인하거나 CustomTabsClient.getPackageName()을 사용하여 맞춤 탭으로 실행할 특정 브라우저를 선택하는 것이 좋습니다. 이 경우 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>

브라우저가 아닌 앱에서 URL 처리

앱에서 맞춤 탭을 사용하여 URL을 열 수 있다고 해도 가능하면 브라우저가 아닌 앱에서 특정 URL을 열도록 허용하는 것이 좋습니다. 앱에 이 기능을 제공하려면 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 인텐트 플래그를 설정하는 인텐트를 사용하여 startActivity() 호출을 시도합니다. 시스템에서 ActivityNotFoundException이 발생하면 앱에서 맞춤 탭으로 URL을 열면 됩니다.

인텐트에 이 플래그가 포함된 경우 startActivity()를 호출하면 다음 조건 중 하나가 발생할 때 ActivityNotFoundException이 발생합니다.

  • 호출로 인해 브라우저 앱이 직접 실행됩니다.
  • 호출로 인해 유일한 옵션이 브라우저 앱인 명확성 대화상자가 사용자에게 표시됩니다.

다음 코드 스니펫은 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 인텐트 플래그를 사용하도록 로직을 업데이트하는 방법을 보여줍니다.

Kotlin

try {
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        // The URL should either launch directly in a non-browser app (if it's
        // the default), or in the disambiguation dialog.
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url)
}

자바

try {
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    // The URL should either launch directly in a non-browser app (if it's the
    // default), or in the disambiguation dialog.
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url);
}

명확성 대화상자 피하기

사용자가 URL을 열 때 표시될 수 있는 명확성 대화상자를 표시하지 않고 대신 이러한 상황에서 URL을 직접 처리하려면 FLAG_ACTIVITY_REQUIRE_DEFAULT 인텐트 플래그를 설정하는 인텐트를 사용하면 됩니다.

인텐트에 이 플래그가 포함된 경우 startActivity()를 호출하면 호출로 인해 사용자에게 명확성 대화상자가 표시될 때 ActivityNotFoundException이 발생합니다.

인텐트에 이 플래그와 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 인텐트 플래그가 모두 포함된 경우 startActivity()를 호출하면 다음 조건 중 하나가 발생할 때 ActivityNotFoundException이 발생합니다.

  • 호출로 인해 브라우저 앱이 직접 실행됩니다.
  • 호출로 인해 명확성 대화상자가 사용자에게 표시됩니다.

다음 코드 스니펫은 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 플래그와 FLAG_ACTIVITY_REQUIRE_DEFAULT 플래그를 함께 사용하는 방법을 보여줍니다.

Kotlin

val url = URL_TO_LOAD
try {
    // In order for this intent to be invoked, the system must directly launch a
    // non-browser app.
    val intent = Intent(ACTION_VIEW, Uri.parse(url).apply {
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or
                FLAG_ACTIVITY_REQUIRE_DEFAULT
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url)
}

자바

String url = URL_TO_LOAD;
try {
    // In order for this intent to be invoked, the system must directly launch a
    // non-browser app.
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER |
            FLAG_ACTIVITY_REQUIRE_DEFAULT);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url);
}

파일 열기

앱에서 파일이나 첨부파일을 처리한다면(예: 기기에서 특정 파일을 열 수 있는지 확인) 일반적으로 파일을 처리할 수 있는 활동을 시작하는 것이 가장 쉽습니다. 이렇게 하려면 ACTION_VIEW 인텐트 작업과 특정 파일을 나타내는 URI가 포함된 인텐트를 사용합니다. 기기에서 사용할 수 있는 앱이 없다면 앱에서 ActivityNotFoundException을 포착할 수 있습니다. 예외 처리 로직에서 오류를 표시하거나 파일을 직접 처리해 볼 수 있습니다.

앱에서 다른 앱이 특정 파일을 열 수 있는지 미리 알아야 한다면 매니페스트에 <queries> 요소의 일부로 다음 코드 스니펫의 <intent> 요소를 포함합니다. 컴파일 시 파일 형식을 이미 알고 있다면 파일 형식을 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
  <data android:mimeType="application/pdf" />
</intent>

그런 다음 인텐트와 함께 resolveActivity()를 호출하여 앱을 사용할 수 있는지 확인하면 됩니다.

맞춤 공유 시트 만들기

가능하면 시스템 제공 공유 시트를 사용하세요. 또는 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SEND" />
  <!-- Replace with the MIME type that your app works with, if needed. -->
  <data android:mimeType="image/jpeg" />
</intent>

queryIntentActivities() 호출과 같이 앱 로직에서 공유 시트를 빌드하는 프로세스는 이전 버전의 Android와 비교하여 변경되지 않은 상태로 유지됩니다.

텍스트 음성 변환 엔진에 연결

앱이 텍스트 음성 변환(TTS) 엔진과 상호작용하면 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.TTS_SERVICE" />
</intent>

미디어 브라우저 서비스에 연결

클라이언트 미디어 브라우저 앱에서 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.media.browse.MediaBrowserService" />
</intent>

연락처를 위한 맞춤 데이터 행 표시

앱은 연락처 제공자에 맞춤 데이터 행을 추가할 수 있습니다. 연락처 앱에서 이 맞춤 데이터를 표시하려면 다음 작업을 할 수 있어야 합니다.

  1. 다른 앱에서 contacts.xml 파일 읽기
  2. 맞춤 MIME 유형에 상응하는 아이콘 로드

개발자의 앱이 연락처 앱이면 매니페스트에 <queries> 요소의 일부로 다음 <intent> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<!-- Allows the app to read the "contacts.xml" file from the other apps. -->
<intent>
  <action android:name="android.accounts.AccountAuthenticator" />
</intent>
<!-- Allows the app to load an icon corresponding to the custom MIME type. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <data android:scheme="content" android:host="com.android.contacts"
        android:mimeType="vnd.android.cursor.item/*" />
</intent>

라이브러리에서 패키지 공개 상태 요구사항 선언

Android 라이브러리를 개발한다면 AAR 매니페스트 파일<queries> 요소를 추가하여 패키지 공개 상태 요구사항을 선언할 수 있습니다. 이 <queries> 요소는 앱이 자체 매니페스트에서 선언할 수 있는 요소와 기능이 동일합니다.

라이브러리에 바인드된 서비스 사용과 같은 '호스트' 앱과의 통신이 포함된 경우 호스트 앱의 패키지 이름을 지정하는 <package> 요소를 포함합니다.

<!-- Place inside the <queries> element. -->
<package android:name=PACKAGE_NAME />

이 선언을 포함하면 호스트 앱이 설치되어 있는지 확인하고 bindService()를 호출하는 등의 방식으로 호스트 앱과 상호작용할 수 있습니다. 라이브러리를 사용하는 호출 앱은 이 상호작용의 결과로 호스트 앱에 자동으로 표시됩니다.