OLD | NEW |
---|---|
1 # Ballista Share Interface | 1 # Web Share Interface |
2 | 2 |
3 **Date**: 2016-04-29 | 3 **Date**: 2016-05-30 |
4 | 4 |
5 This document is a rough spec (i.e., *not* a formal web standard draft) of the | 5 This document is a rough spec (i.e., *not* a formal web standard draft) of the |
6 Ballista one-directional API. To avoid complexity, we avoid discussing the | 6 Web Share API. The basic Share API just sends share requests (with no capability |
7 bidirectional parts of the Ballista project here. | 7 for a website to receive share requests; only native system services can |
benwells
2016/06/01 00:48:33
I think the statement 'only native system services
Matt Giuca
2016/06/01 01:01:13
Done.
| |
8 receive). For a follow-up plan to have websites receive share requests from the | |
9 system, or other websites, see the [Share Target | |
10 API](interface_share_target.md). | |
8 | 11 |
9 Examples of using the one-directional API for sharing can be seen in the | 12 Examples of using the Share API for sharing can be seen in the |
10 [explainer document](explainer.md). | 13 [explainer document](explainer.md). |
benwells
2016/06/01 00:48:33
Can we move these into this document? This API pro
Matt Giuca
2016/06/01 01:01:13
Are you saying the explainer and interface doc sho
benwells
2016/06/01 01:28:11
I mean that this needs to end up in a repository j
Matt Giuca
2016/06/01 01:31:57
Oh OK, gotcha. Yes, that refactoring is the subjec
benwells
2016/06/01 01:47:53
Acknowledged.
| |
11 | 14 |
12 ## Requester API | 15 **Note**: The Web Share API is the first concrete proposal of the [Ballista |
16 project](../README.md), which aims to explore website-to-website and | |
17 website-to-native interoperability. | |
13 | 18 |
14 The `navigator.actions` interface (available from both foreground pages and | 19 ## navigator.share |
15 workers) is where our API surface lives. | 20 |
21 The `navigator.share` function (available from both foreground pages and | |
22 workers) is the main method of the interface: | |
16 | 23 |
17 ```WebIDL | 24 ```WebIDL |
18 partial interface Navigator { | 25 partial interface Navigator { |
19 readonly attribute Actions actions; | 26 Promise<void> share(ShareData data); |
20 }; | 27 }; |
21 | 28 |
22 partial interface WorkerNavigator { | 29 partial interface WorkerNavigator { |
23 readonly attribute Actions actions; | 30 Promise<void> share(ShareData data); |
31 }; | |
32 | |
33 dictionary ShareData { | |
34 DOMString? title; | |
35 DOMString? text; | |
36 DOMString? url; | |
24 }; | 37 }; |
25 ``` | 38 ``` |
26 | 39 |
27 ### performAction | 40 The `share` method takes one argument: the object that will be delivered to the |
41 handler. It contains the data being shared between applications. | |
28 | 42 |
29 The `navigator.actions` interface provides the `performAction` method which | 43 The `data` object may have any of (and should have at least one of) the |
30 initiates a request. | 44 following optional fields: |
45 | |
46 * `title` (string): The title of the document being shared. May be ignored by | |
47 the handler. | |
48 * `text` (string): Arbitrary text that forms the body of the message being | |
49 shared. | |
50 * `url` (string): A URL or URI referring to a resource being shared. | |
51 | |
52 We may later expand this to allow image data or file blobs. | |
benwells
2016/06/01 00:48:33
Should this be a TODO, or at least more definite (
Matt Giuca
2016/06/01 01:01:12
Done.
| |
53 | |
54 `share` always shows some form of UI, to give the user a choice of application | |
55 and get their approval to invoke and send data to a potentially native | |
56 application (which carries a security risk). UX mocks are shown | |
57 [here](user_flow.md). | |
benwells
2016/06/01 00:48:33
Again, these should be moved into this document to
Matt Giuca
2016/06/01 01:01:12
The user_flow mocks are being moved (in the follow
| |
58 | |
59 `share`'s promise is resolved if the user chooses a target application, | |
60 and that application accepts the data without error. The promise may be rejected | |
61 in the following cases (it is possible to distinguish between these four failure | |
62 modes, but not learn the identity of the chosen application): | |
63 | |
64 * The share was invalid (e.g., inappropriate fields in the `data` parameter). | |
65 * There were no apps available to handle sharing. | |
66 * The user cancelled the picker dialog instead of picking an app. | |
67 * The data could not be delivered to the target app (e.g., the chosen app could | |
68 not be launched), or the target app explicitly rejected the share event. | |
69 | |
70 ## navigator.canShare | |
71 | |
72 `navigator` also provides a method for determining whether there are any | |
73 applications that can handle sharing: | |
31 | 74 |
32 ```WebIDL | 75 ```WebIDL |
33 interface Actions { | 76 partial interface Navigator { |
34 Promise<Action> performAction((ActionOptions or DOMString) options, | 77 boolean canShare(); |
35 object data); | |
36 }; | |
37 | |
38 dictionary ActionOptions { | |
39 DOMString verb; | |
40 }; | |
41 | |
42 dictionary Action {}; | |
43 ``` | |
44 | |
45 The `performAction` method takes two arguments: | |
46 * `options` provides metadata about the action which is used by the user agent | |
47 to decide how to behave (what apps to show, how the UI is presented, whether | |
48 to expect a response, etc). Currently just has `verb` (the only non-optional | |
49 field) but we will expand this with more options in the future. If this is a | |
50 string `x`, that is short-hand for `{verb: x}`. | |
51 * `data` is the object that will be delivered to the handler. It contains the | |
52 data being shared between applications. Its fields depend on the verb (see | |
53 below for details on the `share` verb). | |
54 | |
55 `performAction` always shows some form of UI, to give the user a choice of | |
56 application and get their approval to invoke and send data to a potentially | |
57 native application (which carries a security risk). UX mocks are shown | |
58 [here](user_flow.md). | |
59 | |
60 `performAction` returns (asynchronously, via a promise) an `Action` object. This | |
61 object currently contains no fields, but we will extend it later. It is not | |
62 possible for the requester to learn the identity of the chosen application. | |
63 | |
64 `performAction`'s promise may be rejected in the following cases (it is possible | |
65 to distinguish between these four failure modes, but again, not learn the | |
66 identity of the chosen application): | |
67 | |
68 * The action was invalid (e.g., an unknown verb or inappropriate fields for the | |
69 given verb). | |
70 * There were no apps available to handle that specific action. | |
71 * The user cancelled the action instead of picking an app. | |
72 * The data could not be delivered to the target app (e.g., service worker could | |
73 not start, had no event handler, or the chosen native app could not be | |
74 launched), or the target app explicitly rejected the action. | |
75 | |
76 ### canPerformAction | |
77 | |
78 `navigator.actions` also provides a method for determining whether there are any | |
79 applications that can handle a particular action: | |
80 | |
81 ```WebIDL | |
82 partial interface Actions { | |
83 boolean canPerformAction((ActionOptions or DOMString) options); | |
84 }; | 78 }; |
85 ``` | 79 ``` |
86 | 80 |
87 Returns `true` if there are one or more applications that could handle the | 81 Returns `true` if there are one or more applications that could handle a share |
88 action described by `options` (i.e., if `options` was passed to `performAction`, | 82 event (i.e., if `share` was called, would any applications be presented to the |
89 would any applications be presented to the user?). May give false positives, but | 83 user?). May give false positives, but not false negatives (on some systems, it |
90 not false negatives (on some systems, it may not be possible to determine in | 84 may not be possible to determine in advance whether any native applications |
91 advance whether any native applications support the action, in which case | 85 support sharing, in which case `canShare` should return `true`; `false` means |
92 `canPerformAction` should return `true`; `false` means that `performAction` will | 86 that `share` will definitely fail). This can be used by websites to hide or |
93 definitely fail). This can be used by websites to hide or disable the sharing | 87 disable the sharing UI, to avoid presenting a button that just fails when users |
94 UI, to avoid presenting a button that just fails when users press it. | 88 press it. |
95 | 89 |
96 **TODO(mgiuca)**: This may have to be asynchronous, so that the implementation | 90 **TODO(mgiuca)**: This may have to be asynchronous, so that the implementation |
97 can query the file system without blocking. | 91 can query the file system without blocking. |
98 | 92 |
99 **For consideration**: `canPerformAction` may present a fingerprinting issue, by | 93 ## Share handlers |
100 providing several bits of entropy about the identity of the device. (For | |
101 example, an attacker may passively run `canPerformAction` on all available verbs | |
102 with many different options sets, and the set of resulting bits will in some way | |
103 reflect the set of web and native applications registered/installed on the | |
104 device.) I suspect this entropy is minimal as most devices of a given operating | |
105 system would have a similar set of capabilities, but it may allow identification | |
106 of, e.g., users with native editors of obscure MIME types. Further analysis is | |
107 warranted. | |
108 | 94 |
109 ### Verbs | 95 The list of share targets or handlers can be populated from a variety of |
96 sources, depending on the user agent and underlying OS: | |
110 | 97 |
111 The *verb* is a string that determines what handlers are available (handlers | 98 * Built-in service (e.g., "copy to clipboard"). |
112 explicitly register for certain verbs), as well as what fields are expected in | 99 * Native applications. |
113 the `options` and `data` objects, and how the interaction will take place (e.g., | 100 * Web applications registered using the [Web Share Target |
114 whether it will be one-way or bidirectional). Each verb is its own | 101 API](interface_share_target.md). |
115 mini-protocol. | |
116 | 102 |
117 To avoid a) proliferation of overly specialized verbs, and b) mismatched | 103 The user agent can support any or all of the above (for example, on some |
118 expectations about what a particular verb means, we will limit the set of verbs | 104 platforms, there is no system for native apps to receive share data; some user |
119 to those defined in the standard. We will leave the set of verbs open for new | 105 agents may not support the Share Target API). |
120 additions in the future, but not allow individual handlers or requesters to | |
121 invent their own verbs ad-hoc. User agents are expected to reject actions with | |
122 unexpected verbs, and enforce that the correct options and data are supplied for | |
123 the given verb. | |
124 | 106 |
125 In this document, we define only a single verb, `"share"`, but we expect several | 107 The user agent may either present its own picker UI and then forward the share |
126 other verbs to be defined in the initial standard. | 108 data to the chosen app, or simply forward the share data to the system's native |
109 app picking system (e.g., Android, iOS and Windows 10 all [support this concept | |
110 natively](native.md)) and let the OS do the work. | |
127 | 111 |
128 ### Built-in and native app handlers (web-to-native) | 112 When forwarding to a website using the Share Target API, the `ShareData` object |
129 | 113 is simply cloned. When forwarding to a native app, the user agent should do its |
130 The user agent may choose to provide handlers that do not correspond to | 114 best to map the fields onto the equivalent concepts. For example, on Android, |
131 registered web applications. When the user selects these "fake" handlers, the | 115 when a share is sent to a native application, the user agent may create an |
132 user agent itself performs the duties of the handler. This can include: | |
133 | |
134 * Providing a built-in service (such as "copy to clipboard"). | |
135 * Forwarding the action to the native app picking system (e.g., [Android | |
136 intents](http://developer.android.com/training/sharing/send.html), [iOS share | |
137 sheets](https://developer.apple.com/library/ios/documentation/UIKit/Reference/ UIActivityViewController_Class/index.html), | |
138 [Windows Share contracts](https://msdn.microsoft.com/en-us/windows/uwp/app-to- app/share-data)). | |
139 * Forwarding the action directy on to a native system application. | |
140 | |
141 In any case, the user agent is responsible for marshalling data to/from the | |
142 required formats and generally ensuring that the built-in or native handler | |
143 behaves like a web handler. | |
144 | |
145 ## Handler API | |
146 | |
147 Handlers **must** have a registered [service | |
148 worker](https://www.w3.org/TR/service-workers/) and a [web app | |
149 manifest](https://www.w3.org/TR/appmanifest/). | |
150 | |
151 ### App manifest | |
152 | |
153 The first thing a handler needs to do is declare its action handling | |
154 capabilities in the app manifest: | |
155 | |
156 ```WebIDL | |
157 partial dictionary Manifest { | |
158 ManifestAction[]? actions; | |
159 }; | |
160 | |
161 dictionary ManifestAction { | |
162 DOMString verb; | |
163 }; | |
164 ``` | |
165 | |
166 The `"actions"` member of the manifest contains a list of objects, one per verb | |
167 the application can handle. For the share verb, there is no additional metadata | |
168 required, so the following is sufficient: | |
169 | |
170 ```JSON | |
171 "actions": [ | |
172 { | |
173 "verb": "share" | |
174 } | |
175 ] | |
176 ``` | |
177 | |
178 For more complex verbs, other metadata may be provided, such as which MIME types | |
179 will be accepted. | |
180 | |
181 The declarative nature of the manifest allows web applications to be indexed by | |
182 their action handling capabilities, allowing search services that, say, find all | |
183 web applications that handle "share" actions. | |
184 | |
185 Handlers declaring actions in their manifest will **not** be automatically | |
186 registered; the user must explicitly authorize the registration. How this takes | |
187 place is still under consideration (see [User | |
188 Flow](user_flow.md#registering-a-website-as-a-handler-on-mobile), but will | |
189 ultimately be at the discretion of the user agent (the user may be automatically | |
190 prompted, or may have to explicitly request registration). | |
191 | |
192 **For consideration**: We may wish to provide a method for websites to | |
193 explicitly request to prompt the user for handler registration. This would | |
194 *only* allow sites to register for verbs they have declared in the manifest. For | |
195 now, we have omitted such a method from the design to keep control in the hands | |
196 of user agents. It is easier to add such a method later than remove it. | |
197 | |
198 ### Event handlers | |
199 | |
200 When the user picks a registered web app as the target of an action, the | |
201 handler's service worker starts up (if it is not already running), and a | |
202 `"handle"` event is fired at the `navigator.actions` object. | |
203 | |
204 ```WebIDL | |
205 partial interface Actions { | |
206 attribute EventHandler onhandle; | |
207 }; | |
208 Actions implements EventTarget; | |
209 | |
210 interface HandleEvent : ExtendableEvent { | |
211 readonly attribute ActionOptions options; | |
212 readonly attribute object data; | |
213 | |
214 void reject(DOMException error); | |
215 }; | |
216 ``` | |
217 | |
218 The `onhandle` handler (with corresponding event type `"handle"`) takes a | |
219 `HandleEvent`. The `options` and `data` fields are clones of the `options` and | |
220 `data` parameters passed to the `performAction` method by the requester. | |
221 | |
222 If the `reject` method is called, the action fails and the requester's promise | |
223 is rejected. This must be called within the lifetime of the event (either in the | |
224 event handler, or in the promise passed to the event's | |
225 [`waitUntil`](https://www.w3.org/TR/service-workers/#wait-until-method) method). | |
226 The action also fails if the promise passed to `waitUntil` is rejected. Once the | |
227 event completes without failing, the action automatically succeeds, and the | |
228 requester's promise is resolved. | |
229 | |
230 For one-way actions (like `"share"`), the end of the event's lifetime marks the | |
231 end of the action, and there is no further communication in either direction. | |
232 | |
233 The handler-side API is defined entirely within the service worker. If the | |
234 handler needs to provide UI (which should be the common case), the service | |
235 worker must create a foreground page and send the appropriate data between the | |
236 worker and foreground page, out of band. The `handle` event handler is [allowed | |
237 to show a | |
238 popup](https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-show-a-po pup), | |
239 which means it can call the | |
240 [`clients.openWindow`](https://www.w3.org/TR/service-workers/#clients-openwindow -method) | |
241 method. | |
242 | |
243 ### System-generated actions (native-to-web) | |
244 | |
245 Actions do not need to come from web requesters. The user agent may trigger an | |
246 action from some external stimulus, such as the user opening a file, or choosing | |
247 a web app as the target of a system intent. As in the web-to-native case, the | |
248 user agent is responsible for simulating the requester side of the connection | |
249 and marshalling data into the correct format. | |
250 | |
251 For example, the user agent may register web handlers into the operating | |
252 system's native application pickers. When the user picks a web handler, the user | |
253 agent creates an `options` and `data` object and invokes the web handler, as if | |
254 it had been triggered by a web requester. | |
255 | |
256 ## The "share" verb | |
257 | |
258 When an action is sent using the `"share"` verb, the following extra rules | |
259 apply: | |
260 | |
261 * It must be a one-way action (no response after the initial promise completes). | |
262 * No additional `options` are recognised. | |
263 * The `data` object may have any of (and should have at least one of) the | |
264 following optional fields: | |
265 * `title` (string): The title of the document being shared. May be ignored by | |
266 the handler. | |
267 * `text` (string): Arbitrary text that forms the body of the message being | |
268 shared. | |
269 * `url` (string): A URL or URI referring to a resource being shared. | |
270 | |
271 We may later expand this to allow image data or file blobs. | |
272 | |
273 How the handler deals with the data object is at the handler's discretion, and | |
274 will generally depend on the type of app. Here are some suggestions: | |
275 | |
276 * An email client might draft a new email, using `title` as the subject of an | |
277 email, with `text` and `url` concatenated together as the body. | |
278 * A social networking app might draft a new post, ignoring `title`, using `text` | |
279 as the body of the message and adding `url` as a link. If `text` is missing, | |
280 it might use `url` in the body as well. If `url` is missing, it might scan | |
281 `text` looking for a URL and add that as a link. | |
282 * A text messaging app might draft a new message, ignoring `title` and using | |
283 `text` and `url` concatenated together. It might truncate the text or replace | |
284 `url` with a short link to fit into the message size. | |
285 | |
286 When a user agent is acting as a requester or handler on behalf of a native | |
287 system application, it must understand the above requirements and convert | |
288 to/from the appropriate system data structures. For example, on Android, when a | |
289 web requester is used to send a system intent to a native application, the user | |
290 agent may create an | |
291 [Intent](http://developer.android.com/reference/android/content/Intent.html) | 116 [Intent](http://developer.android.com/reference/android/content/Intent.html) |
292 object with `ACTION_SEND`, setting the `EXTRA_SUBJECT` to `title`. Since Android | 117 object with `ACTION_SEND`, setting the `EXTRA_SUBJECT` to `title`. Since Android |
293 intents do not have a URL field, `EXTRA_TEXT` would be set to `text` and `url` | 118 intents do not have a URL field, `EXTRA_TEXT` would be set to `text` and `url` |
294 concatenated together. | 119 concatenated together. |
OLD | NEW |