サブアプリ

非公式提案草案,

このバージョン:
https://WICG.github.io/sub-apps
課題追跡:
GitHub
仕様内のインライン課題
編集者:
(Google)

概要

サブアプリ API を使用すると、親アプリケーションコンテキストは、親とオリジン、ストレージ、およびライフサイクルの境界を共有しながら、 オペレーティングシステムには異なる名前、アイコン、およびウィンドウ ID を提示する補助 アプリケーションをプログラムによってインストール、一覧表示、および削除できます。

この文書のステータス

この仕様は、Web Platform Incubator Community Group によって公開されました。 これは W3C 標準ではなく、W3C 標準化過程にも含まれていません。 次の W3C コミュニティ貢献者ライセンス契約 (CLA) では、限定的なオプトアウトが認められており、その他の条件も適用されることに注意してください。 W3C コミュニティおよびビジネスグループについて詳しく説明します。

1. はじめに

サブアプリ API を使用すると、親アプリケーションは、次の条件を満たす補助 アプリケーション(サブアプリ)をプログラムによってインストール、一覧表示、および削除できます。

  1. オペレーティングシステムおよびユーザーには、完全に独立したアプリケーションとして表示されます(個別のランチャーアイコン、 独立したタスクバー/シェルフウィンドウ、および個別の OS 統合)。

  2. 基盤となるリソース、オリジン、ストレージ、権限、および更新ライフサイクルを親 アプリケーションと共有します。

この API は、セキュリティとデータ整合性を確保するため、分離コンテキストに制限されています。

2. 概念

インストール済みウェブアプリケーションには、関連付けられた親アプリがあり、その値は null、またはインストール済みウェブアプリケーションです。

インストール済みウェブアプリケーションには、関連付けられたサブアプリ集合があり、これは集合であり、インストール済みウェブアプリケーションを要素として持ちます。

Document には、関連付けられたインストール済みウェブアプリケーションがあり、これは その Document が一部として提示されるインストール済みウェブアプリケーションです。この関連付けの正確な機構は実装定義です。

Document は、関連付けられたインストール済みウェブアプリケーションを持ち、かつ その関連付けられたインストール済みウェブアプリケーション親アプリが null でない場合、サブアプリ文書です。

3. Window インターフェイスの拡張

[Exposed=Window, SecureContext, IsolatedContext]
partial interface Window {
  [SameObject] readonly attribute SubApps subApps;
};

3.1. subApps 属性

Window オブジェクトには、関連付けられた subApps があり、これは SubApps インスタンスであり、 Window とともに作成されます。

subApps 取得子の手順は、次のとおりです。
  1. thissubApps を返します。

4. SubApps インターフェイス

// https://w3c.github.io/manifest/#id-member を表します
typedef USVString ManifestId;

dictionary SubAppsAddResponse {
  record<USVString, ManifestId> installedApps;
  record<USVString, DOMException> failedApps;
};

dictionary SubAppsRemoveResponse {
  sequence<ManifestId> removedApps;
  record<USVString, DOMException> failedApps;
};

dictionary SubAppsListResult {
  required DOMString appName;
};

[
  Exposed=Window,
  SecureContext,
  IsolatedContext
] interface SubApps {
  Promise<SubAppsAddResponse> add(sequence<USVString> install_paths);
  Promise<SubAppsRemoveResponse> remove(sequence<ManifestId> manifest_ids);
  Promise<record<USVString, SubAppsListResult>> list();
};

文字列 path は、次のすべての条件を満たす場合、Document document に対する有効な相対パスです。

  1. path は有効な絶対 URL ではありません。

  2. path"/" で始まります。

  3. path は空ではありません。

  4. path"//" で始まりません。

  5. document文書基底 URLを基底 URL として path構文解析した結果が失敗ではありません。

4.1. add() メソッド

add(install_paths) メソッドの手順は、次のとおりです。

