이 명세는 웹 애플리케이션이 이미 열려 있는 앱 인스턴스와 관련하여 앱 실행의 동작을 구성할 수 있게 하는 API를 정의한다. 이 API는 음악 플레이어와 같은 단일 인스턴스 웹 앱의 요구를 충족하는 것을 목표로 한다.
이 API를 구현하려면, 사용자 에이전트는 [[[appmanifest]]]를 지원해야 한다.
음악 플레이어 앱은 음악 재생을 중단하지 않고 앱 바로 가기 실행을 기존 창으로 전달하려고 한다. 이 음악 앱은 다음과 같이 [[[appmanifest]]]에 [=manifest/launch_handler=] 항목을 추가한다:
{
"name": "Music Player",
"shortcuts": [{
"name": "Now Playing",
"url": "/"
}, {
"name": "Library",
"url": "/library"
}, {
"name": "Favorites",
"url": "/favorites"
}, {
"name": "Discover",
"url": "/discover"
}],
"launch_handler": {
"client_mode": "focus-existing"
}
}
[=manifest/client_mode=] 매개변수를 [=client mode/focus-existing=]로 설정하면, 앱 실행 시 기존 앱 인스턴스가 있는 경우 해당 인스턴스를 현재 문서에서 벗어나도록 탐색시키지 않고 포커스로 가져온다.
{{LaunchParams}}가 {{Window/launchQueue}}에 큐에 추가되며, 음악 플레이어는 {{LaunchConsumer}}에서 {{LaunchParams/targetURL}}을 읽고 스크립트에서 이를 처리할 수 있다. 예:
window.launchQueue.setConsumer((launchParams) => {
const url = launchParams.targetURL;
// URL이 앱 섹션 중 하나를 가리키면, 현재 재생 중인 음악을
// 중단하지 않고 앱 뷰를 해당 섹션으로 갱신한다.
if (maybeFocusAppSection(url)) {
return;
}
// 실행을 제자리에서 처리할 수 없으므로, 페이지를 탐색한다
// (재생 중인 음악이 중단된다).
location.href = url;
});
이미 음악 플레이어 앱에서 음악을 듣고 있는 사용자가 "Library" 앱 바로 가기를 활성화하면, /library로의 앱 실행이 트리거되고 이것이 기존 앱 인스턴스로 라우팅되어 페이지의 {{Window/launchQueue}}에 큐에 추가되며, 할당된 {{LaunchConsumer}}를 통해 현재 음악 재생에 영향을 주지 않고 음악 플레이어의 라이브러리 섹션을 포커스로 가져온다.
다음 단계들이 확장 지점, 즉 manifest 처리 단계에 추가된다:
`launch_handler`는 웹 앱 실행이 어떻게 동작해야 하는지에 대한 구성을 담는 dictionary이다.
[=manifest/launch_handler=]는 [=manifest/client_mode=]가 유일한 멤버임에도 dictionary이다. 이는 향후 다른 유형의 동작이 필요해질 경우 더 많은 멤버를 추가할 여지를 두기 위한 것이다.
[=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|이 주어졌을 때 processing the launch_handler member 단계는 다음과 같다:
[=manifest/launch_handler=]의 `client_mode` 멤버는 하나 이상의 [=client mode targets=]를 지정하는 [=string=] 또는 [=strings=]의 리스트이다. [=client mode target=]은 웹 앱 실행에 사용할 특정 클라이언트 선택 및 탐색 동작을 선언한다.
사용자 에이전트는 플랫폼의 제약(예: 모바일 기기가 여러 앱 인스턴스를 동시에 지원하지 않을 수 있음)에 따라 [=client mode targets=]의 일부만 지원할 수 있다.
client mode targets는 다음과 같다:
사용자 에이전트는 플랫폼에 가장 적합한 방식을 결정할 것으로 기대된다. 예를 들어, 단일 앱 인스턴스만 지원하는 모바일 기기에서는 사용자 에이전트가 `navigate-existing`을 사용할 수 있고, 여러 창을 지원하는 데스크톱 기기에서는 데이터 손실을 피하기 위해 `navigate-new`를 사용할 수 있다.
페이지가 실행의 {{LaunchParams}}를 수신하고 이를 처리하려면 {{Window/launchQueue}}에 {{LaunchConsumer}}가 설정되어 있어야 한다. 페이지가 아무 동작도 취하지 않으면 실행의 사용자 경험은 깨진 것처럼 보일 가능성이 높다.
[=ordered map=] |json_launch_handler:ordered map|, [=ordered map=] |manifest_launch_handler:ordered map|이 주어졌을 때 process the `client_mode` member하려면, 다음을 실행한다:
`client_mode`는 사이트가 선호하는 [=client mode target=]이 사용자 에이전트나 플랫폼에 의해 지원되지 않는 경우 사용할 대체 [=client mode targets=]를 지정할 수 있도록 문자열 리스트를 허용한다. 리스트에서 처음으로 지원되는 [=client mode target=] 항목이 사용된다.
이 명세는 [=manifest/launch_handler=]의 동작을 포함하도록 기존의 [=launch a web application=] 알고리즘을 [=launch a web application with handling=] 단계로 대체한다.
launch a web application with handling 단계는 다음 알고리즘으로 주어진다. 이 알고리즘은 [=Document/processed manifest=] |manifest:processed manifest|, 선택적 [=URL=] 또는 {{LaunchParams}} |params|, 선택적 [=POST resource=] |POST resource|를 취하고 [=application context=]를 반환한다.
|application context|는 [=assigned launch consumer=]가 있는 기존 인스턴스일 수 있으므로, 새로 추가된 {{LaunchParams}}를 처리할 필요가 있다.
prepare an application context 단계는 다음 알고리즘으로 주어진다. 이 알고리즘은 [=Document/processed manifest=] |manifest:processed manifest|, {{LaunchParams}} |launch params|, 선택적 [=POST resource=] |POST resource|를 취하고 [=application context=]를 반환한다.
|client mode|에 대해 switch하여 다음 하위 단계를 실행한다:
적절한 선택 전략은 가장 최근에 포커스된 것을 선택하는 것일 수 있다.
{{LaunchQueue}} |queue|가 주어졌을 때 process unconsumed launch params 단계는 다음과 같다:
[Exposed=Window] interface LaunchParams {
readonly attribute DOMString? targetURL;
readonly attribute FrozenArray<FileSystemHandle> files;
};
{{LaunchParams/targetURL}}는 애플리케이션의 [=manifest/within scope=]여야 하는 실행의 [=URL=]을 나타낸다.
{{LaunchParams/files}}의 모든 |file handle:FileSystemHandle|에 대해, {{FileSystemPermissionDescriptor/mode}}를 {{FileSystemPermissionMode/"readwrite"}}로 설정하여 파일 시스템 권한을 질의하면 {{PermissionState/"granted"}}를 반환해야 한다.
callback LaunchConsumer = any (LaunchParams params);
partial interface Window {
readonly attribute LaunchQueue launchQueue;
};
[Exposed=Window] interface LaunchQueue {
undefined setConsumer(LaunchConsumer consumer);
};
{{LaunchQueue}}는 초기에 비어 있는 {{LaunchParams}}의 [=list=]인 unconsumed launch params를 가진다.
{{LaunchQueue}}는 초기에 null인 선택적 {{LaunchConsumer}}인 assigned launch consumer를 가진다.
{{LaunchQueue/setConsumer(consumer)}} 메서드 단계는 다음과 같다:
{{LaunchParams}}는 이벤트가 아니라 {{LaunchQueue}}를 통해 document에 전달된다. 이는 launch 이벤트가 발생하는 것과 페이지 스크립트가 이벤트 리스너를 연결하는 것 사이의 race condition을 피하기 위한 것이다. 반대로 {{LaunchQueue}}는 {{LaunchConsumer}}가 설정될 때까지 큐에 추가된 모든 {{LaunchParams}}를 버퍼링한다.
이 명세에는 알려진 접근성 고려 사항이 없다.
[=manifest/client_mode=]가 [=client mode/focus-existing=]인 실행에 대해 [=launching a web application with handling=]할 때 구현은 주의를 기울여야 한다. 이러한 실행은 [=manifest/navigation scope=] 밖으로 URL을 누설해서는 안 된다. 이는 [=Document/processed manifest=] |manifest|가 주어졌을 때 양방향 모두에 적용된다: