インテントとインテント フィルタ

Intent は、別のアプリ コンポーネントにアクションをリクエストするために使用できるメッセージング オブジェクトです。インテントは、コンポーネント間の通信をさまざまな方法で容易にしますが、基本的なユースケースは 3 つあります。

  • アクティビティを開始する

    Activity は、アプリ内の 1 つの画面を表します。IntentstartActivity() に渡すことで、Activity の新しいインスタンスを開始できます。Intent は、開始するアクティビティを記述し、必要なデータを伝達します。

    アクティビティの終了時に結果を受け取る場合は、startActivityForResult() を呼び出します。アクティビティは、アクティビティの onActivityResult() コールバックで、結果を別の Intent オブジェクトとして受け取ります。詳しくは、アクティビティ ガイドをご覧ください。

  • サービスを開始する

    Service は、ユーザー インターフェースなしでバックグラウンドでオペレーションを実行するコンポーネントです。Android 5.0(API レベル 21)以降では、JobScheduler を使用してサービスを開始できます。JobScheduler の詳細については、API-reference documentation をご覧ください。

    Android 5.0(API レベル 21)より前のバージョンでは、Service クラスのメソッドを使用してサービスを開始できます。startService()Intent を渡すことで、1 回限りのオペレーション(ファイルのダウンロードなど)を実行するサービスを開始できます。Intent は、起動するサービスを記述し、必要なデータを伝送します。

    サービスがクライアント サーバー インターフェースで設計されている場合は、IntentbindService() に渡すことで、別のコンポーネントからサービスにバインドできます。詳細については、サービスガイドをご覧ください。

  • ブロードキャストの配信

    ブロードキャストは、どのアプリでも受信できるメッセージです。システムは、システムの起動やデバイスの充電の開始など、システム イベントに関するさまざまなブロードキャストを配信します。IntentsendBroadcast() または sendOrderedBroadcast() に渡すことで、他のアプリにブロードキャストを配信できます。

このページの残りの部分では、インテントの仕組みと使用方法について説明します。関連情報については、他のアプリと連携するコンテンツを共有するをご覧ください。

インテントの種類

インテントには次の 2 種類があります。

  • 明示的インテントは、完全な ComponentName を指定することで、どのアプリのどのコンポーネントがインテントを満たすかを指定します。通常、自分のアプリのコンポーネントを起動するには明示的インテントを使用します。起動するアクティビティまたはサービスのクラス名がわかっているためです。たとえば、ユーザーの操作に応じてアプリ内で新しいアクティビティを開始したり、バックグラウンドでファイルをダウンロードするサービスを開始したりできます。
  • 暗黙的インテントは、特定のコンポーネントを指定するのではなく、実行する一般的なアクションを宣言します。これにより、別のアプリのコンポーネントがそのアクションを処理できるようになります。たとえば、地図上にユーザーの現在地を表示したい場合は、暗黙的インテントを使用して、指定された場所を地図上に表示するよう別の対応アプリにリクエストできます。

図 1 は、アクティビティの開始時にインテントがどのように使用されるかを示しています。Intent オブジェクトが特定のアクティビティ コンポーネントを明示的に指定している場合、システムは直ちにそのコンポーネントを起動します。

図 1. 暗黙的インテントがシステムを介して配信され、別のアクティビティが開始される仕組み: [1] アクティビティ A がアクションの説明を含む Intent を作成し、それを startActivity() に渡します。[2] Android システムは、インテントに一致するインテント フィルタをすべてのアプリから検索します。一致が見つかると、[3] システムは、一致するアクティビティ(アクティビティ B)の onCreate() メソッドを呼び出し、Intent を渡すことで、そのアクティビティを開始します。

暗黙的インテントを使用すると、Android システムは、インテントの内容をデバイス上の他のアプリのマニフェスト ファイルで宣言されたインテント フィルタと比較して、起動する適切なコンポーネントを見つけます。インテントがインテント フィルタと一致する場合、システムはそのコンポーネントを開始し、そのコンポーネントに Intent オブジェクトを渡します。複数のインテント フィルタが互換性を持つ場合、システムはダイアログを表示し、ユーザーが使用するアプリを選択できるようにします。

インテント フィルタは、アプリのマニフェスト ファイル内の式で、コンポーネントが受け取るインテントのタイプを指定します。たとえば、アクティビティのインテント フィルタを宣言すると、他のアプリが特定種類のインテントでアクティビティを直接起動できるようになります。同様に、アクティビティのインテント フィルタを宣言しない場合、そのアクティビティは明示的インテントでのみ起動できます。

注意: アプリの安全性を確保するため、Service の起動には必ず明示的インテントを使用します。このサービスにはインテント フィルタを宣言しないでください。暗黙的インテントを使用してサービスを開始すると、どのサービスがインテントに応答するのかを把握できず、ユーザーにはどのサービスが開始するのかがわからないため、セキュリティ上の危険が伴います。Android 5.0(API レベル 21)以降では、暗黙的インテントを使用して bindService() を呼び出すと、システムから例外がスローされます。

