😊

【Android開発】暗黙的インテント

2021/01/10に公開

暗黙的インテントとは

アクション(動作)を指定して、それを実行できる端末上のアプリを起動させます。
起動対象が複数ある場合、ユーザーがアプリを選択できます。

呼び出される側のアプリケーションの「AndroidManifest.xml」には、インテントフィルターという、 暗黙的インテントで呼び出すための条件をあらかじめ設定しておきます。

動作環境

Android Studio4.1
windows10

サンプルアプリ

今回は暗黙的インテントを使用して呼び出す側のアプリを作りたいと思います。
以下のイベントを実装します。

  • ウェブページを開く
  • 地図を開く
  • 電話をかける
  • メールを作成する
  • カメラを起動する
  • アラームを作成する
  • タイマーを作成する
  • カレンダーイベントを追加する
  • 連絡先を選択する
  • ファイルを選択する

まずはレイアウトを作成しましょう。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/dial"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="2dp"
        android:onClick="implicitIntentEvent"
        android:text="Dial"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/map"
        app:layout_constraintTop_toTopOf="@+id/map" />

    <Button
        android:id="@+id/web"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="2dp"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Web"
        app:layout_constraintEnd_toStartOf="@+id/map"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/map"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Map"
        app:layout_constraintEnd_toStartOf="@+id/dial"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/web"
        app:layout_constraintTop_toTopOf="@+id/web" />

    <Button
        android:id="@+id/mail"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="2dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Mail"
        app:layout_constraintEnd_toStartOf="@+id/camera"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/web" />

    <Button
        android:id="@+id/camera"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Camera"
        app:layout_constraintEnd_toStartOf="@+id/alarm"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/mail"
        app:layout_constraintTop_toTopOf="@+id/mail" />

    <Button
        android:id="@+id/alarm"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="2dp"
        android:onClick="implicitIntentEvent"
        android:text="Alerm"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/camera"
        app:layout_constraintTop_toTopOf="@+id/camera" />

    <Button
        android:id="@+id/timer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="2dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Timer"
        app:layout_constraintEnd_toStartOf="@+id/calendar"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/mail" />

    <Button
        android:id="@+id/calendar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="1dp"
        android:onClick="implicitIntentEvent"
        android:text="Calendar"
        app:layout_constraintEnd_toStartOf="@+id/contact"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/timer"
        app:layout_constraintTop_toTopOf="@+id/timer" />

    <Button
        android:id="@+id/contact"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="2dp"
        android:onClick="implicitIntentEvent"
        android:text="Contact"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/calendar"
        app:layout_constraintTop_toTopOf="@+id/calendar" />

    <Button
        android:id="@+id/file"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="2dp"
        android:layout_marginTop="16dp"
        android:onClick="implicitIntentEvent"
        android:text="File"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/timer" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivityにイベントの実装をします。

MainActivity.java
package com.example.implicitintent;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.AlarmClock;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void implicitIntentEvent(View view) {

        Intent intent = null;

        switch (view.getId()) {
            case R.id.web: /* WebのUrlを読み込む */
                intent = new Intent(
                    Intent.ACTION_VIEW,
                    Uri.parse("https://developer.android.com/guide")
                );
                break;

            case R.id.map: /* 地図を開く */
                // geo:latitude,longitude
                Uri geoLocation = Uri.parse("geo:35.6585805,139.7432389");
                // クエリ文字列で検索する場合
                // Uri geoLocation = Uri.parse("geo:0,0?q=東京タワー");
                intent = new Intent(
                    Intent.ACTION_VIEW,
                    geoLocation
                );
                break;

            case R.id.dial: /* 電話をかける */
                intent = new Intent(Intent.ACTION_DIAL)
                    .setData(Uri.parse("tel:0123456789"));
                break;

            case R.id.mail: /* メールを作成する */
                intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
                intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"宛先1"});
                intent.putExtra(Intent.EXTRA_CC, new String[]{"宛先2"});
                intent.putExtra(Intent.EXTRA_SUBJECT, "件名をいれます");
                intent.putExtra(Intent.EXTRA_TEXT, "本文をいれます");

                break;

            case R.id.camera: /* カメラを起動する */
                // カメラモードで起動
                String camera = MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
                // 動画モードで起動
                // String movie = MediaStore.INTENT_ACTION_VIDEO_CAMERA;
                intent = new Intent(camera);

                break;

            case R.id.alarm: /* アラームを作成する */
                // ACTION_SET_ALARM インテントを呼び出すには
                // AndroidManifest.xmlにSET_ALARMパーミッションが必要です。
                // <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
                intent = new Intent(AlarmClock.ACTION_SET_ALARM);
                // アラームを識別するメッセージ
                intent.putExtra(AlarmClock.EXTRA_MESSAGE, "set alarm");
                // アラームの時間
                intent.putExtra(AlarmClock.EXTRA_HOUR, 10);
                // アラームの分
                intent.putExtra(AlarmClock.EXTRA_MINUTES, 30);
                // UIをスキップするか
                // true = アプリの画面に遷移しない(ステータスバーに通知される)
                // false = アプリに遷移する
                intent.putExtra(AlarmClock.EXTRA_SKIP_UI, false);

                break;

            case R.id.timer: /* タイマーを作成する */
                intent = new Intent(AlarmClock.ACTION_SET_TIMER)
                    .putExtra(AlarmClock.EXTRA_MESSAGE, "set timer")
                    .putExtra(AlarmClock.EXTRA_LENGTH, 5)
                    .putExtra(AlarmClock.EXTRA_SKIP_UI, false);

                    break;

            case R.id.calendar: /* カレンダー イベントを追加する */
                intent = new Intent(Intent.ACTION_INSERT);
                intent.setData(CalendarContract.Events.CONTENT_URI);
                intent.putExtra(CalendarContract.Events.TITLE, "イベントのタイトルを入れます");
                intent.putExtra(CalendarContract.Events.DESCRIPTION, "イベントの説明を入れます");
                // 終日のイベントかどうかを示すブール値
                intent.putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, false);
                // イベントの開始時間
                intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, 0);
                // イベントの終了時間
                intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, 0);
                // 参加者のメールアドレス
                intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"hoge@mail.com", "foo@gmail.com"});

                break;

            case R.id.contact: /* 連絡先を選択する*/
                intent = new Intent(Intent.ACTION_PICK);
                intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
                break;

            case R.id.file: /* ファイルを選択する */
                intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("image/*");

                break;
        }

        // 端末に暗黙的インテントを受け取ることができるアプリが存在するか確認する
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivity(intent);
        }
    }
}

実行結果

実行結果は以下のようになります。

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

暗黙的インテントに応答するアプリが複数ある場合、ユーザーは使用するアプリを選択でき、そのアプリをアクションのデフォルトの選択肢にできます。

ただしユーザーが毎回別のアプリを使用する可能性がある場合は、チューザダイアログを明示的に表示させます。

チューザを表示するにはcreateChooser()を使用します。

intent = new Intent(
    Intent.ACTION_VIEW,
    Uri.parse("https://developer.android.com/guide")
);

Intent chooser = Intent.createChooser(intent, "chooser title");

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

■実行結果

createChooser()使用 createChooser()未使用

Discussion