이 명세는 웹사이트가 자신을 웹 공유 대상으로 선언하여, [[[Web-Share]]] 또는 시스템 이벤트(예: 네이티브 앱에서의 공유)로부터 공유된 콘텐츠를 받을 수 있게 하는 API를 정의한다.
이는 {{NavigatorContentUtils/registerProtocolHandler()}}와 유사한 메커니즘이다. 사용자 에이전트에 웹사이트를 등록하여, 나중에 다른 사이트나 네이티브 애플리케이션에서 사용자 에이전트를 통해(사용자의 재량에 따라) 호출될 수 있게 하기 때문이다. 차이점은 {{NavigatorContentUtils/registerProtocolHandler()}}는 프로그래밍 방식의 API로 핸들러를 등록하는 반면, Web Share Target은 [[[appmanifest]]]에 선언되어, 사용자 에이전트 또는 사용자가 선택한 시점에 등록된다는 점이다.
이것은 Web Share Target 명세의 초기 초안이다.
이 API를 구현하려면 사용자 에이전트는 [[[appmanifest]]]를 지원해야 한다. 이 명세는 [[[Web-Share]]] 명세의 일부 정의도 재사용한다. 그러나 [[[Web-Share]]] 지원은 선택 사항이다.
사이트를 공유 대상으로 등록하려면 아래와 같이 [=manifest/share_target=] 항목을 [[[appmanifest]]]에 추가한다.
{
"name": "Includinator",
"share_target": {
"action": "share.html",
"params": {
"title": "name",
"text": "description",
"url": "link"
}
}
}
[=ShareTarget/params=] 키는 [[[Web-Share]]]의 {{ShareData}}에 있는 키 이름에 대응하며, 값은 대상이 실행될 때 쿼리 매개변수로 사용될 임의의 이름이다.
공유가 발생할 때 사용자가 이 공유 대상을 선택하면, 사용자 에이전트는 HTML 폼 제출과 마찬가지로 공유된 데이터를 포함한 쿼리 매개변수 값을 붙여 `action` URL에서 새 브라우징 컨텍스트를 연다.
이 예의 목적상 매니페스트가 `https://example.org/includinator/manifest.webmanifest`에 있다고 가정한다.
<html>
<link rel="manifest" href="manifest.webmanifest">
<script>
window.addEventListener('load', () => {
const parsedUrl = new URL(window.location);
const { searchParams } = parsedUrl;
console.log("Title shared:", searchParams.get('name'));
console.log("Text shared:", searchParams.get('description'));
console.log("URL shared:", searchParams.get('link'));
});
</script>
들어오는 공유에 제목 "My News"와 URL `http://example.com/news`가 포함되어 있으면, 사용자 에이전트는 새 창 또는 탭을 열고 다음으로 이동한다.
https://example.org/includinator/share.html?name=My+News&link=http%3A%2F%2Fexample.com%2Fnews
U+0020 (SPACE) 문자는 [=`application\/x-www-form-urlencoded`=] 인코딩 사용으로 인해 예상할 수 있는 "`%20`"이 아니라 "`+`"로 인코딩된다. 처리기는 U+002B (+) 문자를 U+0020 (SPACE) 문자로 디코딩하도록 주의해야 하며, ECMAScript의 `decodeURIComponent` 함수를 포함한 일부 URL 디코딩 라이브러리는 이를 자동으로 수행하지 않을 수 있다.
쿼리 매개변수는 공유되는 {{ShareData}}의 정보로 채워진다. {{ShareData}}에 특정 멤버에 대한 정보가 없으면 해당 쿼리 매개변수는 생략된다.
공유 대상은 {{ShareData}} 멤버의 하위 집합에만 관심이 있을 수 있다. 이 예는 공유 대상이 `POST` 요청으로 데이터를 수신하는 경우도 보여주며, 요청이 즉각적인 부작용을 일으키는 경우에는 이렇게 해야 한다.
{
"name": "Bookmark",
"share_target": {
"action": "/bookmark",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"url": "link"
}
}
}
공유된 정보는 서버로 네트워크를 통해 전송되는 대신 [=service worker=]가 읽을 수 있다.
self.addEventListener("fetch", (event) => {
if (event.request.method !== "POST") {
event.respondWith(fetch(event.request));
return;
}
const formDataPromise = event.request.formData();
event.respondWith(
formDataPromise.then((formData) => {
const link = formData.get("link") || "";
saveBookmark(link);
return new Response(`Bookmark saved: ${link}`);
})
);
});
핸들러가 공유된 데이터를 처리하는 방식은 핸들러의 재량이며, 일반적으로 앱의 유형에 따라 달라진다. 다음은 몇 가지 제안이다.
[=manifest=]는 JSON이므로, 이 명세는 [[JSON]] 명세에 정의된 타입, 즉 object와 string에 의존한다.
다음 단계가 [=processing extension-point of web manifest=]에 추가된다.
매니페스트의 share_target
멤버는 [=object=]이다. 존재할 경우, 이 애플리케이션을
웹 공유 대상으로 선언하고 애플리케이션이 공유 데이터를
수신하는 방식을 설명한다.
웹 공유 대상은 [=manifest/share_target=] 멤버를 포함한 유효한 [=manifest=]를 가진 웹사이트이다.
웹 공유 대상은 공유 대상의 한 유형이다(예: 일부 시스템 애플리케이션과 같은 다른 유형도 사용할 수 있다).
[=object=] |json:JSON|과 [=ordered map=] |manifest:ordered map|이 주어졌을 때 `share_target` 멤버를 처리하려면:
ShareTarget [=object=]는 다음 멤버를 가질 수 있다.
action 멤버
method 멤버
enctype 멤버
params 멤버
ShareTargetParams [=object=]는 다음 멤버를 가질 수 있다.
title
멤버
text
멤버
url 멤버
웹 공유 대상이 어떻게 그리고 언제 "등록"되는지는 사용자 에이전트 및/또는 최종 사용자의 재량이다. 실제로 "등록"은 여기서 형식적으로 정의하지 않는 사용자 에이전트별 개념이다. 사용자 에이전트는 웹 공유 대상을 전혀 "등록"할 필요가 없다. 다만 최종 사용자가 선택한 웹 공유 대상으로 공유 데이터를 전달할 수 있는 어떤 메커니즘을 제공해야 한다. 사용자 에이전트는 웹 공유 대상이 [=installed web application|설치=]되어 있지 않더라도 이를 "등록됨"으로 간주할 수 있다.
사용자 에이전트는 사용자가 사이트를 방문할 때 모든 웹 공유 대상을 자동으로 등록할 수 있지만, 사용자가 너무 많은 대상 선택지에 압도되지 않도록 더 신중하게 적용하는 것이 권장된다.
사용자 에이전트가 사용할 수 있는 등록 전략의 예는 다음과 같다.
최종 사용자에게 웹 공유 대상 목록을 표시할 때, 사용자 에이전트는 매니페스트를 미리 색인화한 온라인 서비스를 사용할 수 있으며, 따라서 사용자가 방문하거나 명시적으로 등록한 적이 없는 대상도 사용자에게 보여줄 수 있다.
최종 사용자가 일반 애플리케이션에 보내려는 데이터를 공유하면서, 특정 웹 공유 대상을 데이터의 수신자로 지정하면 웹 공유 대상은 호출된다.
데이터가 어디에서 오는지, 또는 최종 사용자가 웹 공유 대상을 수신자로 지정하는 방식은 명시되지 않는다. 그러나 한 가능한 출처는 같은 사용자 에이전트에서 {{Navigator}}의 {{Navigator/share()}} 메서드를 호출하는 것이다.
웹 공유 대상 호출의 다른 가능한 출처 예는 다음과 같다.
웹 공유 대상이 호출될 때 데이터는 지정되지 않은 형식일 수 있다. 사용자 에이전트는 해당 데이터가 아직 {{ShareData}} 객체가 아니라면, 호스트 시스템의 동등한 개념에서 `ShareData`의 멤버로 매핑하여 먼저 {{ShareData}} 객체로 변환해야 한다. 출처가 {{Navigator/share()}} 호출이었다면, 사용자 에이전트는 {{ShareData}} 인수를 수정하지 않고 사용해야 한다(하지만 어떤 다른 형식을 거치며 손실이 발생할 수 있으므로 항상 가능하지는 않다). 사용자 에이전트는 데이터를 `ShareData` 필드에 가능한 한 잘 매핑하기 위해 휴리스틱을 사용할 수 있다.
예를 들어 호스트 공유 시스템에는 전용 URL 필드가 없지만, 일반 텍스트와 URL이 모두 "text" 필드로 전송되는 경우가 있다는 관례가 있을 수 있다. Android가 이에 해당한다. 사용자 에이전트는 "text" 필드의 전체 또는 일부가 [=valid URL string=]인지 확인하고, 그렇다면 그 부분을 {{ShareData}}의 {{ShareData/url}} 멤버로 옮길 수 있다.
[=ordered map=] |manifest|를 가진 웹 공유 대상이 {{ShareData}} |data|와 함께 호출되면 다음 단계를 실행한다.
이 알고리즘은 |manifest|에 [=process the `share_target` member=] 알고리즘이 실행되었고, 이후에도 [=manifest/share_target=]가 남아 있다고 가정한다.
이 명세에는 알려진 접근성 고려 사항이 없다.
웹 앱 상호운용성 사용 사례의 토대를 마련한 [[[WEBINTENTS]]] 팀에 감사한다. 특히 Web Share와 Web Share Target의 초기 홍보를 많이 한 Paul Kinlan에게 감사한다.
이 명세의 초기 초안을 작성하고 API 설계와 프로토타입 제작을 도운 Connie Pyromallis에게 감사한다.
이 명세의 초기 초안에 피드백을 준 Alex Russell과 David Baron에게 감사한다.