インテントを作成する

Intent オブジェクトには、Android システムが起動するコンポーネントを決定するために使用する情報(正確なコンポーネント名やインテントを受け取るコンポーネントのカテゴリなど)と、受信側のコンポーネントがアクションを適切に実行するために使用する情報(実行するアクションやアクションの対象となるデータなど)が含まれています。

Intent に含まれる主な情報は次のとおりです。

コンポーネント名
起動するコンポーネントの名前。

これは省略可能ですが、インテントを明示的にする重要な情報です。つまり、インテントはコンポーネント名で定義されたアプリ コンポーネントにのみ配信されます。コンポーネント名がない場合、インテントは暗黙的になり、システムは他のインテント情報(アクション、データ、カテゴリなど。後述)に基づいて、どのコンポーネントがインテントを受け取るべきかを決定します。アプリ内の特定のコンポーネントを起動する必要がある場合は、コンポーネント名を指定する必要があります。

注: Service を起動するときは、常にコンポーネント名を指定してください。そうでない場合、どのサービスがインテントに応答するかを把握できず、ユーザーにはどのサービスが開始するのかがわかりません。

Intent のこのフィールドは ComponentName オブジェクトです。これは、アプリのパッケージ名を含むターゲット コンポーネントの完全修飾クラス名(例: com.example.ExampleActivity)を使用して指定できます。コンポーネント名は、setComponent()setClass()setClassName()、または Intent コンストラクタで設定できます。

操作
実行する一般的なアクション(viewpick など)を指定する文字列。

ブロードキャスト インテントの場合、これは発生してレポートされているアクションです。アクションは、インテントの残りの部分の構造(特に、データとエクストラに含まれる情報)を大きく左右します。

アプリ内のインテントで使用する(または、他のアプリがアプリ内のコンポーネントを呼び出すために使用する)独自のアクションを指定できますが、通常は Intent クラスまたは他のフレームワーク クラスで定義されたアクション定数を指定します。アクティビティを開始する一般的なアクションは次のとおりです。

ACTION_VIEW
ギャラリー アプリで表示する写真や、地図アプリで表示する住所など、アクティビティでユーザーに表示できる情報がある場合は、startActivity() を含むインテントでこのアクションを使用します。
ACTION_SEND
共有インテントとも呼ばれます。メールアプリやソーシャル共有アプリなど、別のアプリを通じてユーザーが共有できるデータがある場合は、startActivity() を含むインテントで使用する必要があります。

汎用アクションを定義する定数については、Intent クラスのリファレンスをご覧ください。その他のアクションは、Android フレームワークの別の場所で定義されています。たとえば、システムの設定アプリで特定の画面を開くアクションは Settings で定義されています。

インテントのアクションは、setAction() または Intent コンストラクタで指定できます。

独自のアクションを定義する場合は、次の例に示すように、アプリのパッケージ名を接頭辞として必ず含めてください。

Kotlin

const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"

Java

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
データ
処理対象のデータを参照する URI(Uri オブジェクト)と、そのデータの MIME タイプ。提供されるデータの種類は、通常、インテントのアクションによって決まります。たとえば、アクションが ACTION_EDIT の場合、データには編集するドキュメントの URI が含まれている必要があります。

インテントを作成する際は、URI に加えてデータのタイプ(MIME タイプ)を指定することが重要になることがよくあります。たとえば、URI の形式が似ていても、画像を表示できるアクティビティは音声ファイルを再生できない可能性があります。データの MIME タイプを指定すると、Android システムはインテントを受け取る最適なコンポーネントを見つけやすくなります。ただし、特にデータが content: URI の場合は、URI から MIME タイプを推測できることがあります。content: URI は、データがデバイス上にあり、ContentProvider によって制御されていることを示します。これにより、データの MIME タイプがシステムに認識されます。

データ URI のみを設定するには、setData() を呼び出します。MIME タイプのみを設定するには、setType() を呼び出します。必要に応じて、setDataAndType() を使用して両方を明示的に設定できます。

注意: URI と MIME タイプの両方を設定する場合は、setData()setType() を呼び出さないでください。それぞれが他方の値を null にします。URI と MIME タイプの両方を設定する場合は、常に setDataAndType() を使用します。

カテゴリ
インテントを処理するコンポーネントの種類に関する追加情報を含む文字列。インテントには任意の数のカテゴリの説明を配置できますが、ほとんどのインテントではカテゴリは必要ありません。一般的なカテゴリを次に示します。
CATEGORY_BROWSABLE
ターゲット アクティビティは、ウェブブラウザから起動して、画像やメール メッセージなど、リンクで参照されるデータを表示できます。
CATEGORY_LAUNCHER
アクティビティはタスクの初期アクティビティであり、システムのアプリ ランチャーに表示されます。