install_paths 引数は、サブアプリの開始 HTML ページを指す相対パスのリストです。

  1. promise新しい プロミスとする。

  2. document を、関連するグローバルオブジェクト関連付けられた Documentとする。

  3. document が、"sub-apps" という名前のポリシー制御対象機能使用することを許可されていない場合、promise を "SecurityError" DOMException拒否し、promise を返す。

  4. documentサブアプリ文書である場合、promise を "NotSupportedError" DOMException拒否し、promise を返す。

  5. parsedUrls を空のリストとする。

  6. install_paths 内の各 installPath に対して、以下を反復する:

    1. installPathdocument に対する有効な相対パスでない場合、promise を "TypeError" DOMException拒否し、promise を返す。

    2. absoluteUrl を、document文書基底 URLを基底 URL として installPath構文解析した結果とする。

    3. absoluteUrl が失敗である場合、promise を "TypeError" DOMException拒否し、 promise を返す。

    4. absoluteUrlparsedUrls に付加する。

  7. parentApp を、document関連付けられたインストール済みウェブ アプリケーションとする。

  8. currentSubAppsCount を、parentAppサブアプリセットサイズとする。

  9. install_pathsサイズが 20 より大きい場合、promise を "QuotaExceededError" DOMException拒否し、promise を返す。

  10. currentSubAppsCount + install_pathsサイズが 50 より大きい場合、promise を "QuotaExceededError" DOMException拒否し、promise を返す。

  11. subAppsthisとする。

  12. 以下の手順を並列に実行する:

    1. userConsent を、install_paths 内のサブアプリをインストールするためのユーザーの同意を要求した結果とする (例えば、統合されたインストールダイアログを提示することによる)。

    2. userConsent が拒否された場合、subApps関連するグローバルオブジェクト上でグローバルタスクをキューに入れpromise を "NotAllowedError" DOMException拒否させ、 これらの手順を中止する。

    3. installedApps を空のマップとする。

    4. failedApps を空のマップとする。

    5. parsedUrls 内の各 absoluteUrl に対して、以下を反復する:

      1. installPath を、absoluteUrlパスとする。

      2. manifest を、absoluteUrl を与えてマニフェストをフェッチして処理する 結果とする。

      3. manifest が失敗である場合、以下の手順を実行する:

        1. failedApps[installPath] を新しい "DataError" DOMException設定する

        2. 継続する

      4. manifestIdmanifestidとする。それが 定義されていない場合、manifeststart_url(参照/ハッシュフラグメントを除く)にフォールバックする。

      5. parentAppmanifestId を持つサブアプリがすでにインストールされている場合、 以下の手順を実行する:

        1. failedApps[installPath] を新しい "InvalidStateError" DOMException設定する

        2. 継続する

      6. parentAppマニフェストscopemanifestscope接頭辞であるか、manifestscopeが、parentAppサブアプリセット内の 現在インストールされているいずれかのサブアプリのscope接頭辞であるか、parentAppサブアプリセット内の 現在インストールされているいずれかのサブアプリのscopemanifestscope接頭辞であるか、または absoluteUrlparentAppマニフェスト自体を指している場合、以下の手順を実行する:

        1. failedApps[installPath] を新しい "ConstraintError" DOMException設定する

        2. 継続する

      7. プラットフォームのアプリケーションランチャーにサブアプリをインストールすることを試みる。

      8. システムまたはデータベースのエラーが原因でインストールに失敗した場合:

        1. failedApps[installPath] を新しい "OperationError" DOMException設定する

        2. 継続する

      9. installedApps[installPath] を manifestId設定する

    6. response を、以下を持つ新しい SubAppsAddResponse 辞書とする:

    7. グローバルタスクをキューに入れsubApps関連するグローバルオブジェクト上で、 promiseresponse解決させる。

  13. promise を返す。

4.2. remove() メソッド

manifest_ids 引数は、削除するサブアプリの id のリストです。

remove(manifest_ids) メソッドの手順は、次のとおりです。

  1. promise新しい プロミスとする。

  2. document を、関連するグローバルオブジェクト関連付けられた Documentとする。

  3. document が、"sub-apps" という名前のポリシー制御対象機能使用することを許可されていない場合、promise を "SecurityError" DOMException拒否し、promise を返す。

  4. documentサブアプリ文書である場合、promise を "NotSupportedError" DOMException拒否し、promise を返す。

  5. parentApp を、document関連付けられたインストール済みウェブ アプリケーションとする。

  6. parsedManifestIds を空のリストとする。

  7. manifest_ids 内の各 manifestId に対して、以下を反復する:

    1. manifestIddocument に対する有効な相対パスでない場合、promise を "TypeError" DOMException拒否し、promise を返す。

    2. parsedUrl を、document文書基底 URLを基底 URL として manifestId構文解析した結果とする。

    3. parsedUrl が失敗である場合、promise を "TypeError" DOMException拒否し、 promise を返す。

    4. parsedUrlparsedManifestIds に付加する。

  8. subAppsthisとする。

  9. 以下の手順を並列に実行する:

    1. removedApps を空のシーケンスとする。

    2. failedApps を空のマップとする。

    3. parsedManifestIds 内の各 parsedUrl に対して、以下を反復する:

      1. manifestId を、parsedUrlパスとする。

      2. parentAppサブアプリセット内に、idmanifestId であるインストール済みウェブアプリケーションが存在しない場合、以下の 手順を実行する:

        1. failedApps[manifestId] を新しい "NotFoundError" DOMException設定する

        2. 継続する

      3. ID manifestId を持つサブアプリを、システムのランチャーおよびレジストリから アンインストールすることを試みる。

      4. システムエラーが原因でアンインストールに失敗した場合、以下の手順を実行する:

        1. failedApps[manifestId] を新しい "OperationError" DOMException設定する

        2. 継続する

      5. manifestIdremovedApps に付加する。

    4. response を、以下を持つ新しい SubAppsRemoveResponse 辞書とする:

    5. グローバルタスクをキューに入れsubApps関連するグローバルオブジェクト上で、 promiseresponse解決させる。

  10. promise を返す。

