Android - Uri、Scheme、SSP(Scheme Specific Part)説明

By JS | Last updated: July 03, 2020

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に保存しています。 smsmmsや同じように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

codechachaCopyright ©2019 codechacha