カテゴリの完全なリストについては、Intent クラスの説明をご覧ください。

addCategory() を使用してカテゴリを指定できます。

上記のプロパティ(コンポーネント名、アクション、データ、カテゴリ)は、インテントの定義特性を表します。Android システムは、これらのプロパティを読み取ることで、どのアプリ コンポーネントを起動すべきかを解決できます。ただし、インテントには、アプリ コンポーネントへの解決方法に影響しない追加情報を含めることができます。インテントは次の情報も提供できます。

おまけ
リクエストされたアクションを完了するために必要な追加情報を伝達する Key-Value ペア。特定のアクションが特定の種類のデータ URI を使用するのと同様に、特定のアクションが特定の追加情報を使用することもあります。

さまざまな putExtra() メソッドを使用してエクストラ データを追加できます。各メソッドは、キー名と値の 2 つのパラメータを受け取ります。すべての追加データを含む Bundle オブジェクトを作成し、putExtras() を使用して IntentBundle を挿入することもできます。

たとえば、ACTION_SEND でメールを送信するインテントを作成する場合、EXTRA_EMAIL キーで 宛先を指定し、EXTRA_SUBJECT キーで件名を指定できます。

Intent クラスは、標準化されたデータ型に対して多くの EXTRA_* 定数を指定します。アプリが受け取るインテント用に独自の extras キーを宣言する必要がある場合は、次の例に示すように、アプリのパッケージ名を接頭辞として含めるようにしてください。

Kotlin

const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"

Java

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

注意: 別のアプリが受信することを想定したインテントを送信する際に、Parcelable または Serializable データを使用しないでください。アプリが Bundle オブジェクト内のデータにアクセスしようとしたが、パーセル化またはシリアル化されたクラスにアクセスできない場合、システムは RuntimeException を発生させます。

フラグ
フラグは、インテントのメタデータとして機能する Intent クラスで定義されます。フラグは、アクティビティの起動方法(アクティビティが属するタスクなど)や、起動後のアクティビティの扱い方(最近のアクティビティのリストに属するかどうかなど)を Android システムに指示する場合があります。

詳細については、setFlags() メソッドをご覧ください。

明示的インテントの例

明示的インテントは、アプリ内の特定のアクティビティやサービスなど、特定のアプリ コンポーネントを起動するために使用するインテントです。明示的インテントを作成するには、Intent オブジェクトのコンポーネント名を定義します。他のインテント プロパティはすべて省略可能です。

たとえば、ウェブからファイルをダウンロードするように設計された DownloadService という名前のサービスをアプリでビルドした場合、次のコードで開始できます。

Kotlin

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
val downloadIntent = Intent(this, DownloadService::class.java).apply {
    data = Uri.parse(fileUrl)
}
startService(downloadIntent)

Java

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Intent(Context, Class) コンストラクタは、アプリの Context とコンポーネントに Class オブジェクトを提供します。そのため、このインテントはアプリの DownloadService クラスを明示的に起動します。

サービスのビルドと起動について詳しくは、サービスガイドをご覧ください。

暗黙的インテントの例

暗黙的インテントは、アクションを実行できるデバイス上の任意のアプリを呼び出すことができるアクションを指定します。暗黙的インテントは、アプリでアクションを実行できないが、他のアプリでは実行できる可能性があり、ユーザーにどのアプリを使用するかを選択してもらいたい場合に便利です。

たとえば、ユーザーに他のユーザーと共有してほしいコンテンツがある場合は、ACTION_SEND アクションでインテントを作成し、共有するコンテンツを指定するエクストラを追加します。このインテントで startActivity() を呼び出すと、ユーザーはコンテンツを共有するアプリを選択できます。

Kotlin

// Create the text message with a string.
val sendIntent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, textMessage)
    type = "text/plain"
}

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

Java

// Create the text message with a string.
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

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

startActivity() が呼び出されると、システムはインストールされているすべてのアプリを調べて、この種類のインテント(ACTION_SEND アクションを持ち、「text/plain」データを運ぶインテント)を処理できるアプリを特定します。処理できるアプリが 1 つしかない場合は、そのアプリがすぐに開き、インテントが渡されます。他のアプリが処理できない場合、アプリは発生した ActivityNotFoundException を捕捉できます。複数のアクティビティがインテントを受け入れる場合、図 2 に示すようなダイアログが表示され、ユーザーが使用するアプリを選択できます。

他のアプリの起動に関する詳細については、ユーザーを別のアプリに送信するガイドもご覧ください。

図 2. チューザ ダイアログ

アプリチューザを強制的に表示する

暗黙的インテントに応答できるアプリが複数ある場合、ユーザーは使用するアプリを選択し、そのアプリをアクションのデフォルトの選択肢にすることができます。デフォルトを選択できる機能は、対象のアクションを実行するときにユーザーが毎回同じアプリを使用することを希望している場合に便利です。たとえば、多くのユーザーは、ウェブページを開くときは 1 つのウェブブラウザだけを使用します。

