1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】暗黙的インテントを受け取るにはどうすればいいのか

Posted at

はじめに

Androidアプリでは、Activityや他アプリのサービスを起動するときにIntentを使います。
自分自身Intentについてふわっとした理解だったので、Intentについて整理をしつつ、暗黙的Intentをどうやって受け取るようにするのかについてまとめたいと思います

Intentは何者なのか

公式ガイドでは、Intentは「別のアプリ コンポーネントからのアクションをリクエストするために使用できるメッセージング オブジェクト」と紹介されています。

Intent は、別のアプリ コンポーネントからのアクションをリクエストするために使用できるメッセージング オブジェクトです。

コンポーネントとは、ActivityやService、BroadcastReceiver等のアプリで使っている部品のことですね。
IntentはActivity、Service、BroadcastReceiverに対して「アクションを実行して欲しい」というメッセージを送るために使用されるオブジェクトになります。

アクションというのは、例えば以下のようなことです。

  • アプリ内の特定のActivityを起動してほしい
  • カメラアプリを起動してほしい
  • 他のアプリにデータを渡してほしい

アプリ内のコンポーネント起動や、他のアプリのコンポーネント起動でも、Intentを介してリクエストを行います。

2種類のIntent

Intentには2種類あり、明示的Intent暗黙的Intentがあります。

明示的Intent

特定のコンポーネントを明示的に指定するIntentです。
主にアプリ内で他のコンポーネントを呼び出すときに使うIntentになります。
以下のようなActivity起動で使う機会が多く、使うことも多いものかと思います。

明示的Intent.kt
// 特定のコンポーネント(CalledActivity)を明示的に指定して呼び出す
  val intent = Intent(context, CalledActivity::class.java).apply {
                    putExtra(Intent.EXTRA_TEXT, "Internal App")
                }

   context.startActivity(intent)

暗黙的Intent

特定のコンポーネントを明示的に指定せず、アクションやカテゴリを指定するIntentです。
起動するコンポーネントAndroidのシステムが側で決定するようになっており、リクエスト時に指定したアクションやカテゴリをもとに適切なものを選択するようになっています。
image.png
(こちらの公式ガイドから借用)

以下は、他のアプリ(メッセージアプリやメールアプリなど)にテキストメッセージを送る暗黙的Intentになります。

暗黙的Intent.kt
 val intent = Intent().apply {
                    action = Intent.ACTION_SEND
                    type = "text/plain"
                    addCategory(Intent.CATEGORY_DEFAULT)
                    putExtra(Intent.EXTRA_TEXT, "Message")
                }

 context.startActivity(intent)

startActivityを実行すると、Androidシステムが適切なコンポーネントを起動するように動きます。
適切なコンポーネントが複数ある場合は、ユーザーが使用するものを選べるようにダイアログを出してくれます。
サンプルコードの暗黙的Intentを実行すると以下のような画面が出てきます。

暗黙的Intentを受け取れるようにするには

暗黙的IntentはAndroidシステム側が適切なものを選択するとのことですが、Androidシステムがどういう判断で選んでいるのか。

それは、インストールされている各アプリのAndroidManifestのインテントフィルター(intent-filter)です。
暗黙的Intentで設定されたカテゴリ、アクション、データに一致するインテントフィルターを持つアクティビティやサービスを検索し、マッチするものを選択します。
もしマッチするものが複数ある場合は、前述したスクショのようなダイアログでユーザーに提示するようになっています。

実際に下記の暗黙的Intentを受け取れるActivityを自作してみようと思います。

暗黙的Intent.kt
 val intent = Intent().apply {
                    action = Intent.ACTION_SEND
                    type = "text/plain"
                    addCategory(Intent.CATEGORY_DEFAULT)
                    putExtra(Intent.EXTRA_TEXT, "Message")
                }

 context.startActivity(intent)

Activityの作成

下記は暗黙的Intentで呼び出されるActivityになります。
IntentのPutExtraで設定されるテキストを取得し、画面に表示するようになっています。

暗黙的Intentで呼び出されるActivity.kt
class CalledActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        val text = intent.getStringExtra(Intent.EXTRA_TEXT).toString()
        setContent {
            CalledAppTheme  {
                Scaffold(modifier = Modifier.fillMaxSize()) {
                    Box(
                        contentAlignment = Alignment.Center,
                        modifier = Modifier.padding(it).fillMaxSize()
                    ) {
                        Text(text)
                    }
                }
            }
        }
    }
}

次に、このActivityをAndroidシステムの検索でマッチするように、インテントフィルターを定義したいと思います。

AndroidManifestにインテントフィルターを定義

暗黙的Intentを受け取りたいActivity(CalledActivity)にインテントフィルターの定義を設定しました。
受け取りたいIntentに沿ってaction、category、dataを設定する必要があります。
今回受け取りたいIntentは、以下を想定しているので、満たすように定義しています。

  • アクション:ACTION_SEND
  • カテゴリー:CATEGORY_DEFAULT
  • データ:text/plain
AndroidManifest.xml
   <activity
        android:name=".CalledActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>

注意してほしいのが android:exported の部分です。
これは当該のActivityを外部アプリから呼び出せるかどうかの設定となっており、true:呼び出し可能、false:呼び出し不可(アプリ内部のみ可)を定義します。
今回は外部アプリの暗黙的Intentを受け取れるようにしたいので、trueに設定しています。
これをfalseにすると受け取れませんのでご注意ください。
(exportedの設定はAndroid 12以降では必須になっています。)

暗黙的Intentを起動してみる

実際に暗黙的Intentを起動してみると、先ほど作ったActivityがダイアログの候補として表示され、無事Androidシステムが拾ってくれていることを確認できます。

CalledAppを選択すると、作成したAcitivityを開き、Intentからメッセージ取得して画面に表示されます。

おまけ

暗黙的Intentのアクションですが、独自に定義することも可能です。
独自をアクションを定義すると、暗黙的Intentでも、特定のアプリのコンポーネントを起動することができます。
独自のアクションを定義する際のルールとしては、必ずプレフィックスとしてアプリのパッケージ名を必ず含めてユニークなものにする必要があります。

独自のアクションを定義.xml
 <activity
        android:name=".CalledActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.calledapp.action.open" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
独自のアクションを使用した暗黙的Intent.kt
val intent = Intent().apply {
                    action = "com.example.calledapp.action.open"
                    type = "text/plain"
                    putExtra(Intent.EXTRA_TEXT, "独自のアクションで呼び出す")
                }

context.startActivity(intent)

上記暗黙的Intentを起動すると、起動アプリを選択するダイアログは表示されず、すぐに指定したActivityを起動します。

おわり

私自身何となく使っていたIntentについて、公式ガイドを参照しながら自分なりに整理しました。
暗黙的Intentがどのように実行されているのかや、独自アクションを使った方法など、これまで知らなかったことが多く、新しい発見がありました。
特に独自アクションは初耳で、どのような場面で使うのか具体的なイメージはまだ湧いていません。
ただ、協業するアプリ間でのデータのやり取りや特定の機能を呼び出すときに役立つのかもと思いました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?