他のアプリからのアクティビティの開始を許可する

前 2 回のレッスンでは、自分のアプリから別のアプリのアクティビティを開始する場合について焦点を当てました。 一方、自分のアプリで別のアプリにとって役に立つかもしれないアクションを実行できる場合について、自分のアプリが他のアプリからのアクション要求に応答できるようにする必要があります。 たとえば、友人とメッセージや写真を共有できるソーシャル アプリをビルドした場合、ユーザーが別のアプリから「共有」アクションを開始し、こちら側のアプリを起動してそのアクションを実行できるよう、ACTION_SEND インテントをサポートすることが最善の方法です。

他のアプリからアクティビティを開始できるようにするには、対応する <activity> 要素のマニフェスト ファイルに <intent-filter> 要素を追加する必要があります。

アプリが端末にインストールされている場合、システムはインテント フィルタを識別し、インストールされているすべてのアプリでサポートされるインテントの内部カタログに情報を追加します。アプリが暗黙的インテントを使って startActivity() または startActivityForResult() を呼び出すと、システムがどのアクティビティ(または複数のアクティビティ)がインテントに応答できるかを特定します。

インテント フィルタを追加する

アクティビティがどのインテントを処理できるか適切に定義するためには、アクティビティが受け入れるアクションとデータのタイプについて、追加する各インテント フィルタをできるだけ具体的にする必要があります。

アクティビティが Intent オブジェクトに関する次の基準を満たしているインテント フィルタを持つ場合、システムは、アクティビティに対して所定の Intent を送信することができます。

アクション
実行するアクション名を表す文字列。通常、ACTION_SENDACTION_VIEW などのプラットフォームに定義された値のいずれか。

<action> 要素を使用してインテント フィルタでこれを指定します。この要素で指定した値は、API 定数ではなく、アクションの完全な文字列名(下記の例を参照)である必要があります。

データ
インテントに関連するデータの詳細。

<data> 要素を使用して、インテント フィルタでこれを指定します。この要素で 1 つ以上の属性を使用して、MIME タイプのみ、URI 接頭辞のみ、URI スキームのみ、またはこれらと受け入れられるデータタイプを示すその他の項目の組み合わせを指定することができます。

注: Uri データに関する詳細を宣言する必要がない場合(アクティビティが URI ではなく他の種類の「特別」データを処理するときなど)は、アクティビティが処理する text/plainimage/jpeg のようなデータタイプを宣言する android:mimeType 属性のみを指定する必要があります。

カテゴリ
インテントを処理するアクティビティを特徴づけるための追加的な方法を提供し、通常はユーザーの操作や起動元の場所に関連付けられます。 システムでサポートされているいくつかの異なるカテゴリがありますが、大抵のカテゴリはほとんど使用されません。 しかし、すべての暗黙的インテントは、デフォルトでは CATEGORY_DEFAULT を使用して定義されています。

<category> 要素を使用して、インテント フィルタでこれを指定します。

インテント フィルタでは、それぞれの基準を <intent-filter> 要素内でネストした対応する XML 要素を使用して宣言することによって、アクティビティが受け入れる基準を宣言することができます。

次に、データタイプがテキストまたは画像の場合に、ACTION_SEND インテントを処理するインテント フィルタを使用したアクティビティの例を示します。

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

受信するインテントはそれぞれ 1 つのアクションと 1 つのデータタイプのみを指定しますが、各 <intent-filter> 内で <action><category><data> 要素の複数のインスタンスを宣言することもできます。

アクションとデータのいずれか 2 つのペアが、各自の動作において相互に排他的である場合は、別のインテント フィルタを作成して、どのデータタイプと組み合わされたときにとのアクションが受け入れられるかを指定する必要があります。

たとえば、アクティビティが ACTION_SENDACTION_SENDTO の両方のインテントに関してテキストと画像の両方を処理するとします。この場合は、次の 2 つのアクションのための 2 つの別々のインテント フィルタを定義する必要があります。なぜなら ACTION_SENDTO インテントは、URI スキームの send または sendto を使用して受信者のアドレスを指定するために、Uri データを使用する必要があるからです。 次に例を示します。

<activity android:name="ShareActivity">
    <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!-- filter for sending text or images; accepts SEND action and text or image data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

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

ソーシャル共有行動を実行する ACTION_SEND インテントの送受信方法については、レッスン他のアプリから単純なデータを受信するを参照してください。

自分のアクティビティでインテントを処理する

アクティビティで実行するアクションを決定するために、起動時に使用された Intent を読み取ることができます。

アクティビティが開始されたら、getIntent() を呼び出して、アクティビティを開始した Intent を取得します。アクティビティのライフサイクル中はいつでもこれを行うことができますが、通常は、 onCreate()onStart() などの早い段階のコールバックの間に行う必要があります。

次に例を示します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Get the intent that started this activity
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Figure out what to do based on the intent type
    if (intent.getType().indexOf("image/") != -1) {
        // Handle intents with image data ...
    } else if (intent.getType().equals("text/plain")) {
        // Handle intents with text ...
    }
}

結果を返す

呼び出し元のアクティビティに結果を返したい場合は、setResult() を呼び出して結果コードと結果の Intent を指定します。操作が実行され、ユーザーが元のアクティビティに復帰する必要がある場合、finish() を呼び出してアクティビティを閉じます(その後破棄します)。 次に例を示します。

// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));
setResult(Activity.RESULT_OK, result);
finish();

結果に対しては常に結果コードを指定する必要があります。通常、RESULT_OK または RESULT_CANCELED です。その後、必要に応じて Intent を使用して、追加のデータを指定することができます。

注: 結果は、デフォルトでは RESULT_CANCELED に設定されています。したがって、ユーザーがアクションを完了する前に戻るボタンを押して、結果がまだ設定されていない場合、元のアクティビティは「キャンセルされた」結果を受け取ります。

いくつかの結果オプションのいずれかを示す整数を返す必要がある場合は、0 よりも大きい任意の値に結果コードを設定することができます。結果コードを使用して整数を返す場合に Intent を含める必要がなければ、setResult() を呼び出して結果コードのみを渡すことができます。 次に例を示します。

setResult(RESULT_COLOR_RED);
finish();

この場合、可能性のある結果の数はわずかであるため、結果コードは、ローカルに定義されている整数(0 より大きい)になります。 これは、自分が作成したアプリのアクティビティに結果を返す場合に役立ちます。結果を受け取るアクティビティがパブリック定数を参照でき、結果コードの値を判断できるためです。

注: 自分のアクティビティが startActivity() または startActivityForResult() を使用して開始されたかどうかをチェックする必要はありません。 アクティビティを開始したインテントが結果を待っている場合は、setResult() を呼び出します。 元のアクティビティが startActivityForResult() を呼び出していた場合、setResult() に提供した結果がそこに送られます。それ以外の場合は、結果は無視されます。