ただし、複数のアプリがインテントに応答でき、ユーザーが毎回異なるアプリを使用する可能性がある場合は、チューザ ダイアログを明示的に表示する必要があります。チューザ ダイアログでは、アクションに使用するアプリの選択をユーザーに求めます(アクション用のデフォルト アプリを選択することはできません)。たとえば、アプリが ACTION_SEND アクションで「共有」を実行する場合、ユーザーは状況に応じて別のアプリを使用して共有したい場合があります。そのため、図 2 に示すように、常にチューザ ダイアログを使用する必要があります。

チューザを表示するには、次の例に示すように、createChooser() を使用して Intent を作成し、startActivity() に渡します。この例では、createChooser() メソッドに渡されたインテントに応答できるアプリのリストがダイアログに表示され、指定したテキストがダイアログのタイトルとして使用されます。

Kotlin

val sendIntent = Intent(Intent.ACTION_SEND)
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
val title: String = resources.getString(R.string.chooser_title)
// Create intent to show the chooser dialog
val chooser: Intent = Intent.createChooser(sendIntent, title)

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(packageManager) != null) {
    startActivity(chooser)
}

Java

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

インテントの安全でない起動を検出する

アプリは、アプリ内のコンポーネント間を移動するため、または別のアプリに代わってアクションを実行するため、インテントを起動することがあります。Android 12(API レベル 31)以降では、プラットフォームのセキュリティを強化するため、アプリがインテントの安全でない起動を実行したときに警告するデバッグ機能が導入されました。たとえば、アプリがネストされたインテント(別のインテント内でエクストラとして渡されるインテント)の安全でない起動を実行する場合があります。

アプリが次のアクションの両方を実行すると、システムによってインテントの安全でない起動が検出され、StrictMode 違反が発生します。

  1. 配信されたインテントのエクストラから、ネストされたインテントを取り出した。
  2. そのネストされたインテントを使用して(たとえば startActivity()startService()、または bindService() にインテントを渡して)、アプリ コンポーネントを直ちに開始した。

この状況を識別してアプリに変更を加える方法について詳しくは、Medium の Android のネスト インテントに関するブログ記事をご覧ください。

安全でないインテントの起動を確認する

アプリでの安全でないインテントの起動を確認するには、VmPolicy を構成する際に detectUnsafeIntentLaunch() を呼び出します。次のコード スニペットをご覧ください。アプリで StrictMode 違反が検出された場合は、機密に該当する可能性がある情報を保護するために、アプリの実行を停止することをおすすめします。

Kotlin

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}

Java

protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

より厳格なインテントの使い方

安全でないインテントの起動や StrictMode 違反の可能性を最小限に抑えるには、次のベスト プラクティスに従ってください。

インテント内の必須のエクストラのみをコピーして、必要なサニタイズと検証を行います。アプリは、あるインテントから、新しいコンポーネントの起動に使用される別のインテントに、エクストラをコピーすることがあります。これは、アプリが putExtras(Intent) または putExtras(Bundle) を呼び出したときに発生します。アプリがこれらのオペレーションのいずれかを実行する場合、受信コンポーネントで想定されるエクストラのみをコピーします。コピーを受信するインテントがエクスポートされていないコンポーネントを起動する場合は、エクストラをサニタイズして検証してから、コンポーネントを起動するインテントにコピーします。

アプリのコンポーネントを不必要にエクスポートしないでください。たとえば、内部のネストされたインテントを使用してアプリ コンポーネントを起動する場合は、そのコンポーネントの android:exported 属性を false に設定します。

ネストされたインテントの代わりに PendingIntent を使用します。この方法では、別のアプリがその内部の IntentPendingIntent を取り出したとき、別のアプリがアプリの識別子を使用して PendingIntent を起動できます。この構成により、別のアプリはアプリ内の任意のコンポーネント(エクスポートされないコンポーネントを含む)を安全に起動できます。

図 2 の図は、システムが(クライアント)アプリから別の(サービス)アプリに制御を渡し、アプリに戻す方法を示しています。

  1. アプリが、別のアプリのアクティビティを呼び出すインテントを作成します。そのインテント内で、PendingIntent オブジェクトをエクストラとして追加します。この保留中のインテントは、アプリ内のコンポーネントを呼び出します。このコンポーネントはエクスポートされません。
  2. アプリのインテントを受け取ると、別のアプリがネストされた PendingIntent オブジェクトを抽出します。
  3. もう一方のアプリは、PendingIntent オブジェクトで send() メソッドを呼び出します。
  4. 制御がアプリに戻されると、システムはアプリのコンテキストを使用して保留中のインテントを呼び出します。

図 2.ネストされた保留中のインテントを使用する場合のアプリ間通信の図。

暗黙的インテントの受信

