【Android】暗黙的Intent と Intent Filter の使い方

2018/11/28 追記

  • リンクが切れている箇所を修正しました。
  • シンタックスハイライトを適用しました。

前書き

AndroidManifest.xmlIntent Filterを設定しておくと、暗黙的 Intent を受信することが出来ます。

Intent は Android アプリの根幹に関わる仕組みなので、ちょっと検索すればすぐに豊富な資料を見つけることが出来るんですが、「実際にどうやって書くのか?」となると結構色んな資料を見なくてはいけないので、一つにまとめたいと思います。

暗黙的 Intent と Intent Filter の仕組み

Intent には遷移するクラスを指定した明示的 Intent と、「こう言う処理がしたいんだけど、誰かできる?」と問い合わせてみる暗黙的 Intent があります。

暗黙的 Intent を発行するにはString action を受け取るコンストラクタを使うか、Intent#setAction(String action)を使用する必要があります。

また、その暗黙的 Intent で処理してもらいたいデータはUriとして渡すことが出来ます。

Intent 送信側の動き

// 電話をかけられるアプリに電話番号を渡す
Intent i = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:08099999999"));

//Intent i = new Intent();
//i.setAction(Intent.ACTION_CALL);
//i.setData(Uri.parse("tel:08099999999"));

startActivity(i);

上記のコードが実行されると、AndroidManifest.xml に以下の記述があるアプリを探してきます。

<intent-filter>
  <action android:name="android.intent.action.DIAL" />
  <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

ただ、必ずしも上記の通りの記述がされているかはわかりません。<category>の値が違ったり、<intent-filter>内に更に<data>が設定されているかもしれません。

が、今回のIntent には ACTION_DIAL しか指定されていないので、とりあえず<intent-filter>にそれが指定されているものを探してきます。

ちなみに、該当するアプリが複数あればユーザにどのアプリを使うか訊いてきます。

Intent 受信側の動き

選択されたアプリ(受信側)はActivity#getIntent()で送られてきた Intent を取得し、Intent#getData()Uri を取得し、Uri のメソッド*1でデータを抽出するわけです。

この仕組みを使うことで、処理を丸ごと別アプリに委譲したり、逆に別アプリからのデータを受け取って処理することが出来ます。また、独自の <action><category> を規定することでアプリのプラグインなどを容易に作成することも出来ます。

<intent-filter>に設定できる属性

ドキュメントを読む限り、AndroidManifest の<intent-filter>に設定できる属性は以下の三つみたいです。

  • android:icon
  • android:label
  • android:priority

何らかのアプリで暗黙的 Intent が送信されると、「それ、ウチで処理できますよ」と手を挙げるアプリが一覧として表示されるわけですが、その時にどう表示するかを設定できるっぽいですね。

直接数値を設定する android:priority 以外はきちんとリソースを用意しておく必要があります。設定しないと<application>の値を自動で継承してくれます。

ちなみに android:priority ですが、Activity に設定しても意味がないとのことです。なんてこったい。

<action>の設定

<intent-filter>に必須の子要素として、<action>があります。これは action の名称を示す属性(name)を指定してあげれば OK です。

じゃあ指定できる <action> の値ってなに?となるんですが、結論から言えば、なんでもいいです。暗黙的 Intent の送信側と Intent Filter が設定されている受信側で値が一致していれば、自動で受け取ってくれます。

action nameの定数

とは言え、流石にそれだと使いにくすぎるので、Intentクラス内に定数としてよく使われる action が定義されています。

Intent のドキュメント内で「Standard Activity Actions」と検索すればその一覧が出てくるので、それっぽいものを選びましょう。

また、設定する文字列は Constant Value と言う形で書いてあります。例えばIntent#ACTION_CALLなら android.intent.action.CALL です。

<category>の設定

<action> とは別に<category>を設定することが出来ます。<action> よりもうちょっと具体性のある、「こう言う機能を持ったアプリに Intent を渡したい」と言う指示を出すことができます。

こちらもname属性に指定してあげれば OK です。

category nameの定数

定数の一覧を見たい場合は Intent のドキュメント内で「Standard Categories」と検索しましょう。Intent#CATEGORY_BROWSABLEあたりを見ておけば何となくイメージもつかみやすいんじゃないでしょうか。

送信側はIntent#addCategory(String category)メソッドで設定することが出来ます。

受信側は指定したい <category> がなくてもDEFAULT_CATEGORY を指定しておかないと暗黙的 Intent を受け取れないので注意しましょう。

また、<category><action> と同様に自分で定義したものを使用することが出来ます。

<data>の設定

<data>を指定すると、Intent と一緒に渡される Uri の値をもとにフィルタリングすることが出来ます。

指定できる属性は以下の通りです。

  • android:scheme
  • android:host
  • android:port
  • android:mimeType
  • android:path
  • android:pathPrefix
  • android:pathPattern

schemehostport に関しては特に説明しなくてもいいでしょう。ただ、scheme が指定されていないのに host を指定しても効果がないとか、そう言うのがあるとのことなのでドキュメントはちゃんと読んでおきましょうね。

mimeType もそのままの意味です。送られてくるデータの型でフィルタリングすることが出来ます。

path はちょっと複雑ですが、path を指定したときは完全一致、pathPrefix を指定したときは前方一致、pathPattern ではワイルドカードを指定できます。

これらの値は基本的にUri クラスから設定 / 取得することになるんですが、MIME-Type だけはIntent クラスから設定 / 取得することになります。*2

Uri と MIME-Type を同時に設定するメソッドも用意されているので、上手く活用しましょう。

まとめ

恐ろしくざっくりとした記事ですが、Intent Filter で厄介なのは「どの Action や Category をセットすればいいのか」と「どう言う Uri を作成すればいいのか」と「Uri からどうやって値を取得したらいいのか」の三つで、その辺を全部すっ飛ばしてるからです。

とは言えこの辺すらわかってないと設計すら出来ないので、とりあえず一旦まとめておきました。

2014/06/09 追記

続きのような記事を書きました。

outofmem.hatenablog.com

参考

*1:電話番号だとUri#getSchemeSpecificPart()あたりかな?

*2:当たり前ですが、URI から MIME-Type は特定できないからです。