1. はじめに
連絡先ピッカーは、さまざまなデスクトップおよびネイティブモバイルアプリケーションで多くのユースケースに利用されています。本仕様は、連絡先ピッカーをウェブにもたらすAPIを定義し、ウェブアプリの新たなユースケースを可能にします。例えば:
-
ソーシャルネットワークのためにユーザーのソーシャルグラフをブートストラップする。
-
メールアプリケーション内でメッセージの宛先を選択する。
連絡先ピッカーモデルは、ユーザーが共有するデータを完全に管理できるようにするために選ばれました。ユーザーは、ウェブサイトに提供する連絡先を正確に選択できます。連絡先ピッカーモデルでは、ウェブサイトはユーザーの連絡先への一度限りのアクセス権しか得られず、開発者は必要な都度アクセスを要求しなければなりません。これは一部のネイティブ連絡先APIとは異なりますが、ユーザーの連絡先が本人の認知と明示的な同意なしにアクセスされないようにするために必要です。
1.1. 例
selectRecipientsButton. addEventListener( 'click' , async () => { const contacts= await navigator. contacts. select([ 'name' , 'email' ], { multiple: true }); if ( ! contacts. length) { // ピッカーで連絡先が選択されませんでした。 return ; } // |contacts| の名前とメールアドレスをウェブサイトUIの宛先フィールドに反映する。 populateRecipients( contacts); });
上記の例で selectRecipientsButton
は HTMLButtonElement
、
populateRecipients
は開発者定義の関数です。
selectRecipientButton. addEventListener( 'click' , async () => { // 住所がサポートされているか、ブラウザーが提供できるかは不明です。 if (( await navigator. contacts. getProperties()). includes( 'address' )) { const contacts= await navigator. contacts. select([ 'address' ]); if ( ! contacts. length) { // ピッカーで連絡先が選択されませんでした。 return ; } // 複数連絡先を要求していないので length は 1。 sendGiftToAddress( contacts[ 0 ]. address); } // フォームへのフォールバック。 });
上記の例で selectRecipientButton
は HTMLButtonElement
、
sendGiftToAddress
は開発者定義の関数です。
selectRecipientButton. addEventListener( 'click' , async () => { // アイコンがサポートされているか、ブラウザーが提供できるかは不明です。 if (( await navigator. contacts. getProperties()). includes( 'icon' )) { const contacts= await navigator. contacts. select([ 'name' , 'icon' ]); if ( ! contacts. length) { // ピッカーで連絡先が選択されませんでした。 return ; } if ( ! contacts[ 0 ]. name. length|| ! contacts[ 0 ]. icon. length) { // 情報が見つかりません。フォールバックを使用してください。 return ; } // 必要なのは1つの名前と1つの画像だけです。 const name= contacts[ 0 ]. name[ 0 ]; const imgBlob= contacts[ 0 ]. icon[ 0 ]; // 画像を表示する。 const url= URL. createObjectURL( imgBlob); imgContainer. onload= () => URL. revokeObjectURL( url); imgContainer. src= url; // 代わりにBitmapを使用することもできます。 const imgBitmap= await createImageBitmap( imgBlob); // アイコンをアップロードする。 const response= await fetch( '/contacticon' , { method: 'POST' , body: imgBlob}); } });
上記の例で selectRecipientButton
は HTMLButtonElement
、
imgContainer
は HTMLImageElement
です。
2. プライバシーに関する考慮事項
連絡先情報を公開することは、関係のない第三者の個人情報(PII)を露出させるという明確なプライバシーへの影響があります。ピッカーモデルを採用することで、ユーザーエージェントがウェブサイトといつどの情報が共有されるかをユーザーに明確に伝えるユーザー体験を提供できるようにしています。
さらに、以下の制約も適用されます:
-
APIの開始にはユーザーの操作が必要です。これにより、ユーザーの連絡先へのプログラムによるリクエストは許可されません。
-
APIは最上位トラバーサブルでのみ利用可能であり、かつセキュアコンテキストである必要があります。これらの制約により、提供された連絡先情報が意図した受信者に確実に届くようにします。
-
APIの開始には一時的なアクティベーションが必要です。これにより、ユーザーの連絡先へのプログラムによるリクエストは許可されません。
3. セキュリティに関する考慮事項
-
APIは最上位トラバーサブルでのみ利用可能であり、かつセキュアコンテキストである必要があります。これらの制約により、提供された連絡先情報が意図した受信者に確実に届くようにします。
4. レルム
すべてのプラットフォームオブジェクトは、特に記載がない限り、thisの関連レルムで作成されます。
5. インフラストラクチャ
連絡先ピッカー・タスクソースは、タスクソースです。
5.1. 住所
住所(physical address)は以下から構成されます:
-
国(country):
DOMString
型で、住所の国を[ISO3166-1]アルファ2コード(大文字形式、または空文字列)で表します。例:"JP"。 -
住所行(address line):リスト型の
DOMString
で、 住所の最も詳細な部分を含みます。例:通り名、番地、部屋番号、農村配達ルート、説明的な指示、私書箱番号など。 -
地域(region):
DOMString
型で、国の最上位行政区分を表します。例:州、県、オブラスト、都道府県など。 -
市区町村(city):
DOMString
型で、住所の市区町村部分を表します。 -
従属地域(dependent locality):
DOMString
型で、都市内の従属地域や副地域を表します。例:地区、区、ネイバーフッド、イギリスのdependent localityなど。 -
郵便番号(postal code):
DOMString
型で、郵便番号やZIPコード(インドではPINコード)を表します。 -
仕分けコード(sorting code):
DOMString
型で、フランスのCEDEXシステムなど仕分けコードシステムを表します。 -
組織(organization):
DOMString
型で、住所の組織・企業・会社・機関名を表します。 -
受取人(recipient):
DOMString
型で、住所の受取人または連絡先担当者名を表します。 -
電話番号(phone number):
DOMString
型で、住所の受取人や連絡先の電話番号を表します。[E.164]に準拠する構造も可。
5.2. ユーザー連絡先
ユーザー連絡先(user contact)は以下から構成されます:
ユーザー連絡先は、単一ユーザーに関するデータを含みます。
注: リストのサイズは異なる場合があり、同じインデックスの要素同士が対応する必要はありません。
5.3. 連絡先ソース
連絡先ソース(contacts source)は、ユーザーの連絡先情報をユーザーエージェントに提供するサービスです。
連絡先ソースは以下から構成されます:
-
サポートされるプロパティ(supported properties):リスト型の利用可能な
ContactProperty
値。
注: どの連絡先ソースを選択するかはユーザーエージェントの裁量です。
6. APIの説明
6.1. Navigator
への拡張
[Exposed =Window ]partial interface Navigator { [SecureContext ,SameObject ]readonly attribute ContactsManager contacts ; };
Navigator
には contacts manager(ContactsManager
)があり、初期値は新しい
ContactsManager
です。
contacts
属性のgetterは、thisのcontacts
managerを返します。
ナビゲート可能オブジェクトには、contact picker is showing flag(連絡先ピッカー表示フラグ)があり、初期状態は未設定です。
6.2. ContactProperty
enum {
ContactProperty ,
"address" ,
"email" ,
"icon" ,
"name" };
"tel"
ContactProperty
は、関連するuser
contactフィールドにユーザーエージェントがアクセスできる場合、利用可能とみなされます。
- "address"
-
user contactのaddressesに関連します。
- "email"
-
user contactのemailsに関連します。
- "icon"
-
user contactのiconsに関連します。
- "name"
-
user contactのnamesに関連します。
- "tel"
-
user contactのnumbersに関連します。
6.3. ContactAddress
[Exposed =Window ]interface { [
ContactAddress Default ]object ();
toJSON readonly attribute DOMString city ;readonly attribute DOMString country ;readonly attribute DOMString dependentLocality ;readonly attribute DOMString organization ;readonly attribute DOMString phone ;readonly attribute DOMString postalCode ;readonly attribute DOMString recipient ;readonly attribute DOMString region ;readonly attribute DOMString sortingCode ;readonly attribute FrozenArray <DOMString >addressLine ; };
ContactAddress
インターフェースは住所(physical
address)を表します。
ContactAddress
インスタンスは以下を持ちます:
-
address(住所)
city
属性のgetterは、thisのaddressのcityを返します。
country
属性のgetterは、thisのaddressのcountryを返します。
dependentLocality
属性のgetterは、thisのaddressのdependent localityを返します。
organization
属性のgetterは、thisのaddressのorganizationを返します。
phone
属性のgetterは、thisのaddressのphone numberを返します。
postalCode
属性のgetterは、thisのaddressのpostal codeを返します。
recipient
属性のgetterは、thisのaddressのrecipientを返します。
region
属性のgetterは、thisのaddressのregionを返します。
sortingCode
属性のgetterは、thisの
addressの
sorting codeを返します。
addressLine
属性のgetterは、thisの
addressの
address lineを返します。
6.4. ContactsManager
dictionary {
ContactInfo sequence <ContactAddress >;
address sequence <DOMString >;
sequence <Blob >;
icon sequence <DOMString >;
name sequence <DOMString >; };
tel dictionary {
ContactsSelectOptions boolean =
multiple false ; }; [Exposed =Window ,SecureContext ]interface {
ContactsManager Promise <sequence <ContactProperty >>getProperties ();Promise <sequence <ContactInfo >>select (sequence <ContactProperty >,
properties optional ContactsSelectOptions = {}); };
options
6.4.1. getProperties()
getProperties()
メソッドが呼び出された時、以下の手順を実行します:
-
promiseに新しいPromiseを設定する。
-
以下の手順を並列で実行:
-
promiseをcontacts sourceのsupported propertiesで解決する。
-
-
promiseを返す。
6.4.2.
select()
select(properties, options)
メソッドが呼び出された際、以下の手順を実行します:
-
globalを、thisの関連グローバルオブジェクトとします。
-
navigableをglobalのnavigableとします。
-
もしnavigableが最上位トラバーサブルでなければ、Promiseを
InvalidStateError
DOMException
で拒否して返します。 -
もしglobalに一時的アクティベーションがなければ、Promiseを
SecurityError
DOMException
で拒否して返します。 -
それ以外の場合は、ユーザーアクティベーションを消費します(globalの)。
-
もしnavigableのcontact picker is showing flagが設定されていたら、 Promiseを
InvalidStateError
DOMException
で拒否して返します。 -
各 propertyについてpropertiesを:
-
もし連絡先ソースのサポートされるプロパティが propertyを含んでいなければ、 Promiseを
TypeError
で拒否して返します。
-
-
navigableのcontact picker is showing flagを設定します。
-
promiseを新しいPromiseとします。
-
以下の手順を並列で実行:
-
selectedContactsを、contact pickerの起動の結果として、 optionsの
multiple
メンバーとpropertiesで取得します。失敗した場合:-
連絡先ピッカー・タスクをキューして以下の手順を実行:
-
navigableのcontact picker is showing flagを解除します。
-
これらの手順を中止します。
-
-
navigableのcontact picker is showing flagを解除します。
-
連絡先ピッカー・タスクをキューして以下の手順を実行:
-
contactsを空のリストとします。
-
各 selectedContactについてselectedContactsを:
-
contactを新しい
ContactInfo
として次のように設定:address
-
selectedContactのaddresses(propertiesが "
address
"を含む場合のみ)、それ以外はundefined。 email
-
selectedContactのemails(propertiesが "
email
"を含む場合のみ)、それ以外はundefined。 icon
-
selectedContactのicons(propertiesが "
icon
"を含む場合のみ)、それ以外はundefined。 name
-
selectedContactのnames(propertiesが "
name
"を含む場合のみ)、それ以外はundefined。 tel
-
selectedContactのnumbers(propertiesが "
tel
"を含む場合のみ)、それ以外はundefined。
-
contactを contactsに追加します。
-
-
promiseをcontactsで解決します。
-
-
-
promiseを返します。
7. 連絡先ピッカー
DOMString
)を受け取り、
ユーザーエージェントは以下のルールに従ったユーザーインターフェースを表示しなければなりません:
-
ユーザーインターフェースの表示に失敗した場合、または連絡先ソースの利用可能な連絡先へのアクセスが失敗した場合、失敗を返す。
-
UIは最上位トラバーサブルのオリジンを目立つ形で表示しなければならない。
-
UIは連絡先のどの
properties
が要求されているかを明確に示さなければならない。注: この情報はpropertiesから導出されます。
-
UIはユーザーが特定の連絡先情報の共有を拒否できる方法を提供するべきである。
注: ユーザーが共有を拒否した場合は、 選択された連絡先を返す前に該当するユーザー連絡先フィールドを修正するべきです。 共有されなかった情報なのか、もともと存在しなかった情報なのかは、返されるユーザー連絡先から区別できないようにする必要があります。
-
UIはどの情報が共有されるかを明確に示さなければならない。
-
UIは個別の連絡先を選択できる方法を提供しなければならない。allowMultipleがfalseの場合、選択できる連絡先は1つのみとする。
-
UIは連絡先を一切共有せずにキャンセル・戻るためのオプションを提供しなければならず、その場合はUIを削除し、空のリストを返す。
-
UIはユーザーが選択を完了したことを示す方法を提供しなければならず、その場合はUIを削除し、選択された連絡先のリストをユーザー連絡先として返す。
8. ユーザー入力からContactAddress
を作成する
ユーザー入力から
ContactAddress
を作成する手順は以下のアルゴリズムによって示されます。
このアルゴリズムはオプションでリスト型のredactListを受け取ります。
redactListが渡されなかった場合、既定では空のリストとなります。
注: redactListはオプションとして、
ユーザーエージェントがAPIで要求元アプリケーションに共有する受取人情報の量を制限するために利用できます。
生成されるContactAddress
オブジェクトは、通信やサービス提供など必要な処理を行うのに十分な情報を提供しますが、
多くの場合、受取人を物理的に特定・一意に識別するには十分ではありません。
ただし、redactListがあっても、
郵便番号が特定の国では個人を一意に特定できるほど細分化されている場合があるため、
受取人の匿名性を保証することはできません。
-
detailsをマップ« "addressLine" → 空のリスト, "country" → "", "phone" → "", "city" → "", "dependentLocality" → "", "organization" → "", "postalCode" → "", "recipient" → "", "region" → "", "sortingCode" → "" »とする。
-
もしredactListが"addressLine"を含まなければ、 details["addressLine"]にユーザーが入力した住所行を分割してリストとしたものを設定する。
注: 住所行の分割方法はロケール依存であり、本仕様の範囲外です。
-
もしredactListが"country"を含まなければ、 details["country"]にユーザーが入力した国を大文字の[ISO3166-1] アルファ2コードとして設定する。
-
もしredactListが"phone"を含まなければ、 details["phone"]にユーザーが入力した電話番号を設定する。
注: ユーザーのプライバシー保護のため、 連絡先住所に紐付く電話番号がエンドユーザー自身のものと同じ場合と異なる場合があるため、 実装者はエンドユーザーの同意なく電話番号を提供しないよう十分注意する必要があります。
-
もしredactListが"city"を含まなければ、 details["city"]にユーザーが入力した市区町村を設定する。
-
もしredactListが"dependentLocality"を含まなければ、 details["dependentLocality"]にユーザーが入力した従属地域を設定する。
-
もしredactListが"organization"を含まなければ、 details["organization"]にユーザーが入力した受取人の組織を設定する。
-
もしredactListが"postalCode"を含まなければ、 details["postalCode"]にユーザーが入力した郵便番号を設定する。 必要に応じてdetails["postalCode"]の一部を秘匿する。
注: 郵便番号が一部の国では個人を一意に特定できるほど細分化されているため、 プライバシー保護の観点から、アプリケーションの用途に十分な部分のみを返す場合があります。 国・地域ごとに事情が異なるため、郵便番号の全部または一部の秘匿は、ユーザー保護の観点から実装者の判断に委ねられます。
-
もしredactListが"recipient"を含まなければ、 details["recipient"]にユーザーが入力した受取人情報を設定する。
-
もしredactListが"region"を含まなければ、 details["region"]にユーザーが入力した地域を設定する。
注: ベルギー等一部の国では、 地域を住所に含めることが一般的でない場合があります(国の全地域が [ISO3166-2]に含まれていても)。 そのため、ユーザーエージェントが特定の国向け住所入力と認識している場合は 地域入力欄を提供しないことがあります。 こういった場合は
ContactAddress
のregion
属性が空文字となりますが、 通信やサービス提供など本来の目的には問題なく利用できます。 -
もしredactListが"sortingCode"を含まなければ、 details["sortingCode"]にユーザーが入力した仕分けコードを設定する。
-
detailsの内容に一致する属性値を持つ新しい
ContactAddress
を返す。
9. 謝辞
Web向けContacts APIの標準化にはこれまでにも複数の試みがあり、本APIはその豊富な歴史から学ぶことを目指しています。過去の試みにはMozillaのContacts API、Contacts API W3C会員提出、そしてW3C作業グループによる標準化の取組み:Contacts API、Pick Contacts Intent、Contacts Manager APIがあります。 Contact Picker APIは、設計時にプライバシー保護を主眼としており、そのアプローチが従来と異なります。従来のAPIは一度許可すると継続的アクセスが可能だったり、プライバシーモデルが曖昧だったりしましたが、本仕様ではUI制約を強制し、ユーザーが共有データを完全に管理でき、濫用を防ぐように設計されています。例えば、ピッカーモデルを採用し、ユーザーが共有する連絡先情報の仲介者として必ず介在し、毎回完全な管理下で情報が提供されます。より詳細な歴史的背景については、従来の試みの文書ステータスのセクションもご参照ください。