アプリが受け取ることができる暗黙的インテントをアドバタイズするには、マニフェスト ファイル<intent-filter> 要素を使用して、アプリの各コンポーネントに対して 1 つ以上のインテント フィルタを宣言します。各インテント フィルタは、インテントのアクション、データ、カテゴリに基づいて、受け入れるインテントのタイプを指定します。システムは、インテントがインテント フィルタのいずれかを通過できる場合にのみ、暗黙的インテントをアプリ コンポーネントに配信します。

注: 明示的インテントは、コンポーネントが宣言するインテント フィルタに関係なく、常にターゲットに配信されます。

アプリ コンポーネントは、実行できる固有のジョブごとに個別のフィルタを宣言する必要があります。たとえば、画像ギャラリー アプリの 1 つのアクティビティに、画像を閲覧するためのフィルタと画像を編集するためのフィルタの 2 つのフィルタを設定できます。アクティビティが開始されると、Intent が検査され、Intent の情報に基づいて動作が決定されます(エディタ コントロールを表示するかどうかなど)。

各インテント フィルタは、アプリのマニフェスト ファイル内の <intent-filter> 要素で定義され、対応するアプリ コンポーネント(<activity> 要素など)内にネストされます。

<intent-filter> 要素を含む各アプリ コンポーネントで、android:exported の値を明示的に設定します。この属性は、アプリ コンポーネントが他のアプリからアクセス可能かどうかを示します。インテント フィルタに LAUNCHER カテゴリが含まれるアクティビティなど、状況によっては、この属性を true に設定すると便利です。それ以外の場合は、この属性を false に設定する方が安全です。

警告: アプリのアクティビティ、サービス、またはブロードキャスト レシーバがインテント フィルタを使用し、android:exported の値を明示的に設定していない場合、Android 12 以降を実行しているデバイスにアプリをインストールできません。

<intent-filter> 内で、次の 3 つの要素の 1 つ以上を使用して、受け入れるインテントのタイプを指定できます。

<action>
name 属性で、受け入れられるインテント アクションを宣言します。値はクラス定数ではなく、アクションのリテラル文字列値にする必要があります。
<data>
データ URI(schemehostportpath)と MIME タイプのさまざまな側面を指定する 1 つ以上の属性を使用して、受け入れ可能なデータの型を宣言します。
<category>
name 属性で、受け入れられるインテント カテゴリを宣言します。値はクラス定数ではなく、アクションのリテラル文字列値にする必要があります。

注: 暗黙的インテントを受け取るには、インテント フィルタ内に CATEGORY_DEFAULT カテゴリを含める必要がありますstartActivity() メソッドと startActivityForResult() メソッドは、CATEGORY_DEFAULT カテゴリを宣言しているものとして、すべてのインテントを処理します。インテント フィルタ内でこのカテゴリを宣言していない場合、暗黙的インテントはアクティビティに変換されません。

たとえば、データ型がテキストの場合に ACTION_SEND インテントを受け取るインテント フィルタを持つアクティビティの宣言は次のようになります。

<activity android:name="ShareActivity" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

<action><data><category> のインスタンスを複数含むフィルタを作成できます。その場合は、コンポーネントがこれらのフィルタ要素のすべての組み合わせを処理できることを確認する必要があります。

複数の種類のインテントを処理したいが、アクション、データ、カテゴリ タイプの特定の組み合わせでのみ処理したい場合は、複数のインテント フィルタを作成する必要があります。

暗黙的インテントは、インテントを 3 つの要素のそれぞれと比較することで、フィルタに対してテストされます。コンポーネントに配信されるには、インテントが 3 つのテストすべてに合格する必要があります。1 つでも一致しない場合、Android システムはコンポーネントにインテントを配信しません。ただし、コンポーネントには複数のインテント フィルタを設定できるため、コンポーネントのフィルタの 1 つを通過しなかったインテントが、別のフィルタを通過する可能性があります。システムがインテントを解決する方法について詳しくは、下記のインテントの解決に関するセクションをご覧ください。

注意: インテント フィルタを使用しても、他のアプリがコンポーネントを起動するのを安全に防ぐことはできません。インテント フィルタは、コンポーネントが特定の種類の暗黙的インテントにのみ応答するように制限しますが、デベロッパーがコンポーネント名を特定した場合、別のアプリが明示的インテントを使用してアプリ コンポーネントを起動する可能性があります。独自のアプリのみがコンポーネントの 1 つを起動できるようにすることが重要な場合は、マニフェストでインテント フィルタを宣言しないでください。代わりに、そのコンポーネントの exported 属性を "false" に設定します。

同様に、別のアプリの Service を誤って実行しないように、独自のサービスを開始するには常に明示的インテントを使用します。

注: すべてのアクティビティについて、マニフェスト ファイルでインテント フィルタを宣言する必要があります。ただし、ブロードキャスト レシーバのフィルタは、registerReceiver() を呼び出すことで動的に登録できます。その後、unregisterReceiver() を使用してレシーバの登録を解除できます。これにより、アプリの実行中に、指定した期間のみ特定のブロードキャストをリッスンできます。

