パッケージの公開設定を限定して一般的なユースケースを実行する

このドキュメントでは、アプリが他のアプリと連携する場合の一般的なユースケースを紹介します。各セクションで、パッケージの公開設定を制限してアプリの機能を実現する方法について説明しています。これは、アプリが Android 11(API レベル 30)以降をターゲットとしている場合に考慮する必要があることです。

Android 11 以降をターゲットとするアプリがインテントを使用して別のアプリのアクティビティを開始する最も簡単な方法は、インテントを呼び出し、利用可能なアプリがないときは ActivityNotFoundException 例外を処理することです。

UI の表示など、アプリの一部が startActivity() の呼び出しに成功するかどうかの認識に依存している場合は、アプリのマニフェストの <queries> 要素に要素を追加します。通常、これは <intent> 要素です。

URL を開く

このセクションでは、Android 11 以降をターゲットとするアプリで URL を開くさまざまな方法について説明します。

ブラウザまたは他のアプリで URL を開く

URL を開くには、ウェブ URL の読み込みについてのガイドにあるように、ACTION_VIEW インテントのアクションを含むインテントを使用します。このインテントを使用して startActivity() を呼び出すと、次のいずれかが発生します。

  • ウェブブラウザ アプリで URL が開く。
  • URL をディープリンクとしてサポートしているアプリで URL が開く。
  • URL を開くアプリを選択できる確認ダイアログが表示される。
  • URL を開けるアプリがデバイスにインストールされていないために ActivityNotFoundException が発生する(これはめったにありません)。

    ActivityNotFoundException が発生した場合は、アプリで捕捉して処理することをおすすめします。

startActivity() メソッドでは、別のアプリのアクティビティを開始するためにパッケージの公開設定を必要としないため、アプリのマニフェストに <queries> 要素を追加する必要はありません。また、既存の <queries> 要素変更を加える必要もありません。これは、URL を開く暗黙的インテントと明示的インテントの両方に当てはまります。

ブラウザが利用可能かどうかを確認する

場合によっては、URL を開く前、デバイスにブラウザが少なくとも 1 つあること、または特定のブラウザがデフォルトのブラウザであることをアプリで確認する必要があります。そのような場合は、マニフェストで <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 をブラウザ以外のアプリで開くように設定している場合は、このリストにブラウザアプリは含まれません。

カスタムタブで 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)
}

Java

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 {
    // 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)
}

Java

String url = URL_TO_LOAD;
try {
    // 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() を呼び出すことで、アプリが利用可能かどうかを確認できます。

URI アクセス権を付与する

注: アプリが Android 11(API レベル 30)以降をターゲットとする場合、このセクションの説明にあるように、URI アクセス権限を宣言する必要があります。これは、ターゲットとなる SDK のバージョンや、コンテンツ プロバイダをエクスポートするかどうかに関係なく、すべてのアプリで推奨されます。

Android 11 以降をターゲットとするアプリがコンテンツ URI にアクセスできるようにするには、アプリのインテントで、インテント フラグ FLAG_GRANT_READ_URI_PERMISSIONFLAG_GRANT_WRITE_URI_PERMISSION のいずれかまたは両方を設定して URI アクセス権限を宣言する必要があります。

Android 11 以降では、URI アクセス権限により、インテントを受け取るアプリに以下の機能が提供されます。

  • 指定の URI 権限に応じて、コンテンツ URI が表すデータから読み取る、またはデータに書き込む。
  • URI オーソリティと一致するコンテンツ プロバイダを含むアプリを認識する。コンテンツ プロバイダを含むアプリは、インテントを送信するアプリとは異なる場合があります。

URI 権限のインテント フラグを追加して、Android 11 以降をターゲットとする別のアプリがコンテンツ URI 内のデータを表示できるようにする方法を、次のコード スニペットに示します。

Kotlin

val shareIntent = Intent(Intent.ACTION_VIEW).apply {
    flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
    data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP
}

Java

Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);

サービスに接続する

自動的に公開されないサービスとアプリが連携する必要がある場合は、<queries> 要素内で適切なインテント アクションを宣言できます。以下のセクションでは、頻繁にアクセスするサービスを使用した例を示します。

テキスト読み上げエンジンに接続する

アプリがテキスト読み上げ(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.speech.RecognitionService" />
</intent>

メディア ブラウザ サービスに接続する

アプリがクライアント メディア ブラウザ アプリである場合は、マニフェストで <queries> 要素の一部として、次の <intent> 要素を含めます。

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

カスタム機能を提供する

アプリが他のアプリとの連携に基づいて、カスタマイズ可能なアクションを実行する場合、またはカスタマイズ可能な情報を表示する必要がある場合は、マニフェストで <queries> 要素の一部としてインテント フィルタのシグネチャを使用し、そのカスタム動作を表すことができます。以下のセクションでは、いくつかの一般的なシナリオについて詳しく説明します。

SMS アプリのクエリ

デバイスにインストールされている SMS アプリのセットに関する情報をアプリが必要とする場合(たとえば、デバイスのデフォルト SMS ハンドラはどのアプリかをチェックする場合)は、次のように、マニフェストの <queries> 要素内に <intent> 要素を含めます。

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SENDTO"/>
  <data android:scheme="smsto" android:host="*" />
</intent>

カスタムの Sharesheet を作成する

可能な限り、システム提供の Sharesheet を使用してください。または、マニフェストで <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() の呼び出しなど、アプリのロジックで Sharesheet を作成するプロセスは、Android 11 より前のバージョンの Android と比べて変更されていません。

カスタムのテキスト選択操作を表示する

ユーザーがアプリでテキストを選択すると、選択したテキストに対して行える一連の操作がテキスト選択ツールバーに表示されます。このツールバーに他のアプリからのカスタム操作を表示する場合は、マニフェストで <queries> 要素の一部として、次の <intent> 要素を含めます。

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.PROCESS_TEXT" />
  <data android:mimeType="text/plain" />
</intent>

連絡先のカスタムデータ行を表示する

アプリで、連絡先プロバイダにカスタムデータ行を追加できます。このカスタムデータを連絡帳アプリで表示するには、次の操作を行えるようにする必要があります。

  1. 他のアプリから contacts.xml ファイルを読み取る。
  2. カスタム MIME タイプに対応するアイコンを読み込む。

アプリが連絡帳アプリの場合は、マニフェストで <queries> 要素の一部として、次の <intent> 要素を含めます。

<!-- Place inside the <queries> element. -->
<!-- Lets the app read the contacts.xml file from other apps. -->
<intent>
  <action android:name="android.accounts.AccountAuthenticator" />
</intent>
<!-- Lets the app 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>