4.3. list() メソッド

list() メソッドの手順は、次のとおりです。

  1. promise新しい プロミスとする。

  2. document を、関連するグローバルオブジェクト関連付けられた Documentとする。

  3. document が、"sub-apps" という名前のポリシー制御対象機能使用することを許可されていない場合、promise を "SecurityError" DOMException拒否し、 promise を返す。

  4. documentサブアプリ文書である場合、promise を "NotSupportedError" DOMException拒否し、 promise を返す。

  5. parentApp を、document関連付けられたインストール済みウェブ アプリケーションとする。

  6. subAppsthisとする。

  7. 以下の手順を並列に実行する:

    1. listResult を空のマップとする。

    2. parentApp に対して現在インストールされているすべてのサブアプリのリストを、 プラットフォームのレジストリから取得する。

    3. プラットフォームエラーが原因でリストの取得に失敗した場合、subApps関連するグローバルオブジェクト上でグローバルタスクをキューに入れpromise を "OperationError" DOMException拒否させ、 これらの手順を中止する。

    4. インストール済みの各サブアプリ subApp に対して、以下を反復する:

      1. manifestId を、subAppidとする。

      2. appName を、サブアプリのウェブマニフェストから抽出された名前 とする。

      3. resultEntry を、appNameappName に設定された新しい SubAppsListResult 辞書とする。

      4. listResult[manifestId] を resultEntry設定する

    5. グローバルタスクをキューに入れsubApps関連するグローバルオブジェクト上で、 promiselistResult解決させる。

  8. promise を返す。

4.4. マニフェストをフェッチして処理する

「マニフェストをフェッチして 処理する」アルゴリズムを記述する。 [課題 #2]

urlURL)を与えてマニフェストをフェッチして 処理するには、次の 手順を実行します。

  1. 失敗を返します。

5. セキュリティおよびプライバシーに関する考慮事項

補助アプリケーションのインストールと管理は強力な機能です。ユーザーエージェントは、明示的な許可なしに、ウェブアプリケーションが サブアプリをインストールまたは管理することを許可してはなりません。

この節では、考慮される脅威と、それらを軽減するためのユーザーエージェントに対する規範的要件を概説します。

5.1. 共有オリジンのアイデンティティ

サブアプリは、個別のセキュリティオリジンを持ちません。親アプリと完全に同じオリジンおよびローカルデータストア(Cookie、IndexedDB、LocalStorage、 Cache Storage など)を共有します。標準的なウェブセキュリティ境界(同一オリジンポリシーなど)は、 親アプリとそのすべてのサブアプリを単一のエンティティとして扱います。

5.2. 権限の継承

すべての権限は、親アプリとそのサブアプリの間で共有されます。サブアプリに権限(たとえば、カメラ、ファイル システムアクセス、USB)を付与すると、その権限は親にも自動的に付与され、その逆も同様です。

サブアプリ API にアクセスするには、親アプリの文書が権限ポリシー sub-apps を明示的に宣言する必要があります。サブアプリに対して宣言された権限ポリシーは効果を持ちません。

特定のオリジンについて、ユーザーの同意を得なければなりません。add() が呼び出された場合、ユーザーエージェントは、要求されたすべての サブアプリを表示する統合インストールダイアログをユーザーに提示しなければなりません。複数のサブアプリを一度に追加する場合、ダイアログの乱発を避けるため、 それらを単一のプロンプト内に提示するべきです。

ユーザーエージェントは、どのオリジンがアクセスを要求しているかを明確に示し、 ユーザーが十分な情報に基づいて判断できるだけの情報(たとえば、インストールされるサブアプリの名前 およびアイコン)を提供する権限プロンプトを表示しなければなりません。

5.4. アイデンティティ偽装のリスク

開発者はサブアプリの名前とアイコンをカスタマイズできるため、悪意のあるアプリケーションが システムダイアログや信頼されたサードパーティアプリケーションを模倣するサブアプリを作成するリスクがあります。 このリスクを軽減するため、サブアプリ API は、整合性および署名検証を保証する分離コンテキストに制限されています。