フィルタの例

インテント フィルタの動作を示すため、ソーシャル共有アプリのマニフェスト ファイルの例を次に示します。

<activity android:name="MainActivity" android:exported="true">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity" android:exported="false">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>

最初のアクティビティ MainActivity は、アプリのメイン エントリ ポイントです。つまり、ユーザーがランチャー アイコンを使用してアプリを最初に起動したときに開くアクティビティです。

  • ACTION_MAIN アクションは、これがメインのエントリ ポイントであり、インテント データは想定されていないことを示します。
  • CATEGORY_LAUNCHER カテゴリは、このアクティビティのアイコンをシステムのアプリ ランチャーに配置する必要があることを示します。<activity> 要素で icon を使用してアイコンが指定されていない場合、システムは <application> 要素のアイコンを使用します。

アクティビティをアプリ ランチャーに表示するには、この 2 つをペア設定する必要があります。

2 つ目のアクティビティ ShareActivity は、テキストとメディア コンテンツの共有を容易にすることを目的としています。ユーザーは MainActivity からこのアクティビティに移動してアクセスできますが、2 つのインテント フィルタのいずれかに一致する暗黙的インテントを発行する別のアプリから ShareActivity に直接アクセスすることもできます。

注: MIME タイプ application/vnd.google.panorama360+jpg は、パノラマ写真を表す特殊なデータ型です。このデータ型は、Google パノラマ API で処理できます。

インテントと他のアプリのインテント フィルタを一致させる

別のアプリが Android 13(API レベル 33)以上をターゲットとしている場合、そのアプリの <intent-filter> 要素のアクションとカテゴリにインテントが一致する場合にのみ、そのアプリはインテントを処理できます。一致するものが見つからない場合、システムは ActivityNotFoundException をスローします。送信側アプリはこの例外を処理する必要があります。

同様に、アプリを Android 13 以上をターゲットとするようにアップデートした場合、外部アプリから発信されるすべてのインテントは、アプリが宣言する <intent-filter> 要素のアクションとカテゴリに一致する場合にのみ、アプリのエクスポート済みコンポーネントに配信されます。この動作は、送信側アプリのターゲット SDK バージョンに関係なく発生します。

次の場合、インテント マッチングは適用されません。

  • インテント フィルタを宣言していないコンポーネントに配信されるインテント。
  • 同じアプリからのインテント。
  • システムからのインテント、つまり「システム UID」(uid=1000)から送信されるインテント。システムアプリとしては、system_server と、android:sharedUserIdandroid.uid.system に設定するアプリがあります。
  • ルートからのインテント。

詳しくは、インテント マッチングに関する記事をご覧ください。

ペンディング インテントの使用

PendingIntent オブジェクトは Intent オブジェクトのラッパーです。PendingIntent の主な目的は、含まれている Intent をアプリ自身のプロセスから実行されたかのように使用する権限を外部アプリに付与することです。

保留中のインテントの主なユースケースは次のとおりです。

  • ユーザーが Notification でアクションを実行したときに実行されるインテントを宣言します(Android システムの NotificationManagerIntent を実行します)。
  • ユーザーがアプリ ウィジェットでアクションを実行したときに実行されるインテントを宣言します(ホーム画面アプリが Intent を実行します)。
  • 指定した将来の時刻に実行されるインテントを宣言します(Android システムの AlarmManagerIntent を実行します)。

Intent オブジェクトが特定のタイプのアプリ コンポーネント(ActivityServiceBroadcastReceiver のいずれか)で処理されるように設計されているのと同様に、PendingIntent も同じ考慮事項に基づいて作成する必要があります。保留中のインテントを使用する場合、アプリは startActivity() などの呼び出しでインテントを実行しません。代わりに、それぞれのクリエーター メソッドを呼び出して PendingIntent を作成するときに、目的のコンポーネント タイプを宣言する必要があります。

アプリが他のアプリから保留中のインテントを受信している場合を除き、PendingIntent を作成する上記のメソッドは、おそらく必要な唯一の PendingIntent メソッドです。

各メソッドは、現在のアプリの Context、ラップする Intent、インテントの使用方法を指定する 1 つ以上のフラグ(インテントを複数回使用できるかどうかなど)を受け取ります。

保留中のインテントの使用について詳しくは、通知アプリ ウィジェットの API ガイドなど、それぞれのユースケースのドキュメントをご覧ください。

可変性を指定する

アプリが Android 12 以降を対象としている場合、アプリが作成する各 PendingIntent オブジェクトの可変性を指定する必要があります。特定の PendingIntent オブジェクトが可変または不変であることを宣言するには、PendingIntent.FLAG_MUTABLE フラグまたは PendingIntent.FLAG_IMMUTABLE フラグをそれぞれ使用します。

