別のアプリにユーザーを送信する

Android の最も重要な特長の 1 つに、ユーザーが実行を希望する「アクション」に基づいて、別のアプリにユーザーを送信するアプリの機能があります。 たとえば、自分のアプリで地図上に表示したいお店やサービスの住所がある場合、アプリでマップを表示するアクティビティをビルドする必要はありません。 代わりに Intent 使用して、住所を表示するための要求を作成することができます。 Android システムは、マップ上に住所を表示できるアプリを起動します。

第 1 回のクラス、初めてのアプリ作成で説明したように、自分のアプリでのアクティビティ間を移動するためにインテントを使用する必要があります。 通常それには、起動するコンポーネントの正確なクラス名を定義する、明示的なインテントを使用します。 ただし、「マップを表示する」などのアクションを別のアプリに実行させたい場合、暗黙的なインテントを使用する必要があります。

このレッスンでは、特定のアクションの暗黙的インテントを作成する方法や、他のアプリでアクションを実行するアクティビティを開始させる目的で、暗黙的インテントを使用する方法を示します。

暗黙的インテントをビルドする

暗黙的インテントは、開始するコンポーネントのクラス名を宣言せず、代わりに実行するアクションを宣言します。 アクションでは、表示編集送信や、取得などの、希望する操作を指定します。 インテントは、多くの場合、表示対象の住所、送信対象の電子メール メッセージなど、アクションに関連するデータを含みます。作成するインテントにもよりますが、データは Uri、またはその他のいくつかのデータタイプのいずれかとなるか、データ自体まったく必要とならない場合もあります。

データが Uri である場合は、シンプルな Intent() コンストラクタを使用してアクションとデータを定義することができます。

次の例は、電話番号を指定するための Uri のデータを使用して、電話をかけるインテントを作成する方法を示しています。

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

startActivity() を呼び出すことにより、自分のアプリでインテントが起動されると、電話アプリは指定された電話番号への通話を開始します。

ここでは他の 2 つのインテント、およびそのアクションとUri データのペアの例を示します。

  • マップを表示する:
    // 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);
    
  • ウェブページを表示する:
    Uri webpage = Uri.parse("http://www.android.com");
    Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
    

暗黙的インテントのその他の種類には、文字列などのさまざまなデータタイプを提供する「特別」データを必要とします。 さまざまな putExtra() メソッドを使用して、特別データを 1 つ以上追加することができます。

デフォルトでは、インテントに含まれる Uri データに基づいて、インテントに必要な適切な MIME タイプをシステムが決定します。インテントに Uri が含まれていない場合は、通常は setType() を使用して、インテントに関連するデータタイプを指定する必要があります。 MIME タイプの詳細な指定により、どの種類のアクティビティがインテントを受け取るかが指定されます。

ここでは、目的のアクションを指定するための特別データを追加しているインテントの例を示します。

  • 添付ファイル付きのメールを送信する:
    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[] {"jon@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
    
  • カレンダー イベントを作成する:
    Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
    Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
    Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 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");
    

    注: カレンダー イベント用のこのインテントは、API レベル 14 以降でのみサポートされています。

注: できるだけ具体的に Intent を定義することが重要です。たとえば、ACTION_VIEW インテントを使用して画像を表示する場合、image/* の MIME タイプを指定する必要があります。 これにより、他のタイプのデータを「表示」できる(マップアプリのような)アプリがインテントによってトリガーされることを回避します。

インテントを受け取るアプリがあるか確認する

Android プラットフォームは、特定のインテント(電話、メール、カレンダー アプリなど)が内蔵のアプリのいずれかへ解決することを保証しますが、インテントを呼び出す前に常に検証ステップを含める必要があります。

警告: インテントを呼び出した際、端末上で利用可能なインテントを処理できるアプリがない場合、アプリがクラッシュします。

インテントに応答できる利用可能なアクティビティがあるかどうかを確認するには queryIntentActivities() を呼び出して、Intent を処理できるアクティビティのリストを取得します。 返された List が空ではない場合、安全にインテントを使用することができます。次に例を示します。

PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
        PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;

isIntentSafetrue であれば、少なくとも 1 つのアプリがインテントに応答します。 false であれば、インテントを処理するアプリが存在しません。

注: ユーザーがインテントを使用する前にインテントを使用する機能を無効化する必要がある場合、アクティビティが最初に起動するときにこのチェックを実行する必要があります。 インテントを処理できるアプリが具体的にわかっている場合、当該アプリをダウンロードするユーザーのためにリンクを提供することができます(Google Play 上の自分の製品にリンクする方法を参照)。

インテントを使ってアクティビティを開始する

図 1 複数のアプリがインテントを処理することができるときに表示される選択ダイアログの例です。

Intent を作成し、追加情報を設定したら、startActivity() を呼び出してシステムに送信します。システムがインテントを処理することができるアクティビティを複数特定した場合、図 1 に示すように使用するアプリを選択できるダイアログをユーザーに表示します。インテントを処理できるアクティビティが 1 つのみの場合、システムはすぐにそのアクティビティを起動します。

startActivity(intent);

次に、マップを表示するためのインテントを作成し、そのインテントを処理するアプリが存在するかを確認してから起動する、一連の方法について例を示します。

// 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);

// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;

// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent);
}

アプリチューザを表示する

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

自分の IntentstartActivity() に渡してアクティビティを開始した際に、インテントに応答できるアプリが複数ある場合、ユーザーがデフォルトで使用するアプリを選択できること(ダイアログの下部にあるチェックボックスを選択してこれを行います。図 1 を参照)に注意してください。 これは、(1 つのウェブブラウザのみを使用する傾向にあるユーザーが)ウェブページを開いたり、(1 つのカメラを選ぶ傾向にあるユーザーが)写真を撮影したりするときのように、ユーザーがアクション実行時に毎回同じアプリの使用を希望するような場合には有用です。

一方、実行対象のアクションが複数のアプリによって処理できる場合、ユーザーは毎回異なるアプリを選ぶかもしれません。たとえば「共有」アクションにおいては、アイテムの共有に使用するアプリが複数ある可能性があります。この場合、図 2 に示すように、チューザのダイアログを明示的に表示する必要があります。このチューザのダイアログは、アクションのたびにユーザーに使用するアプリを選択させます(ユーザーはアクションのデフォルトのアプリを選択することはできません)。

チューザを表示するには、createChooser() を使用して Intent を作成し、startActivity() に渡します。次に例を示します。

Intent intent = 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 chooser
Intent chooser = Intent.createChooser(intent, title);

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

これにより、createChooser() メソッドに渡されたインテントに応答するアプリのリストがダイアログに表示され、指定されたテキストがダイアログのタイトルになります。