5.5. OS 統合拡張のリスク

サブアプリは、独自の OS 統合(プロトコルハンドラーやファイルタイプの 関連付けなど)を登録できます。これは、アプリケーションが親アプリの主要マニフェストで 宣言された範囲をはるかに超えて、OS 内での影響範囲を拡張する可能性があることを意味します。 この問題は、ほとんどのオペレーティングシステム統合が有効になる前に、明示的なユーザー承認(たとえば、 あるファイルタイプの既定のアプリケーションとしてサブアプリを選択すること)を必要とするという事実によって軽減されます。

5.6. クォータおよび制限

ホストオペレーティングシステムおよびユーザーのアプリケーションランチャーを、潜在的なリソース枯渇や悪用から保護するため、 プラットフォームは次の 2 つの制限を適用する:
  1. 親アプリケーションごとにインストール済みサブアプリを 50 個とする厳格な上限。

  2. 1 回の権限プロンプトでインストールできるサブアプリを 20 個とする制限。

一括インストール呼び出しがプラットフォームの制限を超える場合、add() 呼び出し全体が "QuotaExceededError" DOMException で拒否される。

6. 統合

6.1. 権限ポリシー

この仕様は、Window オブジェクト上の subApps 属性によって公開されるメソッドを使用できるかどうかを制御する機能を定義します。

この機能の機能名は、"sub-apps" です。

この機能の既定の許可リスト'none' です。ユーザーエージェントは、特定のオリジンについて これを 'self' に上書きしても構いません(たとえば、ユーザーの判断に基づく場合)。

適合性

文書の 表記規則

適合性要件は、説明的な表明 と RFC 2119 の用語を組み合わせて 表現されます。 この文書の規範的な部分におけるキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、 「MAY」、および「OPTIONAL」 は、RFC 2119 に記載されているとおりに 解釈されるものとします。 ただし、読みやすさのため、 この仕様では、これらの語がすべて大文字で表記されるとは限りません。

明示的に非規範的と記されている節、例、および注記を除き、 この仕様のすべてのテキストは規範的です。 [RFC2119]

この仕様の例は、「たとえば」という語で導入されるか、 class="example" によって 規範的テキストから区別されます。 次に例を示します。

これは参考例の例です。

参考注記は「注記」という語で始まり、 class="note" によって 規範的テキストから区別されます。 次に例を示します。

注記: これは参考注記です。

テスト

この仕様の内容に関連するテストは、 この例のような「テスト」ブロックに記載される場合があります。 このようなブロックはいずれも非規範的です。


索引

この仕様で定義される 用語

参照によって定義される 用語

参考文献

規範的参考文献

[APPMANIFEST]
Marcos Caceres; Daniel Murphy; Christian Liebel. ウェブ アプリケーションマニフェスト. URL: https://w3c.github.io/manifest/
[DOM]
Anne van Kesteren. DOM 標準. 現行標準. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 標準. 現行標準. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 標準. 現行標準. URL: https://infra.spec.whatwg.org/
[ISOLATED-CONTEXTS]
分離 コンテキスト. コミュニティグループ報告書草案. URL: https://wicg.github.io/isolated-web-apps/isolated-contexts.html
[PERMISSIONS]
Marcos Caceres; Mike Taylor. 権限. URL: https://w3c.github.io/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland. 権限 ポリシー. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. RFC で 要件レベルを示すために使用するキーワード. 1997年3月. 現行の最良慣行. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL 標準. 現行標準. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 標準. 現行 標準. URL: https://webidl.spec.whatwg.org/

IDL 索引

[Exposed=Window, SecureContext, IsolatedContext]
partial interface Window {
  [SameObject] readonly attribute SubApps subApps;
};

// https://w3c.github.io/manifest/#id-member を表します
typedef USVString ManifestId;

dictionary SubAppsAddResponse {
  record<USVString, ManifestId> installedApps;
  record<USVString, DOMException> failedApps;
};

dictionary SubAppsRemoveResponse {
  sequence<ManifestId> removedApps;
  record<USVString, DOMException> failedApps;
};

dictionary SubAppsListResult {
  required DOMString appName;
};

[
  Exposed=Window,
  SecureContext,
  IsolatedContext
] interface SubApps {
  Promise<SubAppsAddResponse> add(sequence<USVString> install_paths);
  Promise<SubAppsRemoveResponse> remove(sequence<ManifestId> manifest_ids);
  Promise<record<USVString, SubAppsListResult>> list();
};

課題索引

「マニフェストをフェッチして処理する」アルゴリズムを記述する。 [課題 #2]