アプリがどちらの可変性フラグも設定せずに PendingIntent オブジェクトを作成しようとすると、IllegalArgumentException がスローされ、logcat に次のメッセージが表示されます。

PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

可能な限り不変のペンディング インテントを作成する

ほとんどの場合において、アプリでは不変の PendingIntent オブジェクトを作成するようにしてください(次のコード スニペットを参照)。PendingIntent オブジェクトが不変の場合、他のアプリはそのインテントを変更して、インテント呼び出しの結果を調整することはできません。

Kotlin

val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

ただし、次の場合には可変の PendingIntent オブジェクトを作成する必要があります。

  • 通知でのダイレクト返信アクションをサポートします。ダイレクト返信が、返信に関連付けられた PendingIntent オブジェクト内のクリップデータの変更を必要とする場合。通常は、fillIn() メソッドに FILL_IN_CLIP_DATA をフラグとして渡すことにより、この変更をリクエストします。
  • CarAppExtender のインスタンスを使用して、通知を Android Auto フレームワークに関連付けます。
  • PendingIntent のインスタンスを使用して会話をバブルに配置します。可変の PendingIntent オブジェクトを使用すると、システムは FLAG_ACTIVITY_MULTIPLE_TASKFLAG_ACTIVITY_NEW_DOCUMENT などの正しいフラグを適用できます。
  • requestLocationUpdates() などの API を呼び出してデバイスの位置情報をリクエストする。変更可能な PendingIntent オブジェクトを使用すると、システムは位置情報のライフサイクル イベントを表すインテント エクストラを追加できます。これらのイベントには、位置情報の変更やプロバイダの利用可能状態の変更が含まれます。
  • AlarmManager を使用してアラームをスケジュールする。変更可能な PendingIntent オブジェクトにより、システムは EXTRA_ALARM_COUNT インテント エクストラを追加できます。このエクストラは、繰り返しアラームがトリガーされた回数を表します。このエクストラを含めることで、デバイスがスリープ状態だった場合など、繰り返しアラームが複数回トリガーされたかどうかをアプリに正確に通知できます。

アプリで可変の PendingIntent オブジェクトを作成する場合は、明示的インテントを使用して ComponentName の値をフィルインすることを強くおすすめします。そうすれば、別のアプリが PendingIntent を呼び出してアプリに制御を戻すたびに、常にアプリ内の同じコンポーネントが開始されます。

保留中のインテント内で明示的インテントを使用する

他のアプリがアプリの保留中のインテントを使用する方法をより明確に定義するには、常に保留中のインテントを明示的インテントでラップします。このベスト プラクティスを実践するには、次の操作を行います。

  1. ベース インテントのアクション、パッケージ、コンポーネントの各フィールドが設定されていることを確認します。
  2. Android 6.0(API レベル 23)で追加された FLAG_IMMUTABLE を使用して、保留中のインテントを作成します。このフラグにより、PendingIntent を受信したアプリが未入力プロパティを入力するのを防ぐことができます。アプリの minSdkVersion22 以下の場合、次のコードを使用して安全性と互換性を同時に提供できます。

    if (Build.VERSION.SDK_INT >= 23) {
      // Create a PendingIntent using FLAG_IMMUTABLE.
    } else {
      // Existing code that creates a PendingIntent.
    }

インテントの解決

システムがアクティビティを開始する暗黙的インテントを受け取ると、3 つの側面に基づいてインテント フィルタと比較し、そのインテントに最適なアクティビティを検索します。

  • アクション。
  • データ(URI とデータ型の両方)。
  • カテゴリ。

以降のセクションでは、アプリのマニフェスト ファイルのインテント フィルタ宣言に従って、インテントが適切なコンポーネントにどのように照合されるかについて説明します。

アクション テスト

受け入れ可能なインテント アクションを指定するには、次の例に示すように、インテント フィルタで 0 個以上の <action> 要素を宣言します。

<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

このフィルタを通過するには、Intent で指定されたアクションが、フィルタにリストされているアクションのいずれかと一致する必要があります。

フィルタにアクションがリストされていない場合、インテントが一致するものが何もないため、すべてのインテントがテストに失敗します。ただし、Intent でアクションが指定されていない場合、フィルタに 1 つ以上のアクションが含まれていれば、テストは合格となります。

カテゴリテスト

受け入れ可能なインテント カテゴリを指定するには、次の例に示すように、インテント フィルタで 0 個以上の <category> 要素を宣言できます。

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

インテントがカテゴリ テストに合格するには、Intent のすべてのカテゴリがフィルタ内のカテゴリと一致する必要があります。逆は必要ありません。インテント フィルタは Intent で指定されたカテゴリよりも多くのカテゴリを宣言できますが、Intent は引き続き渡されます。したがって、カテゴリのないインテントは、フィルタで宣言されているカテゴリに関係なく、常にこのテストに合格します。

