Androidの開発をしながら使用して、Uri、Scheme、SSP(Scheme Specific PART)についてまとめました。 Intentはdataという情報を持っています。 dataはUriで表現され、Uriのコンポーネントの中scheme、SSPがあります。 schemeとhostなどは難しく感じられませんが、SSP(Scheme Specific Part)は見慣れ感じられることがあります。
まず、Intentについて簡単に説明し、UriとScheme、SSPを紹介します。
Intentの簡単な説明
Androidからイベントを送受信するときIntentを使用します。 Intentには、Dataというアイテムがありますが。 Intentは、任意のデータを持っているかどうかを表現し、Broadcastなどを転送するときにどのようなレシーバに転送する必要がありかどうかを表していると考えることができます。 Activityを実行するときにもDataの内容に応じていくつかのActivityを実行するかどうか決定します。
Intentは、次のように生成し、Dataを設定することができます。
val intent = Intent(Intent.ACTION_VIEW)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.addCategory(Intent.CATEGORY_BROWSABLE)
val uri: Uri = Uri.parse("http://google.com")
intent.data = uri
上記のコードでIntentのdataを設定するときUriを入力します。つまり、データはUriでUriがどのようなデータであることを表現します。
Uriが持っているデータについて
UriはUniform Resource Identifierという意味で、リソースを表す識別子です。インターネット上で使用されるUrlはUri下位概念です。
Uriは、次のような構造で構成されています。
<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]
上記の http://google.com
を例に聞きました。ここで、 http
はscheme、google.com
はhostがされます。
port、およびpathなどはありません。
次のように Uri.parse()
を利用して、文字列をUriオブジェクトにすることができます。
次のコードのようにUriオブジェクトのscheme、hostなどを出力してみるとよく設定されたことを見ることができます。
val uri: Uri = Uri.parse("http://google.com")
Log.d(TAG, "scheme: ${uri.scheme}, host: ${uri.host}, " +
"port: ${uri.port}, path: ${uri.path}")
Output:
MainActivity: scheme: http, host: google.com, port: -1, path:
Uriを使用する理由
Uriは、リソースを表す識別子です。
たとえば、ユーザーが http://google.com
というリンクをクリックしたときのアプリは、これをインテントにしstartActivity()
を呼び出します。
そしてシステムは、Intentのデータを処理することができるアプリを探します。このときUriのscheme、hostなどで関連しているアプリを検索します。
次のコードを実行させると、システムは、このIntentと関連しているアプリを探して実行します。このようなインテントは、Browserが処理することができますので、コードを実行すると、Browserが実行されます。
val intent = Intent(Intent.ACTION_VIEW)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.addCategory(Intent.CATEGORY_BROWSABLE)
val uri: Uri = Uri.parse("http://google.com")
intent.data = uri
startActivity(intent)
アプリがどのような種類のインテントを処理することができるかどうかを表現する方法の一つは、AndroidManifestのIntentFilterです。 システムは、AndroidManifest.xmlを読んで、アプリがどのようなインテントを処理することができるかどうか分類し、インテントを送信するときに、このような情報を参照して、誰に送るかを決定します。
ChromeアプリのManifestを見ると、以下のようにActivityのIntentFilterを設定しました。
もう少し詳しく見ると、上記のIntentが持っているaction、categoryが同一であることを見ることができます。
また、dataの項目にschemeが http
で定義されています。このdataはUriを意味し、schemeが、http、httpsのUriはすべて処理することができるということを意味します。つまり、hostがどのようなものか輝重要ではない。
<activity android:name="com.google.android.apps.chrome.IntentDispatcher">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
</intent-filter>
</activity>
このようにAppはManifestに処理することができるUriを宣言するためのシステムは、Uri情報を比較して、誰にIntentを送信するかを決定することができます。
もしいくつかのActivityはhostが google.com
あるだけ処理することができる場合は、次のようにIntentFilterを設定することができます。 data項目を見ればhostが設定された。
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" android:host="google.com"/>
<data android:scheme="https" android:host="google.com"/>
</intent-filter>
SSP(Scheme Specific Part)
上記のUriは以下のような形式としました。
<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]
しかし、下記のような形式でも使用します。
<scheme>:<scheme-specific-part>#fragment
最初のパターンと比較した場合、 //
はありません。 :
の右側の部分を(SSP Scheme Specific Part)と呼ばれます。そして #
の右側には、fragmentと呼ばれます。
AndroidからSSP形式のUriを使用する場合もあります。
たとえば、Appがインストールが完了すると、 ACTION_PACKAGE_ADDED
インテントが配信されます。
Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.codechacha.myapplication flg=0x4000010 (has extras) }
このインテントのUriは package:com.codechacha.myapplication
です。 schemeは package
でSSPは、com.codechacha.myapplication
です。 fragmentはありません。
他の例として、電話をかけるときに送出されるIntentのUriは tel:010-1111-1111
のような形式です。 tel
というschemeがあり、そのschemeの詳細情報をSSPに保存しています。
sms
やmms
や同じようにSSPで表現しています。
IntentFilterにSSP定義
アプリがデバイスから削除される PACKAGE_FULLY_REMOVED
というインテントをブロードキャストで送信します。このインテントは、SSPを使用してUriを表現し package:com.example.myapplication
ようSSPにアプリのパッケージ名を入れて渡します。
もし PACKAGE_FULLY_REMOVED
をレシーバで受けたい場合は、次のようにschemeをpackage
に設定する必要があります。
このように設定すると、いくつかのアプリが削除されるとき、そのイベントを受け取ります。
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
しかし、もし com.example.myapplication
というアプリが削除された場合にのみ、インテントを受けたい場合はどうでしょうか
IntentFilterにsspに com.example.myapplication
に設定します。このように設定すると、インテントのsspとインテントフィルタのsspと一致する場合にのみ伝達がされます。
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<data android:scheme="package" android:ssp="com.example.myapplication"/>
</intent-filter>
</receiver>
Manifestではなく、 Context.registerReceiver()
でレシーバを登録する場合は、次のようにIntentFilterオブジェクトを生成することができます。 SSPを設定するとき addDataSchemeSpecificPart()
を使用します。
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
intentFilter.addDataScheme("package")
intentFilter.addDataSchemeSpecificPart("com.example.myapplication",
PatternMatcher.PATTERN_LITERAL)
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("MyReceiver", "onReceive: $intent")
}
}
context.registerReceiver(receiver, intentFilter)
SSPでUriが定義されたIntentを提供
上記の例は、SSPに設定されたIntentを受けるためにIntentFilterを登録する方法です。 逆に私のアプリでIntentを送信することもできます。
UriにSSPを設定したい場合は、次のように Uri.fromParts(scheme, ssp, fragment)
でsspが設定されたUriオブジェクトを作成することができます。
val intent = Intent("com.custom.intent.action")
intent.data = Uri.fromParts("package" /* scheme */,
"com.example.myapplication" /* ssp */,
null /* fragment */)
このようにインテントを送信する次のようにインテントフィルタを設定したアプリに転送することができます。
<intent-filter>
<action android:name="com.custom.intent.action" />
<data android:scheme="package" android:ssp="com.example.myapplication"/>
</intent-filter>
もちろんschemeだけ設定したアプリでも配信がされます。
<intent-filter>
<action android:name="com.custom.intent.action" />
<data android:scheme="package"/>
</intent-filter>
Fragmentが使用されている例
Android開発をしながらfragmentが使用されているのはないみました。もしかしたらご覧になった方があれば教えてください。
まとめ
IntentのDataを表現する方法は、UriとMimetypeがあります。
Mimetypeはここで紹介していなかったが、データのタイプを表現します。 Uriは <scheme>://<host>
形式で使用される時もあり<scheme>:<scheme-specific-part>
形式で使用されることがあります。
それぞれIntentFilterとIntentオブジェクトを作成する方法が少しずつ異なります。
この記事を読んながらIntentを少しでも理解するのに役立ちたら、と思います。
Intentの基本的な内容についてもっと知りたい場合は、以下の文も読んでみてことをお勧めします。
Related Posts
- Android - 振動、Vibrator、VibrationEffectの例
- Android - TabLayoutの実装方法(+ ViewPager2)
- Android - PackageManagerにPackage情報を取得する
- Android - ACTION_BOOT_COMPLETEDイベント受信
- Android - FusedLocationProviderClientに位置情報を取得する
- Android - GPS、Network位置情報を取得する(LocationManager)
- Android - Foreground Service実行
- Android - 時間、日付、変更イベント受信
- Android - currentTimeMillis()、elapsedRealtime()、uptimeMillis()
- Android-PowerManager WakeLock
- Android - ファイル入出力の例(Read、Write、内部、外部ストレージ)
- Android - Screen On / Offイベントの受信、状態確認
- Android - 他のアプリのServiceにバインド
- Android - Handler vs Executor
- Android - Darkmode有効にする方法
- Android - hasSystemFeature()、サポートされているFeature確認
- Android - アプリの権限を確認(Permission check)
- Android - インストールされてアプリリストをインポートする
- Android App Shortcuts実装
- Android - ContentProviderを実装、および例
- Android - AIDLを利用して、Remote Serviceの実装
- Android - Uri、Scheme、SSP(Scheme Specific Part)説明
- Android - アプリのインストール、削除、イベントダウンロード(BroadcastReceiverインテントを受け取る)
- Android - SharedPreferencesに簡単なデータを保存する方法
- Android - AlarmManagerにアラームを登録する方法、および例
- Android - Quick SettingsにCustom Tile追加する方法(kotlin)
- Android - Broadcast Receiver登録およびイベントの受信方法
- Android - Runtime permissionリクエスト方法と例(kotlin)
- Android - ネットワーク(WIFI)の接続状態を確認し、変更の検出
- Mockito - static、final methodをmockingする方法
- Andriod - カスタムパーミッションを定義する方法
- RobolectricにUnit Testを作成する(kotlin)
- Android Mockitoのテストコードを作成する(kotlin)
- Android - Handlerの使用方法、および例
- Android - IntentService使用方法
- Android - JobIntentService使用方法