Receiving shared data with the Web Share Target API

November 21, 2019 0 Comments

Receiving shared data with the Web Share Target API

 

 

Sharing on mobile made simple with the Web Share Target API

On a mobile device, sharing should be as simple as clicking the Share button,
choosing an app, and choosing who to share with. For example, you may want to
share an interesting article, either by emailing it to friends or tweeting it to
the world.

In the past, only native apps could register with the operating system to receive shares from other installed apps. But with the Web Share Target API, installed web apps can register with the underlying operating system as a share target to receive shared content. Support for text and data was added in Chrome 71, and support for files was added in Chrome 76.

Android phone with the 'Share via' drawer open.
System-level share target picker with an installed PWA as an option.
  1. Using Chrome 76 or later (Android only), open the Web Share Target demo.
  2. When prompted, click Install to add the app to your home screen, or use the Chrome menu to add it to your home screen.
  3. Open any app that supports native sharing, or use the Share button in the demo app.
  4. From the target picker, choose Web Share Test.

After sharing, you should see all of the shared information in the web share target web app.

To register your app as a share target, it needs to meet Chrome's installability criteria. In addition, before a user can share to your app, they must add it to their home screen. This prevents sites from randomly adding themselves to the user's share intent chooser and ensures that sharing is something that users want to do with your app.

To register your app as a share target, add a share_target entry to its web app manifest. This tells the operating system to include your app as an option in the intent chooser. What you add to the manifest controls the data that your app will accept. There are three common scenarios for the share_target entry:


  • Accepting basic information

  • Accepting application changes

  • Accepting files

If your target app is merely accepting basic information such as data, links,
and text, add the following to the manifest.json file:

"share_target": {
"action": "/share-target/",
"method": "GET",
"params": {
"title": "title",
"text": "text",
"url": "url"
}
}

If your application already has a share URL scheme, you can replace the param values with your existing query parameters. For example, if your share URL scheme uses body instead of text, you could replace "text": "text" with "text": "body".

The method value defaults to "GET" if not provided. The enctype field, not shown in this example, indicates the type of encoding for the data. For the "GET" method, enctype defaults to "application/x-www-form-urlencoded" and is ignored if it's set to anything else.

Accepting application changes #

If the shared data changes the target app in some way—for example, saving a bookmark in the target application—set the method value to "POST" and include the enctype field. The example below creates a bookmark in the target app, so it uses "POST" for the method and "multipart/form-data" for the enctype:

{
"name": "Bookmark",
"share_target": {
"action": "/bookmark",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"url": "link"
}
}
}

Accepting files #

As with application changes, accepting files requires that method be "POST" and that enctype be present. Additionally, enctype must be "multipart/form-data", and a files entry must be added.

You must also add a files array defining the types of files your app accepts. The array elements are entries with two members: a name field and an accept field. The accept field takes a MIME type, a file extension, or an array containing both.

{
"name": "Aggregator",
"share_target": {
"action": "/cgi-bin/aggregate",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"title": "name",
"text": "description",
"url": "link",
"files": [
{
"name": "records",
"accept": ["text/csv", ".csv"]
},
{
"name": "graphs",
"accept": "image/svg+xml"
}
]
}
}
}

Handle the incoming content #

How you deal with the incoming shared data is up to you and depends on your app. For example:


  • An email client could draft a new email using title as the subject of an
    email, with text and url concatenated together as the body.

  • A social networking app could draft a new post ignoring title, using
    text as the body of the message, and adding url as a link. If text is
    missing, the app might use url in the body as well. If url is missing,
    the app might scan text looking for a URL and add that as a link.

  • A photo sharing app could create a new slideshow using title as the
    slideshow title, text as a description, and files as the slideshow images.

  • A text messaging app could draft a new message using text and url
    concatenated together and dropping title.

If the user selects your application, and your method is "GET" (the
default), the browser opens a new window at the action URL. The browser then
generates a query string using the URL-encoded values supplied in the manifest.
For example, if the sharing app provides title and text, the query string is
?title=hello&text=world. To process this, use a DOMContentLoaded event
listener in your foreground page and parse the query string:

window.addEventListener('DOMContentLoaded', () => {
const parsedUrl = new URL(window.location);

console.log('Title shared: ' + parsedUrl.searchParams.get('title'));
console.log('Text shared: ' + parsedUrl.searchParams.get('text'));
console.log('URL shared: ' + parsedUrl.searchParams.get('url'));
});

Be sure to use a service worker to precache the action page so that it will load quickly and work reliably, even if the user is offline.

If your method is "POST", as it would be if your target app accepts a saved bookmark or shared files, then the body of the incoming POST request contains the data passed by the sharing application, encoded using the enctype value provided in the manifest.

The foreground page cannot process this data directly. Since the page sees the data as a request, the page passes it to the service worker, where you can intercept it with a fetch event listener. From here, you can pass the data back to the foreground page using postMessage() or pass it on to the server:

self.addEventListener('fetch', event => {
if (event.request.method !== 'POST') {
event.respondWith(fetch(event.request));
return;
}

event.respondWith((async () => {
const formData = await event.request.formData();
const link = formData.get('link') || '';
const responseUrl = await saveBookmark(link);
return Response.redirect(responseUrl, 303);
})());
});

Verifying shared content #

An Android phone displaying the demo app with shared content.
The sample sharing target app.

Be sure to verify incoming data. Unfortunately, there is no guarantee that other apps will share the appropriate content in the right parameter.

For example, on Android, the url field will be
empty
because
it's not supported in Android's share system. Instead, URLs will often appear in
the text field, or occasionally in the title field.

Last updated: Improve article


Tag cloud