注: Android は、startActivity()startActivityForResult() に渡されるすべての暗黙的インテントに CATEGORY_DEFAULT カテゴリを自動的に適用します。アクティビティで暗黙的インテントを受け取るには、前の <intent-filter> の例に示すように、インテント フィルタに "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 の各部分は、schemehostportpath という個別の属性です。

<scheme>://<host>:<port>/<path>

次の例は、これらの属性の可能な値を示しています。

content://com.example.project:200/folder/subfolder/etc

この URI では、スキームは content、ホストは com.example.project、ポートは 200、パスは folder/subfolder/etc です。

これらの属性は <data> 要素では省略可能ですが、線形依存関係があります。

  • スキームが指定されていない場合、ホストは無視されます。
  • ホストが指定されていない場合、ポートは無視されます。
  • スキームとホストの両方が指定されていない場合、パスは無視されます。

インテントの URI がフィルタの URI 仕様と比較される場合、フィルタに含まれる URI の部分のみが比較されます。次に例を示します。

  • フィルタでスキームのみが指定されている場合、そのスキームのすべての URI がフィルタに一致します。
  • フィルタでスキームとオーソリティが指定されていて、パスが指定されていない場合、パスに関係なく、同じスキームとオーソリティを持つすべての URI がフィルタを通過します。
  • フィルタでスキーム、権限、パスが指定されている場合、同じスキーム、権限、パスを持つ URI のみがフィルタを通過します。

注: パス名の部分一致のみを必要とする場合は、パスの指定にワイルドカードのアスタリスク(*)を含めることができます。

データテストでは、インテントの URI と MIME タイプを、フィルタで指定された URI と MIME タイプと比較します。ルールは次のとおりです。

  1. URI も MIME タイプも含まないインテントは、フィルタが URI も MIME タイプも指定していない場合にのみテストに合格します。
  2. URI を含むが MIME タイプを含まない(明示的にも URI から推測可能でもない)インテントは、その URI がフィルタの URI 形式と一致し、フィルタも同様に MIME タイプを指定していない場合にのみ、テストに合格します。
  3. MIME タイプは含むが URI は含まないインテントは、フィルタが同じ MIME タイプをリストし、URI 形式を指定していない場合にのみテストに合格します。
  4. URI と MIME タイプ(明示的または URI から推測可能)の両方を含むインテントは、そのタイプがフィルタにリストされているタイプと一致する場合にのみ、テストの MIME タイプ部分に合格します。テストの URI がフィルタ内の URI と一致する場合、または content: URI か file: URI を持ち、フィルタで URI が指定されていない場合、テストの URI 部分は合格します。つまり、コンポーネントのフィルタに MIME タイプのみがリストされている場合、そのコンポーネントは content: データと file: データをサポートしていると見なされます。

注: インテントで URI または MIME タイプが指定されている場合、<intent-filter><data> 要素がないと、データテストは失敗します。

最後のルール(d)は、コンポーネントがファイルまたはコンテンツ プロバイダからローカルデータを取得できることを前提としています。そのため、フィルタにはデータ型のみを指定でき、content: スキーマと file: スキーマを明示的に指定する必要はありません。次の例は、<data> 要素が、コンポーネントがコンテンツ プロバイダから画像データを取得して表示できることを Android に伝える一般的なケースを示しています。

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

データ型は指定するが URI は指定しないフィルタは、おそらく最も一般的です。利用可能なデータのほとんどはコンテンツ プロバイダによって提供されるためです。

もう 1 つの一般的な構成は、スキーマとデータ型を含むフィルタです。たとえば、次のような <data> 要素は、アクションを実行するためにコンポーネントがネットワークから動画データを取得できることを Android に伝えます。

<intent-filter>
    <data android:scheme="http" android:mimeType="video/*" />
    ...
</intent-filter>

インテント マッチング

インテントは、アクティブにするターゲット コンポーネントを検出するだけでなく、デバイス上のコンポーネントのセットに関する情報を検出するためにも、インテント フィルタと照合されます。たとえば、ホームアプリは、ACTION_MAIN アクションと CATEGORY_LAUNCHER カテゴリを指定するインテント フィルタを持つすべてのアクティビティを見つけて、アプリ ランチャーに表示します。IntentFilter クラスのドキュメントで説明されているように、インテントのアクションとカテゴリがフィルタと一致する場合にのみ、一致が成功します。

アプリケーションは、Google Home アプリと同様の方法でインテント マッチングを使用できます。PackageManager には、特定のインテントを受け取ることができるすべてのコンポーネントを返す query...() メソッドのセットと、インテントに応答する最適なコンポーネントを決定する resolve...() メソッドの同様のシリーズがあります。たとえば、queryIntentActivities() は引数として渡されたインテントを実行できるすべてのアクティビティのリストを返し、queryIntentServices() は同様のサービスのリストを返します。どちらのメソッドもコンポーネントを有効化するのではなく、応答できるコンポーネントをリストするだけです。ブロードキャスト レシーバにも同様のメソッド queryBroadcastReceivers() があります。