Web Application Manifest 확장 및 인큐베이션을 위한 기능 명세로, Chromium은 이미 출시했지만 다른 사용자 에이전트의 약속 / 구현은 없는 기능을 다룬다. 이러한 기능을 explainer로 유지하는 대신, 여기에서 더 공식적으로 문서화한다.
이는 비공식 제안이다.
display_override 멤버
고급 사용을 위해, [=manifest/display_override=] 멤버는 개발자가 웹 애플리케이션에 대해 선호하는 display mode를 선택할 수 있도록 display mode list values의 사용자 지정 fallback 순서를 지정하는 데 사용할 수 있다. 그 값은 [=display mode=]이다.
[=application manifest=]의 [=manifest/display_override=] 멤버는 [=display mode/window-controls-overlay=] 및 [=display mode/unframed=]와 같은 확장을 포함하는 display mode list values의 sequence이다. 이 멤버는 [=display mode=]들에 대한 개발자의 선호 fallback 체인을 나타낸다. 이 필드는 [=manifest/display=] 멤버를 재정의한다. 사용자 에이전트가 여기에 지정된 [=display mode=] 중 어느 것도 지원하지 않는 경우, 다시 [=manifest/display=] 멤버를 고려한다. 알고리즘 단계는 display 멤버 처리를 참조한다.
다음 단계들은 웹 앱의 선택된 display mode 결정에서 [=application manifest/processing extension-point=]에 추가된다:
이 멤버는 개발자가 자신의 display mode fallback 순서를 명시적으로 제어하려는 경우, 또는 기본 display modes list에서 사용할 수 없는 mode를 위한 고급 사례에서만 사용하도록 의도되었다. 그 외에는 대부분의 사용 사례에서 [=manifest/display=] 멤버로 충분하다.
일반적인 display modes에 추가로, [=manifest/display_override=]는 이에 대한 특정 확장도 지원한다.
다음은 standalone보다
minimal-ui display mode를
선호하지만, minimal-ui가 지원되지 않으면
browser가 아닌 standalone으로 fallback하는
[=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"
}
[=app-region=] CSS 속성은 어떤 사용자 에이전트에서도 구현되지 않았으므로 at risk 상태이다. 일부 사용자 에이전트는 같은 목적을 위해 비표준 CSS 속성 `-webkit-app-region`을 사용한다는 점에 유의한다.
`app-region` 속성은 예를 들어 title bar에서 어떤 영역이나 요소가 드래그 가능한지 CSS로 정의하는 데 사용할 수 있다.
이 명세가 추가하는 모든 새로운 확장 및 인큐베이션 기능을 용이하게 하기 위해, 사용자 에이전트는 [=processing a manifest=]의 extension point 중에 다음을 실행해야 한다(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=] display mode에서 애플리케이션이 어떻게 동작하도록 의도되었는지에 대한 정보를 담는 object이다. 다음 멤버들을 가진다:
home_tab 멤버
[=tab_strip=] object의 `home_tab` 멤버는 애플리케이션의 최상위 메뉴로 작동하도록 의도된 특별한 "home tab"에 대한 정보를 담는 ordered map이다. 다음 멤버들을 포함한다:
scope_patterns 멤버는 [=manifest URL=]을
기준으로 [=within home tab scope|home tab의 scope=]를 정의하는
{{URLPatternInput}}의 리스트이다.
애플리케이션의 적용된 [=display mode=]가 [=display mode/tabbed=]이고 [=Document/processed manifest=]가 [=tab_strip=] 멤버의 null이 아닌 [=home_tab=] 멤버를 포함하는 경우, 애플리케이션은 home tab을 가진다.
home tab context는 다른 application contexts와 비교하여 특별한 속성을 가지는 선택적 [=application context=]이다. 애플리케이션이 [=has a home tab=]이면, 모든 application window는 [=home tab context=]를 포함해야 한다(SHOULD). 그렇지 않으면, application windows는 [=home tab context=]를 가져서는 안 된다(SHOULD NOT).
[=home tab context=]가 어떻게 표시되는지는 사용자 에이전트의 재량에 맡겨지지만, 일반 application contexts와 다른 외형을 가져야 한다(SHOULD).
[=URL=] |url:URL|은 다음 경우에만 within home tab scope라고 한다:
URL이 [=within home tab scope=]가 아니면 outside of home tab scope이다.
애플리케이션이 [=has a home tab=]이면, 새 application window가 생성될 때마다(예: 애플리케이션을 실행할 때 또는 tab을 새 창으로 이동할 때) 사용자 에이전트는 그 창에 새로운 [=home tab context=]를 생성해야 한다. 새로 생성된 [=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" target과 noopener true로 navigable을
선택한 결과로 둔다.
[=display mode/tabbed=]의 [=display mode=]를 가지지만 [=home tab context=]와 연결되지 않은 [=top-level traversable=] (즉, non-home tab)을 [=within home tab scope=]인 [=URL=] |url:URL|로 [=navigate|탐색=]할 때, 다음 단계들이 실행된다:
위 규칙들은 [=has a home tab|home tab을 가지는=] 애플리케이션에 대해 다음 불변 조건들이 항상 참이 되도록 보장하기 위한 것이다:
사용자 에이전트는 document들이 [=URL/fragment=]를 변경하거나, {{History}} API를 사용하여 표시 URL을 home tab scope 안팎으로 수정하더라도 home-tab과 non-home-tab contexts 사이에서 동적으로 document를 이동하지 않는다. 탐색이 발생하지 않기 때문이다. 이러한 이유로, 위 불변 조건들은 document가 생성될 당시 가지고 있던 [=Document/URLs=]만 고려한다.
URL을 수정하여 탐색하는 척하는 single-page applications의 경우, 이는 위 불변 조건을 깨는 바람직하지 않은 동작을 초래할 수 있다 (예: 사용자가 home tab에서 링크를 클릭하여 URL을 non-home page로 동적으로 변경해도, 실제로 [=navigating=]하지 않기 때문에 home tab 안에 머무르게 된다). 이 상황을 피하기 위해, 애플리케이션은 tabbed application mode에 있는지 감지하고, URL을 수정하는 대신 home tab scope 안팎으로 실제 탐색을 수행하도록 동작을 변경할 수 있다.
new_tab_button 멤버
[=tab_strip/new_tab_button=] 멤버는 클릭/활성화되었을 때 application window 내에 새 [=application context=]를 여는 UI affordance (예: 버튼)의 동작을 설명하는 ordered map이다. 다음 멤버들을 가진다:
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=]이면 new tab button을 가진다. 애플리케이션이 [=has a new tab button|new tab button을 가지지=] 않으면, 사용자 에이전트는 최종 사용자에게 "new tab" affordance를 제공해서는 안 된다(SHOULD NOT).
최종 사용자가 new tab button을 활성화하면, 다음 단계들이 실행된다:
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process the `tab_strip` member하려면, [=processing a manifest=]의 extension point 중에 다음을 실행한다:
[=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process the `home_tab` member하려면, 다음을 실행한다:
[=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map|, [=URL=] |manifest URL:URL| 및 [=URL=] |start URL:URL|가 주어졌을 때 process the `new_tab_button` member하려면, 다음을 실행한다:
[=ordered map=] |json home tab:ordered map|, [=ordered map=] |manifest home tab:ordered map| 및 [=URL=] |manifest URL:URL|가 주어졌을 때 process the `scope_patterns` member하려면, 다음을 실행한다:
{
"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 mode가 지원되지 않을 경우 단일-document standalone
창으로 fallback하는 tabbed 웹 앱이다. 메인 index 페이지
(/ 또는 /index.html)로의 모든 탐색은
[=home tab context=]에서 열린다. new tab button은 /create에서
새 tab을 연다.
[=tab_strip/home_tab/scope_patterns=]에 대해 매칭할 때는 URL의
[=URL/query=] 부분이 기본적으로 무시된다(따라서
/index.html?utm_source=foo로의 탐색은 home tab에서 열린다).
그러나 [=start URL=]에 대해 매칭할 때는 [=URL/query=]가 정확히
일치해야 하므로, query를 무시하려는 사이트는 [=start URL=]의
[=URL/path=]를 scope pattern으로 명시적으로 포함하는 것이 권장된다.
`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's=] protocol_handlers 멤버는 웹 애플리케이션이 URL
protocols를 처리할 수 있게 하는 protocol handler description들의
배열이다.
설치 시, 사용자 에이전트는 다음과 일관된 상호작용을 통해 운영체제에 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).
[[HTML]]의 {{NavigatorContentUtils/registerProtocolHandler()}}는 웹
사이트가 특정 protocols에 대한 가능한 handler로 자신을 등록할 수
있게 한다. protocol handler description의 유효한
[=protocol handler
description/protocol=] 및 [=protocol handler description/url=] 값이
무엇인지는 해당 API에서 정의된다. 또한 [[HTML]] API는 여기서 사용하는
[=protocol handler description/protocol=] 대신 scheme을
사용하지만, 동일한 제한이 적용된다는 점에 유의한다.
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's=] file_handlers 멤버는 앱 자체 외부에서 발생하는
file-opening actions를 앱이 어떻게 처리하는지에 대한 지침을 제공하는
[=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's=] related_applications 멤버는 related
applications를 나열하며, 웹 애플리케이션과 related applications
사이의 그러한 관계를 나타내는 표시로 사용된다. 이 관계는 단방향이며,
나열된 애플리케이션이 같은 관계를 주장하지 않는 한, user agent는
양방향 endorsement를 가정해서는 안 된다(MUST NOT).
`related_applications` 사용 예로는, 그 정보를 사용하여 웹 애플리케이션에 대한 더 많은 정보를 수집하는 crawler나, 사용자가 웹 애플리케이션을 설치하려 할 때 나열된 애플리케이션을 대안으로 제안할 수 있는 browser가 있을 수 있다.
[=ordered map=] |json:ordered map| 및 [=ordered map=] |manifest:ordered map|가 주어졌을 때 process the `related_applications` member하려면:
[=manifest's=] `prefer_related_applications` 멤버는
related applications가 웹 애플리케이션보다 선호되어야 함을 사용자
에이전트에 알려주는 hint로 사용되는 [=boolean=]이다.
`prefer_related_applications` 멤버가 `true`로 설정되어 있고, 사용자
에이전트가 웹 애플리케이션 설치를 제안하려는 경우, 사용자 에이전트는
대신 related applications 중 하나의 설치를 제안하려 할 수 있다.
[=manifest's=] 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's=] fingerprints 멤버는
[=fingerprints=]의 [=list=]를 나타낸다.
fingerprint는 애플리케이션 검증에 사용되는 cryptographic fingerprints의 집합을 나타낸다. fingerprint는 type 및 value라는 두 멤버를 가진다. 이들은 각각 string이지만, 그 syntax 및 semantics는 platform-defined이다.
설치 과정을 트리거할 수 있는 여러 방법이 있다:
어떤 경우든, 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" 이벤트를 처리한다.