Chromium Code Reviews| 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 |