Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

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

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

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

このレッスンでは、特定のアクションを対象とする暗黙的インテントを作成する方法や、暗黙的インテントを使用して、別のアプリ内でアクションを実行するアクティビティを起動する方法について説明します。また、暗黙的インテント用のランタイム チェックを組み込む理由については、下記の動画をご覧ください。

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

暗黙的インテントは、開始するコンポーネントのクラス名を宣言せず、代わりに実行するアクションを宣言します。アクションは、表示、編集、送信、取得など、実行する処理を指定します。また、インテントには、表示を目的とする住所や、送信を目的とするメールなど、アクションに関連付けられたデータが格納されることもよくあります。作成するインテントに応じて、Uri など、各種のデータタイプが格納されます。インテントによっては、データをまったく必要としない場合もあります。

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

たとえば、電話番号を指定する Uri データを使用して、通話を開始するインテントを作成する方法を以下に示します。

Kotlin

    val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
        Intent(Intent.ACTION_DIAL, number)
    }
    

Java

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

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

ほかに 2 つのインテント(およびそのアクションと Uri データのペア)の例を以下に示します。

  • 地図を表示する:

    Kotlin

        // Map point based on address
        val mapIntent: Intent = Uri.parse(
                "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
        ).let { location ->
            // Or map point based on latitude/longitude
            // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
            Intent(Intent.ACTION_VIEW, location)
        }
        

    Java

        // 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);
        
  • ウェブページを表示する:

    Kotlin

        val webIntent: Intent = Uri.parse("http://www.android.com").let { webpage ->
            Intent(Intent.ACTION_VIEW, webpage)
        }
        

    Java

        Uri webpage = Uri.parse("http://www.android.com");
        Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
        

他の種類の暗黙的インテントは、文字列など、さまざまなデータタイプを提供する「エクストラ」データを必要とします。さまざまな putExtra() メソッドを使用することで、エクストラ データを 1 つまたは複数追加することができます。

デフォルトでは、インテント内に格納されている Uri データに基づいて、インテントに必要とされる適切な MIME タイプが自動的に決定されます。インテント内に Uri を格納していない場合、通常は setType() を使用して、インテントに関連付けられるデータタイプを指定することをおすすめします。MIME タイプを詳細に設定することで、インテントが受け取るアクティビティの種類を指定できます。

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

  • 添付ファイル付きのメールを送信する:

    Kotlin

        Intent(Intent.ACTION_SEND).apply {
            // The intent does not have a URI, so declare the "text/plain" MIME type
            type = HTTP.PLAIN_TEXT_TYPE
            putExtra(Intent.EXTRA_EMAIL, arrayOf("jon@example.com")) // recipients
            putExtra(Intent.EXTRA_SUBJECT, "Email subject")
            putExtra(Intent.EXTRA_TEXT, "Email message text")
            putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
            // You can also attach multiple items by passing an ArrayList of Uris
        }
        

    Java

        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
        
  • カレンダー イベントを作成する:

    Kotlin

        Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
            val beginTime: Calendar = Calendar.getInstance().apply {
                set(2012, 0, 19, 7, 30)
            }
            val endTime = Calendar.getInstance().apply {
                set(2012, 0, 19, 10, 30)
            }
            putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
            putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
            putExtra(Events.TITLE, "Ninja class")
            putExtra(Events.EVENT_LOCATION, "Secret dojo")
        }
        

    Java

        Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
        Calendar beginTime = Calendar.getInstance();
        beginTime.set(2012, 0, 19, 7, 30);
        Calendar endTime = Calendar.getInstance();
        endTime.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 が空でなかった場合は、安全にインテントを使用することができます。たとえば、次のようになります。

Kotlin

    val activities: List<ResolveInfo> = packageManager.queryIntentActivities(
            intent,
            PackageManager.MATCH_DEFAULT_ONLY
    )
    val isIntentSafe: Boolean = activities.isNotEmpty()
    

Java

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

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

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

インテントを使用してアクティビティを起動する

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

Intent を作成し、エクストラ情報を設定したら、startActivity() を呼び出してシステムに送信します。インテントを処理できるアクティビティが複数あると判明した場合、図 1 に示すように、使用するアプリを選択できるダイアログ(別名「確認ダイアログ」)が表示されます。インテントを処理できるアクティビティが 1 つのみの場合、システムはすぐにそのアクティビティを起動します。

Kotlin

    startActivity(intent)
    

Java

    startActivity(intent);
    

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

Kotlin

    // Build the intent
    val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
    val mapIntent = Intent(Intent.ACTION_VIEW, location)

    // Verify it resolves
    val activities: List<ResolveInfo> = packageManager.queryIntentActivities(mapIntent, 0)
    val isIntentSafe: Boolean = activities.isNotEmpty()

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

Java

    // 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() に渡します。たとえば、次のようになります。

Kotlin

    val intent = Intent(Intent.ACTION_SEND)
    ...

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

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

Java

    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() メソッドに渡されたインテントに応答できるアプリのリストがダイアログに表示され、指定したテキストがダイアログのタイトルとして使用されます。