Web Application Manifest 확장 및 인큐베이션을 위한 기능 명세로, Chromium은 이미 출시했지만 다른 사용자 에이전트의 약속 / 구현은 없는 기능을 다룬다. 이러한 기능을 explainer로 유지하는 대신, 여기에서 더 공식적으로 문서화한다.
이는 비공식 제안이다.
display_override 멤버
고급 사용의 경우, [=manifest/display_override=] 멤버를 사용하여 개발자가 웹 애플리케이션에 대해 선호하는 표시 모드를 선택할 수 있도록 표시 모드 목록 값의 사용자 정의 대체 순서를 지정할 수 있다.
[=application manifest=]의 [=manifest/display_override=] 멤버는 [=display override entries=]의 [=list=]이다. display override entry는 표시 모드 목록 값 ([=display mode/window-controls-overlay=], [=display mode/tabbed=], 그리고 [=display mode/unframed=] 같은 [=display mode extensions|extensions=]를 포함) 또는 [=DisplayOverrideEntryObject=] 중 하나이다.
이 멤버는 [=display modes=]에 대한 개발자의 선호 대체 체인을 나타낸다. 이 필드는 [=manifest/display=] 멤버를 재정의한다. 사용자 에이전트가 여기에 지정된 [=display modes=] 중 어느 것도 지원하지 않으면, [=manifest/display=] 멤버를 고려하는 것으로 대체한다. 알고리즘 단계는 display 멤버 처리를 참조하라.
DisplayOverrideEntryObject는 다음 멤버를 가진 [=ordered map=]이다:
다음 단계는 웹 앱의 선택된 표시 모드 결정에서 [=application manifest/processing extension-point=]에 추가되며, 이제 선택적인 [=URL=] |document URL|도 받는다:
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, 그리고 [=URL=] |manifest URL:URL|이 주어졌을 때 `display_override` 멤버를 처리하려면, 다음을 실행한다:
일반 표시 모드에 더하여, [=manifest/display_override=]는 특정 표시 모드 확장도 지원한다.
다음은 standalone보다
minimal-ui 표시 모드를 선호하지만,
minimal-ui가 지원되지 않으면
browser가 아니라 standalone으로 대체하는
[=manifest=]를 보여준다.
{
"name": "Recipe Zone",
"description": "All of the recipes!",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/index.html",
"display_override": ["minimal-ui"],
"display": "standalone",
"theme_color": "yellow",
"background_color": "red"
}
unframed 표시 모드
[=display mode/unframed=] 표시 모드는 [[[isolated-web-apps]]]가 제목 표시줄 영역을 포함하여 앱 창의 외형을 완전히 제어할 수 있게 한다.
[=display mode/unframed=]인 창에는 호스트 네이티브 제목 표시줄이나 [=window controls=]가 보이지 않으며, 웹 콘텐츠는 전체 창 영역으로 확장된다. 앱은 웹 콘텐츠 안에 [=draggable regions=]를 지정하여 사용자 정의 제목 표시줄을 만들 수 있다.
[=User agents=]는 [=display mode/unframed=]의 사용을 [[[isolated-web-apps]]]로 제한해야 한다(MUST).
[=display mode/unframed=] 창이 생성되면, 그 표시 모드는 창의 수명 동안 고정된다. [=user agent=]는 범위 밖 URL로의 탐색이 unframed 창 안에서 일어나도록 허용해서는 안 된다(MUST NOT).
다음 그림들은 표준 웹 애플리케이션 창과 [=display mode/unframed=] 표시 모드를 활용하는 창 사이의 시각적 차이를 보여준다. 일반 앱 창(왼쪽)은 호스트 네이티브 제목 표시줄과 표준 창 컨트롤을 포함한다. 반대로, unframed 앱 창(오른쪽)은 이러한 호스트 제공 프레임 장식을 제거하여 웹 콘텐츠가 전체 창 영역을 차지할 수 있게 한다.
[=display mode/unframed=] 표시 모드는 `display-mode` 미디어 특성을 사용하여 쿼리할 수 있다.
@media (display-mode: unframed) {
/* styles for unframed mode */
}
개발자에게 제목 표시줄의 제어권을 주면, 이전에는 신뢰할 수 있는 사용자 에이전트 제어 영역이었던 곳의 콘텐츠를 스푸핑할 수 있게 된다. 이 위협을 완화하기 위해, 이 기능은 [[[isolated-web-apps]]]에서만 사용할 수 있어야 하며 창 관리 권한 뒤에 게이트되어야 한다.
[=display mode/unframed=] 창에는 제목 표시줄이 없으므로, 앱 출처나 개인정보 보호 표시기(예: 카메라 및 마이크 접근용)처럼 [=user agent=]가 일반적으로 제목 표시줄에 표시하는 중요한 표시기는 다른 곳에 표시되어야 한다. 이러한 표시기를 표시할 구체적인 위치는 플랫폼에 따라 다르며 사용자 에이전트가 결정한다.
`app-region` 속성은 예를 들어 제목 표시줄의 어떤 영역이나 요소가 드래그 가능한지를 CSS로 정의하는 데 사용할 수 있다.
`app-region` 속성은 창에 적용된 [=display mode=]가 [=display mode/unframed=] 또는 [=display mode/window-controls-overlay=]인 경우에만 효과를 가져야 한다(MUST).
이 명세에서 추가된 모든 새로운 확장 및 인큐베이션 기능을 용이하게 하기 위해, 사용자 에이전트는 [=processing a manifest=]의 확장 지점에서 다음을 실행하는 것이 좋다(SHOULD) ([=URL=] |document URL:URL|, [=URL=] |manifest URL:URL|, [=ordered map=] |json:ordered map|, 그리고 [=ordered map=] |manifest:ordered map|에 접근할 수 있는 상태에서):
tab_strip 멤버
Web Application Manifest의 `tab_strip` 멤버는 애플리케이션이 [=display mode/tabbed=] 표시 모드에서 어떻게 동작하도록 의도되었는지에 대한 정보를 포함하는 객체이다. 이는 다음 멤버를 가진다:
home_tab 멤버
[=tab_strip=] 객체의 `home_tab` 멤버는 애플리케이션의 최상위 메뉴 역할을 하도록 의도된 특별한 "홈 탭"에 대한 정보를 포함하는 순서 있는 맵이다. 이는 다음 멤버를 포함한다:
scope_patterns 멤버는 [=manifest URL=]을 기준으로
[=within home tab scope|홈 탭의 범위=]를 정의하는
{{URLPatternInput}}의 목록이다.
애플리케이션에 적용된 [=display mode=]가 [=display mode/tabbed=]이고, [=Document/processed manifest=]가 [=tab_strip=] 멤버의 null이 아닌 [=home_tab=] 멤버를 포함하면, 그 애플리케이션은 홈 탭을 가진다.
홈 탭 컨텍스트는 다른 애플리케이션 컨텍스트와 비교하여 특별한 속성을 가지는 선택적 [=application context=]이다. 애플리케이션이 [=has a home tab=]이면, 모든 애플리케이션 창은 [=home tab context=]를 포함하는 것이 좋다(SHOULD). 그렇지 않으면, 애플리케이션 창은 [=home tab context=]를 가져서는 안 된다(SHOULD NOT).
[=home tab context=]가 어떻게 표시되는지는 사용자 에이전트의 재량에 달려 있지만, 일반 애플리케이션 컨텍스트와 다른 외형을 가지는 것이 좋다(SHOULD).
[=URL=] |url:URL|은 다음 경우에, 그리고 그 경우에만 홈 탭 범위 내에 있다고 한다:
URL은 [=within home tab scope=]가 아니면 홈 탭 범위 밖이다.
애플리케이션이 [=has a home tab=]이면, 새 애플리케이션 창이 생성될 때마다 (예를 들어 애플리케이션을 시작할 때나 탭을 새 창으로 이동할 때), 사용자 에이전트는 그 창 안에 새 [=home tab context=]를 생성해야 한다(MUST). 새로 생성된 [=home tab context=]는 [=start URL=]로 탐색되는 것이 좋으며(SHOULD), 이는 정의상 [=within home tab scope=]이다.
[=home tab context=]와 연결된 [=top-level traversable=]을 [=outside of home tab scope=]인 [=URL=] |url:URL|로 [=navigate|탐색=]할 때, 다음 단계가 실행된다:
"_blank" 대상과 noopener true로 navigable을 선택한 결과를
[=top-level traversable=] |tab:toplevel traversable|로 둔다.
[=display mode/tabbed=]의 [=display mode=]를 가진 [=top-level traversable=]로서 [=home tab context=]와 연결되지 않은 것(즉, 비-홈 탭)을 [=within home tab scope=]인 [=URL=] |url:URL|로 [=navigate|탐색=]할 때, 다음 단계가 실행된다:
위 규칙들은 [=has a home tab|홈 탭을 가지는=] 애플리케이션에 대해 다음 불변 조건들이 항상 참이 되도록 보장하려는 것이다:
사용자 에이전트는 문서가 [=URL/fragment=]를 변경하거나 {{History}} API를 사용하여 표시 URL을 홈 탭 범위 안팎으로 수정하더라도, 문서를 홈 탭 컨텍스트와 비-홈 탭 컨텍스트 사이에서 동적으로 이동하지 않는다. 이는 실제 탐색이 일어나지 않기 때문이다. 이러한 이유로, 위 불변 조건들은 문서가 생성될 당시 문서가 가지고 있던 [=Document/URLs=]에만 관심을 둔다.
URL을 수정하여 탐색하는 것처럼 "가장하는" 단일 페이지 애플리케이션의 경우, 이는 위 불변 조건을 깨는 바람직하지 않은 동작을 초래할 수 있다 (예: 사용자가 홈 탭의 링크를 클릭하여 URL을 비-홈 페이지로 동적으로 변경하면, 실제로 탐색하는 것이 아니기 때문에 홈 탭 안에 머무르게 된다). 이러한 상황을 피하기 위해, 애플리케이션은 자신이 tabbed 애플리케이션 모드에 있는지를 감지하고, URL을 수정하는 대신 홈 탭 범위 안팎으로 실제 탐색을 수행하도록 동작을 변경할 수 있다.
new_tab_button 멤버
[=tab_strip/new_tab_button=] 멤버는 클릭/활성화될 때 애플리케이션 창 안에서 새 [=application context=]를 여는 UI 어포던스(예: 버튼)의 동작을 설명하는 순서 있는 맵이다. 이는 다음 멤버를 가진다:
url 멤버는
[=Document/processed manifest=]의 [=manifest/within scope=]인
[=manifest URL=] 기준의 URL을 나타내는 문자열이다.
[=Document/processed manifest=]의 [=new_tab_button=]의 [=new_tab_button/url=] 멤버가 [=outside of home tab scope=]이면, 애플리케이션은 새 탭 버튼을 가진다. 애플리케이션이 [=has a new tab button|새 탭 버튼을 가지지 않으면=], 사용자 에이전트는 "새 탭" 어포던스를 최종 사용자에게 제공하지 않는 것이 좋다(SHOULD NOT).
새 탭 버튼이 최종 사용자에 의해 활성화되면, 다음 단계가 실행된다:
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, 그리고 [=URL=] |manifest URL:URL|이 주어졌을 때 `tab_strip` 멤버를 처리하려면, [=processing a manifest=]의 확장 지점에서 다음을 실행한다:
[=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map|, 그리고 [=URL=] |manifest URL:URL|이 주어졌을 때 `home_tab` 멤버를 처리하려면, 다음을 실행한다:
[=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map|, [=URL=] |manifest URL:URL|, 그리고 [=URL=] |start URL:URL|이 주어졌을 때 `new_tab_button` 멤버를 처리하려면, 다음을 실행한다:
[=ordered map=] |json home tab:ordered map|, [=ordered map=] |manifest home tab:ordered map| 및 [=URL=] |manifest URL:URL|이 주어졌을 때 `scope_patterns` 멤버를 처리하려면, 다음을 실행한다:
{
"name": "Tabbed App Example",
"start_url": "/",
"display": "standalone",
"display_override": ["tabbed"],
"tab_strip": {
"home_tab": {
"scope_patterns": [
{"pathname": "/"},
{"pathname": "/index.html"}
]
},
"new_tab_button": {
"url": "/create"
}
}
}
이 예는 tabbed 모드가 지원되지 않는 경우 단일 문서 standalone 창으로
대체되는 tabbed 웹 앱이다. 기본 index 페이지(/ 또는
/index.html)로의 모든 탐색은 [=home tab context=]에서 열린다.
새 탭 버튼은 /create에서 새 탭을 연다.
[=tab_strip/home_tab/scope_patterns=]에 대해 일치시킬 때는 기본적으로
URL의 [=URL/query=] 부분이 무시된다(따라서
/index.html?utm_source=foo로의 탐색은 홈 탭에서 열린다).
그러나 [=start URL=]에 대해 일치시킬 때는 [=URL/query=]가 정확히
일치해야 하므로, 쿼리를 무시하려는 사이트는 [=start URL=]의
[=URL/path=]를 범위 패턴으로 명시적으로 포함하는 것이 좋다.
`share_target` 멤버는 웹 애플리케이션을 share actions(예: 텍스트, URL 또는 파일 공유)에 대한 "target"으로 등록한다. `share_target` 멤버는 [[[web-share-target]]] 명세의 일부이다.
note_taking 멤버
Web Application Manifest의 `note_taking` 멤버는 note-taking과 관련된 정보를 담는 object이다. 다음 멤버들을 가진다:
사용자 에이전트는 이러한 멤버를 사용하여 웹 애플리케이션을 note-taking 기능을 가진 애플리케이션으로 다르게 취급할 수 있다(MAY)(예: 운영체제의 note-taking surface와 통합).
new_note_url
멤버
[=note_taking=] `new_note_url` 멤버는 사용자가 웹 애플리케이션을 사용하여 새 note를 작성하려고 할 때(예: 운영체제 바로 가기 아이콘이나 키보드 단축키에서) 개발자가 사용자 에이전트가 로드하기를 선호하는 URL을 나타내는 [=string=]이다.
`new_note_url` 멤버는 순수하게 권고적인 것이며, 사용자 에이전트는 이를 무시하거나 최종 사용자에게 사용할지 여부를 선택하게 할 수 있다(MAY). 사용자 에이전트는 최종 사용자에게 이를 수정할 선택권을 제공할 수 있다(MAY).
다음은 note-taking 애플리케이션을 위한 [=manifest=]를 보여준다.
{
"name": "My Note Taking App",
"description": "You can take notes!",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/index.html",
"display": "standalone",
"note_taking": {
"new_note_url": "/new_note.html"
}
}
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, [=URL=] |manifest_URL:URL|가 주어졌을 때 process the `note_taking` member하려면, [=processing a manifest=]의 extension point 중에 다음을 실행한다:
[=ordered map=] |json_note_taking:ordered map|, [=ordered map=] |manifest_note_taking:ordered map|, [=URL=] |manifest_URL:URL|가 주어졌을 때 process the `new_note_url` member하려면, 다음을 실행한다:
processed manifest |manifest:processed manifest|가 주어졌을 때 launch the `new_note_url`하려면, 다음 단계를 실행한다:
사용자 에이전트는 주어진 [=installed web application=]에 대해 언제든지, 일반적으로 사용자 affordance에 대한 응답으로 [=launch the `new_note_url`=]할 수 있다(MAY).
[=manifest=]의 protocol_handlers 멤버는 웹 애플리케이션이
URL 프로토콜을 처리할 수 있게 하는
프로토콜 핸들러 설명들의 배열이다.
설치 시, 사용자 에이전트는 다음과 일관된 상호작용을 통해 운영체제에 protocol handlers를 등록해야 한다(SHOULD):
[=object=] |json:JSON|, |manifest:ordered map|가 주어졌을 때 process the `protocol_handlers` member하려면:
사용자 에이전트는 host 운영체제에서 protocol의 기본 handler로 [=protocol handler description=] protocol_handler들을 등록하기 전에 사용자에게 권한을 요청해야 한다(SHOULD). 사용자 에이전트는 host 운영체제의 관례나 제한과 일관되게 유지하기 위해 표시되는 [=protocol handler description=] protocol_handlers 목록을 잘라낼 수 있다(MAY).
각 protocol handler description은 웹 애플리케이션이 처리하려는 protocol을 나타내는 [=object=]이며, [=manifest/protocol_handlers=] 멤버에 대응한다. 다음 멤버들을 가진다:
사용자 에이전트는 이러한 값을 사용하여 웹 애플리케이션을 운영체제에 handler로 등록해야 한다(SHOULD). 사용자가 protocol handler URL을 활성화하면, 사용자 에이전트는 handling a protocol launch를 실행해야 한다(SHOULD).
protocol handler description의 protocol 멤버는
`mailto` 또는 `web+auth`와 같이 처리할 protocol을 나타내는
string이다.
protocol handler description의
[=protocol handler description/protocol=] 멤버는 [[HTML]]에 정의된
{{NavigatorContentUtils/registerProtocolHandler()}}의
scheme 인자와 동등하다.
protocol handler description의 url 멤버는 관련 protocol이
활성화될 때 열리는 애플리케이션의 [=manifest/within scope=]인
URL이다.
protocol
handler description의 [=protocol handler description/url=] 멤버는
[[HTML]]에 정의된 {{NavigatorContentUtils/registerProtocolHandler()}}의
url 인자와 동등하다.
[=manifest=] manifest를 가지는 protocol handler description protocol_handler가 호출되면, 사용자 에이전트가 resultURL로 [=navigating=]하는 대신 manifest와 resultURL을 전달하여 [=launch a web application=]해야 한다는 점을 제외하고, [=invoke a protocol handler=]에 사용되는 동일한 단계를 거친다.
이는 이러한 방식으로 [=invoke a protocol handler=]를 호출하고 변경해서는 안 된다. resultURL의 계산은 일반적인 사용을 위한 별도 알고리즘으로 추출되어야 한다.
운영체제의 기능에 따라, protocol handler는 사용자의 명시적 인지 없이 주어진 protocol의 'default' handler(예: 주어진 protocol의 실행을 자동으로 처리)가 될 수 있다. 가능한 오용을 방지하기 위해, 사용자 에이전트는 다음과 같은 보호 조치를 사용할 수 있다(MAY):
사용자 에이전트가 protocol handler entity의 등록을 제거하는 경우, 사용자가 웹 앱과 protocol을 운영체제에 다시 등록할 수 있는 UX를 제공해야 한다(SHOULD).
[=manifest=]의 file_handlers 멤버는 앱 자체의 외부에서
비롯되는 파일 열기 동작을 앱이 처리하는 방법에 대한 지침을 제공하는
[=list=]이다.
등록된 file-handling applications의 관리, 표시 및 선택은 운영체제의 재량에 맡겨진다.
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, [=URL=] |manifest_url:URL|가 주어졌을 때 process the `file_handlers` member하려면:
[=installation=] 시, 사용자 에이전트는 [=register file handlers=] 과정을 실행해야 한다(SHOULD).
각 file handler는 자신이 수락하는 [=file types=]로 실행을 처리할 수 있는 애플리케이션 scope 내의 URL을 나타낸다. 다음 멤버들을 가진다:
사용자 에이전트는 이러한 멤버를 사용하여 웹 애플리케이션을 운영체제의 [=file type=]과 연결할 수 있다.
file type은 [=MIME type=] 및/또는 [=file extension=]으로 정의될 수 있다. OS가 파일에 [=MIME type=]이 있다고 판단하거나 그 이름이 특정 [=file extension=]으로 끝나는 경우, 파일은 file type에 속한다. file extension은 "."로 시작하고 valid suffix code points만 포함하는 문자열이다. 또한 [=file extensions=]는 16 code points 길이로 제한된다.
[=file handler=]의 action 멤버는
manifest URL 기준의
URL을 나타내는 string이며,
processed
manifest의 [=manifest/within scope=]이다. 이
URL은 [=execute a file handler
launch=] 단계에서 탐색된다.
[=file handler=]의 name 멤버는 사용자에게 file type을
식별하는 string이다. [=User agents=]는 file handler
등록 중 이 정보를 운영체제에 전달할 수 있다(MAY).
file handler의 icons 멤버는 [=file type=]의 그래픽 표현으로
사용되는 icons를 나열한다. 사용자 에이전트는 file handler 등록 중
이 정보를 운영체제에 전달할 수 있다(MAY).
[=file handler=]의 accept 멤버는 [=MIME types=]를
[=file extensions=] 리스트에 매핑하는 dictionary이다.
[=User agents=]는 [=file handler/accept=] 항목이 일치하는 확장자를 가진 파일에만 적용되도록 강제해야 한다(MUST).
[=register file handlers=]하기 위해, 일부 운영체제는 [=MIME types=]를 요구하고 일부는 [=file extensions=]를 요구한다. 따라서 manifest는 각 [=file handler/accept=] 항목에 대해 항상 둘 모두를 제공해야 한다(MUST).
완전한 [=MIME types=] 외에도, "*"를 [=MIME type=]의
subtype으로 사용하여 예를 들어 "image/*"로 모든 이미지
형식(제공된 [=file extensions=] 리스트에도 적용되는)을 매칭할 수
있다.
[=file handler=]의 launch_type 멤버는 이 handler로 라우팅된
파일에 대해 앱이 어떻게 실행되는지를 결정하는 string이다.
가능한 값은 `"single-client"`와 `"multiple-clients"`이다. 제공되지
않으면 기본값은 `"single-client"`이다.
[=file handler=]가 파일 집합과 일치한다고 판단되면, [=user agent=]는 각 파일마다 한 번씩 앱을 실행할지(`"multiple-clients"`), 모든 파일에 대해 한 번만 실행할지(`"single-client"`) 제어하기 위해 [=file handler/launch_type=]을 사용해야 한다(SHOULD). {{LaunchParams/files}}를 참조한다. 사용자 에이전트는 서로 다른 [=file handlers=]의 파일을 하나의 launch event로 병합해서는 안 된다(MUST NOT).
[=ordered map=] |item:ordered map|, [=URL=] |start_url:URL|, [=URL=] |scope:URL| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process a file handler item하려면:
execute a file handler launch 단계는 다음 알고리즘으로 주어진다. 이 알고리즘은 [=list=] |files:list|와 [=processing a manifest=]의 결과를 보유하는 [=ordered map=] |manifest:ordered_map|을 취한다.
사용자 에이전트는 다음과 일관되게 host 운영체제에 register file handlers해야 한다(SHOULD):
사용자 에이전트는 기능을 보존하고 남용을 방지하기 위해 [=file extensions=]의 전체 집합을 잘라낼 수 있다(MAY). 사용자 에이전트는 특정 filetypes와의 연결을 방지할 수 있다(MAY).
운영체제의 기능에 따라, [=file handler=]는 사용자의 명시적 인지 없이 주어진 [=file type=]의 기본 handler가 되어 해당 file type의 실행을 자동으로 처리할 수 있다. 가능한 오용을 방지하기 위해, [=user agents=]는 [=execute a file handler launch=] 과정을 시작하기 전에 명시적 사용자 동의를 요구할 수 있다(MAY). 동의를 요청하는 경우, 사용자 에이전트는 사용자가 그 결정을 영구적으로 지정할 수 있도록 허용해야 하며(SHOULD), 그렇게 지정된 경우 웹 애플리케이션의 OS file handling entity 등록을 제거해야 한다(SHOULD).
각 file handler의 이름과 아이콘은 개인정보 및 보안에 민감할 수 있다. 사용자가 이를 보고 확인하는 지정된 방법이 없기 때문이다. 이로 인해, [=user agents=]는 대체 문자열과 아이콘을 선호하거나 OS 기본값으로 fallback하기 위해 이를 무시하도록 선택할 수 있다(MAY).
다음 예제에서 웹 애플리케이션은 서로 다른 3개의 file handler를 가진다.
related application은 웹 애플리케이션과 관계가 있는, underlying application platform에서 접근 가능한 애플리케이션이다.
[=manifest=]의 related_applications 멤버는 관련
애플리케이션을 나열하며, 웹 애플리케이션과 관련 애플리케이션
사이의 그러한 관계를 나타내는 표시 역할을 한다. 이 관계는 단방향이며,
나열된 애플리케이션이 동일한 관계를 주장하지 않는 한, 사용자 에이전트는
양방향 보증을 가정해서는 안 된다(MUST NOT).
`related_applications` 사용 예로는, 그 정보를 사용하여 웹 애플리케이션에 대한 더 많은 정보를 수집하는 crawler나, 사용자가 웹 애플리케이션을 설치하려 할 때 나열된 애플리케이션을 대안으로 제안할 수 있는 browser가 있을 수 있다.
[=ordered map=] |json:ordered map| 및 [=ordered map=] |manifest:ordered map|가 주어졌을 때 process the `related_applications` member하려면:
[=manifest=]의 `prefer_related_applications` 멤버는
웹 애플리케이션보다 관련 애플리케이션을 선호해야 함을
사용자 에이전트에게 알리는 힌트로 사용되는 [=boolean=]이다.
`prefer_related_applications` 멤버가 `true`로 설정되어 있고
사용자 에이전트가 웹 애플리케이션 설치를 제안하려는 경우,
사용자 에이전트는 대신 관련 애플리케이션 중 하나의 설치를
제안하고자 할 수 있다.
[=manifest=]의 scope_extensions 멤버는 애플리케이션이 원하는
[=scope extensions=]의 목록을 나타낸다.
scope extension은 [=within extended scope=]로 취급되어야 하는 추가 [=URLs=]를 설명함으로써 [=manifest/navigation scope of a manifest=]를 확장한다.
사용자 에이전트는 추가 [=URLs=]가 [=within extended scope=]가 되도록 [=apply extended scope=]할 수 있기 전에 [=process the scope_extensions member=]와 [=validate scope extensions=]를 수행해야 한다(MUST).
[=URL=] |target:URL|은 |target|이 manifest의 [=manifest/within scope=]이거나 [=matches a validated scope extension=]인 경우 |manifest:processed manifest|의 within extended scope이다.
[=URL=] |target:URL|은 [=URL=] |target:URL| 및 [=list=] |validated_scope_extensions:list|가 주어졌을 때 다음 알고리즘이 `true`를 반환하는 경우 matches a validated scope extension이다:
다음 예제는 `scope_extensions` 멤버를 사용하는 애플리케이션의 [=manifest=]를 보여준다.
{
"id": "https://example.com/app",
"name": "My App",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/app/index.html",
"scope": "/app",
"display": "standalone",
"scope_extensions": [
{ "type": "origin", "origin": "https://example.co.uk" },
{ "type": "origin", "origin": "https://help.example.com" }]
}
다음은 `scope_extensions` 멤버에 나열된 [=origins=]의 `.well-known` path에서 다운로드할 수 있는 2개의 [=web-app-origin-association=] 파일을 보여준다.
{
"https://example.com/app": {
"scope": "/app"
}
}
{
"https://example.com/app": {
"scope": "/"
}
}
이 앱의 navigation scope는 다음 [=URLs=] 중 어느 것의 [=URL/within scope=]인 URL들로 구성된다: `https://example.com/app`, `https://example.co.uk/app`, 및 `https://help.example.com`.
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map| 및 [=URL=] |manifest_id:URL|가 주어졌을 때 process the `scope_extensions` member하려면:
[=ordered map=] |extension:ordered map| 및 [=URL=] |manifest_id:URL|가 주어졌을 때 validate scope extensions하려면:
사용자 에이전트는 어떤 시나리오에서는 apply extended scope를 적용하고 다른 시나리오에서는 [=manifest/scope=]를 적용하도록 선택할 수 있다(MAY).
[=application context=]의 [=navigable/active document=]의 [=URL=]이 [=manifest/within scope=]가 아니지만 [=within extended scope=]이면, 사용자 에이전트는 사용자가 [=URL=] 또는 적어도 그 [=origin=]을, secure connection을 통해 제공되는지 여부를 포함하여 확인할 수 있게 하는 UI를 제공해야 한다(SHOULD). 이 UI는 [=URL=]이 [=application context=]의 [=Document/processed manifest=]의 [=manifest/within scope=]가 아닐 때 사용되는 UI와 달라야 하며(SHOULD), 사용자가 여전히 애플리케이션의 의도된 콘텐츠를 탐색하고 있음을 분명히 하면서도 다른 [=origin=]으로 탐색하는 것의 개인정보 및 보안 영향을 계속 알 수 있게 해야 한다.
web-app-origin-association 파일은 [=validate scope extensions=] 또는 [=validate origin migration=]에 사용할 수 있는 JSON 파일이다. 이는 그 파일이 있는 origin과 하나 이상의 웹 애플리케이션 사이의 association을 확인한다. 이는 manifest [=manifest/ids=]를 참조하여 앱을 고유하게 식별한다.
[=origin=] |origin:origin|이 주어졌을 때, [=web-app-origin-association=]
파일은
[origin]/.well-known/web-app-origin-association에서 다운로드할 수
있을 것으로 기대된다.
Web Application Origin Migration은 웹 애플리케이션이 한 origin에서 다른 origin(동일 site 내)으로 이동했음을 사용자 에이전트에 나타낼 수 있게 한다. 이는 사용자 에이전트가 사용자의 설치와 잠재적으로 설정을 보존하면서 설치된 웹 애플리케이션을 migrate할 수 있게 한다.
다음 예제는 https://old.example.com에 호스팅된 웹
애플리케이션을 https://new.example.com으로 migrate할 수
있는 방법을 보여준다. 두 origins는 [=same site=]여야 하며 migration에
명시적으로 동의해야 한다.
먼저, 이전 애플리케이션의 manifest는 사용자 에이전트에 이동 의도를 알리기 위해 선택적으로 `migrate_to` 멤버를 포함할 수 있다(또는 이전 애플리케이션이 새 애플리케이션으로 redirect할 수 있다):
{
"name": "My App",
"id": "/",
"migrate_to": {
"id": "https://new.example.com/",
"install_url": "https://new.example.com/install"
}
}
다음으로, 새 애플리케이션의 manifest는 이전 애플리케이션으로부터의 migration을 claim하기 위해 `migrate_from` 멤버를 포함한다:
{
"name": "My New App",
"id": "/",
"migrate_from": [
{
"id": "https://old.example.com/",
"install_url": "https://old.example.com/install",
"behavior": "force"
}
]
}
마지막으로, 이전 origin은 새 애플리케이션이 takeover하는 것을 허용한다고 definitively validate하기 위해 `web-app-origin-association` 파일을 호스트해야 한다. 이 파일이 없으면, 악의적인 새 애플리케이션이 허가 없이 이전 애플리케이션으로부터 migrate한다고 주장할 수 있다.
{
"https://new.example.com/": {
"allow_migration": true
}
}
migrate_from 멤버
[=manifest/migrate_from=] 멤버는 migration 대상이 되는 이전 웹 애플리케이션을 식별하는 [=strings=] 또는 [=ordered maps=]의 [=list=]이다.
entry가 [=string=]이면, 이전 애플리케이션의 [=manifest/id=]로 취급된다.
entry가 [=ordered map=]이면, 다음 멤버들을 가질 수 있다:
id: 이전
애플리케이션의 [=manifest/id=]를 나타내는 [=string=].
install_url: 이전 애플리케이션의
manifest로 연결되는 페이지의 URL을 나타내는 [=string=].
사용자 에이전트는 이전 애플리케이션의 일부인 다른 모든 URL이 새
애플리케이션으로 redirect하더라도 업데이트를 적용하기 위해 이
필드를 사용하여 이전 애플리케이션의 manifest를 fetch할 수 있다.
behavior:
`"suggest"` 또는 `"force"` 중 하나일 수 있는 [=string=].
이는 migration에 대해 사용자에게 알리기 위해 사용자 에이전트가
표시하는 UI가 얼마나 강제적인지에 영향을 줄 수 있는 hint이다.
migrate_to 멤버
[=manifest/migrate_to=] 멤버는 새 애플리케이션으로의 migration을 능동적으로 알리는 선택적 [=ordered map=]이다. 다음 멤버들을 가진다:
id: 새
애플리케이션의 [=manifest/id=]를 나타내는 [=string=].
install_url: 새 애플리케이션의 manifest로
연결되는 페이지의 URL을 나타내는 [=string=]. 이 페이지의 manifest는
migration이 처리되기 위해 이 애플리케이션을 다시 가리키는
[=manifest/migrate_from=] 필드를 포함해야 한다.
[=URL=] |old_manifest_id:URL| 및 [=URL=] |new_manifest_id:URL|가 주어졌을 때 validate origin migration하려면:
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process the `migrate_from` member하려면:
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process the `migrate_to` member하려면:
악의적인 행위자가 조용히 애플리케이션을 takeover하는 것(예: 단순한 계산기 앱이 자신을 은행 앱처럼 보이도록 업데이트하는 것)을 방지하기 위해, [=validate origin migration=] 알고리즘은 양방향 handshake를 강제한다. 새 애플리케이션 origin과 이전 애플리케이션 origin 모두 [=web-app-origin-association=] 파일을 통해 migration에 명시적으로 동의해야 한다.
또한 migration은 검증되지 않은 제3자에게 ownership을 이전하는 것이 아니라 조직의 통제 내에서 이루어지는 정당한 rebranding 및 architecture 변경에 사용되도록 보장하기 위해 [=same site=]로 제한된다.
사용자 에이전트는 특히 app name 및 icons와 같은 보안에 민감한 필드의 업데이트가 포함된 경우, migration flow의 일부로 명시적 사용자 확인 dialog를 포함하는 것을 고려해야 한다.
각 external application resource는 웹 애플리케이션과 관련된 애플리케이션을 나타낸다.
[=external application resource=]는 다음 멤버들을 가질 수 있으며, 그중 일부는 [=valid external application resource=]가 되기 위해 필요하다:
valid external application resource는 반드시 [=external application resource/platform=] 멤버와, [=external application resource/url=] 또는 [=external application resource/id=] 멤버(또는 둘 다)를 가져야 한다(MUST).
platform 멤버는 이
[=external application resource=]가 연결된 [=platform=]을 나타낸다.
platform은 software distribution ecosystem
또는 가능하게는 operating system을 나타낸다. 이 명세는
platform 멤버의 특정 값을 정의하지 않는다.
[=external application resource's=] url 멤버는 애플리케이션을
찾을 수 있는 URL이다.
process the `url` member of an application하려면:
[=external application resource's=] id 멤버는 platform에서
애플리케이션을 나타내는 데 사용되는 id를 나타낸다.
[=external application resource's=] min_version 멤버는
이 웹 앱과 관련 있다고 간주되는 애플리케이션의 minimum version을
나타낸다. 이 version은 platform-specific syntax 및 semantics를 가진
string이다.
[=external application resource=]의 fingerprints 멤버는
[=fingerprints=]의 [=list=]를 나타낸다.
fingerprint는 애플리케이션을 검증하는 데 사용되는 암호학적 fingerprint들의 집합을 나타낸다. fingerprint는 다음 두 멤버를 가진다: type 및 value. 이들은 각각 문자열이지만, 그 구문과 의미는 플랫폼에 의해 정의된다.
설치 과정을 트리거할 수 있는 여러 방법이 있다:
어떤 경우든, document가 installable이 아니면 사용자 에이전트는 present an install prompt해서는 안 된다(MUST NOT).
사용자 에이전트는 언제든지(단, document가 installable인 경우에만) steps to notify that an install prompt is available를 실행할 수 있으며(MAY), 이를 통해 사이트는 사용자가 사용자 에이전트 UI와 상호작용할 필요 없이 site-triggered install prompt를 표시할 기회를 얻는다.
install prompt를 표시하려면:
steps to notify that an install prompt is available는 다음 알고리즘으로 주어진다:
steps to install the web application은 다음 알고리즘으로 주어진다:
설계상, 이 명세는 개발자에게 웹 애플리케이션을 "install"하는 명시적 API를 제공하지 않는다. 대신, manifest는 웹 애플리케이션을 설치할 수 있다는 사용자 에이전트에 대한 installability signal로 작동할 수 있다. 이러한 signals는 사용자 에이전트마다 달라지며, 각 사용자 에이전트는 웹 사이트가 install prompt를 받을 자격이 있는지 판단하기 위한 자체 heuristics를 가진다. 구현자는 일반적으로 특정 installabilty signals 또는 웹 애플리케이션이 installable로 간주되기 위해 충족해야 하는 기타 관련 기준을 설명하는 문서를 제공한다.
사용자 에이전트가 구현할 수 있는 웹 애플리케이션의 가능한 installability signals 예:
이 목록은 완전하지 않으며 일부 installability signals는 모든 사용자 에이전트에 적용되지 않을 수 있다. 사용자 에이전트가 이러한 installability signals를 사용하여 웹 애플리케이션을 설치할 수 있는지 결정하는 방법은 구현자에게 맡겨진다.
이 명세의 [=event|Events=]는 application life-cycle task source에 의존한다.
[Exposed=Window]
interface BeforeInstallPromptEvent : Event {
constructor(DOMString type, optional EventInit eventInitDict = {});
Promise<PromptResponseObject> prompt();
};
dictionary PromptResponseObject {
AppBannerPromptOutcome userChoice;
};
enum AppBannerPromptOutcome {
"accepted",
"dismissed"
};
{{BeforeInstallPromptEvent}}는 사이트가 site-triggered install prompt를 표시할 수 있도록 허용될 때, 또는 사용자 에이전트가 automated install prompt를 표시하기 전에 dispatch된다. 이는 사이트가 automated install prompt를 cancel할 수 있게 하고, 또한 site-triggered install prompt를 수동으로 표시할 수 있게 한다.
PromptResponseObject는 {{BeforeInstallPromptEvent/prompt()}}를 호출한 결과를 포함한다. 이는 사용자가 선택한 outcome을 나타내는 하나의 멤버 userChoice를 포함한다.
{{BeforeInstallPromptEvent}}의 인스턴스는 다음 internal slots를 가진다:
prompt() 메서드
prompt 메서드는 호출되면 다음 단계를 실행한다:
{{BeforeInstallPromptEvent}} event와 함께 request to present an install prompt하려면:
이 예제는 사용자가 버튼을 클릭하여 site-triggered install prompt를 표시할 때까지 automated install prompt가 표시되지 않도록 하는 방법을 보여준다. 이런 방식으로, 사이트는 설치를 임의의 시점에 prompting하는 대신 사용자의 재량에 맡길 수 있으며, 동시에 이를 위한 눈에 띄는 UI를 제공할 수 있다.
window.addEventListener("beforeinstallprompt", event => {
// Suppress automatic prompting.
event.preventDefault();
// Show the (disabled-by-default) install button. This button
// resolves the installButtonClicked promise when clicked.
installButton.disabled = false;
// Wait for the user to click the button.
installButton.addEventListener("click", async e => {
// The prompt() method can only be used once.
installButton.disabled = true;
// Show the prompt.
const userChoice = await event.prompt();
console.info(`user choice was: ${userChoice}`);
});
});
AppBannerPromptOutcome enum
AppBannerPromptOutcome enum의 값은 presenting an install prompt의 outcomes를 나타낸다.
partial interface Window {
attribute EventHandler onappinstalled;
attribute EventHandler onbeforeinstallprompt;
};
onappinstalled 속성
onappinstalled event handler IDL attribute는 "appinstalled" 이벤트를 처리한다.
onbeforeinstallprompt 속성
onbeforeinstallprompt event handler IDL attribute는 "beforeinstallprompt" 이벤트를 처리한다.