Using Web Share Target API in File Converter PWA

Creating an entirely new, easier way to choose files

Martin Minchev
3 min readJan 12, 2021

The Web Share Target API, part of Chromium’s Project Fugu to expand the web capabilities, has opened a new entry point for returning visitors of my file converter PWA: MConverter. Instead of having to first open the PWA and then choose files through the boring file picker, users can directly share a file for converting from another app, such as a file manager. See the demo (or try it yourself):

Once installed (from Add to home screen), the PWA shows up as a native app

Increased productivity and more returning visitors

Being able to convert files from any app is much more convenient and it feels more native. Users are also exposed to the PWA from another place in addition to the home screen: the share sheet. This has led to more returning visitors, with nearly a quarter of all daily conversions getting initiated through the share menu, thanks to the Share Target API!

How to implement it?

Adding support is relatively straightforward by following this article on web.dev. In essence, you need to announce support for receiving shares in your PWA’s manifest.json:

{
"name": "MConverter",
... "share_target": {
"action": "/?homescreen=1&share-target=1",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"files": [
{
"name": "file",
"accept": ["image/png", ".png"]
}
]
}
}
}

Note! In contrast to the <input type="file">’s accept attribute, here it is very important to include both the MIME type and the file extension. Otherwise, by adding only a file extension, you may run into a nasty issue on Android Chrome where the PWA appears in the share sheet, but it sometimes cannot receive the shared file. Instead, the service worker’s event.request.formData() throws the following error: Uncaught (in promise) TypeError: Failed to fetch.

Next, your service worker needs to process the shared file. In the fetch event handler, add the following snippet:

//service-worker.js:self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
if (event.request.method === 'POST' && url.pathname === '/' && url.searchParams.has('share-target')) {
event.respondWith(Response.redirect('/?receiving-file-share=1'));
event.waitUntil(async function () {
const client = await self.clients.get(event.resultingClientId);
const data = await event.request.formData();
const files = data.get('file');
client.postMessage({ files });
}());
return;
}
...});

The shared file will be made accessible via postMessage() to your website’s “regular” JavaScript code, where you can intercept and handle it the same way as a file from <input type="file">:

//script in index.html:navigator.serviceWorker.addEventListener('message', function (e) {
if (searchParams.has('receiving-file-share')) {
console.log(e.data.files); //contains the file(s)
}
});

But can you share multiple files at once?

Yes! With this little tweak I found from a helpful answer by Jeff Posnick, who is part of Google’s DevRel team, we can process many files from a single share. How convenient!

const files = data.getAll('file');

This will return all files in an array.

Up next: “Open With…” menu integration

Having quicker access to the converter PWA from other apps on Android is great, but what about desktop platforms?

The File Handling API is also part of Chrome’s Project Fugu to bring more capabilities to the web. It will allow an installed PWA to register as a potential handler for a file type.

The “Open with” menu on Windows

In other words, the PWA will appear in the “Open With” menu of file managers on Windows, Mac, Linux and Chrome OS.

Even though it is currently only under a flag, MConverter already has a (mostly complete) implementation for it. So, I am just waiting for the File Handling origin trial to begin, in order to make the functionality available without needing to manually flip the switch in chrome://flags.

— — — — — — — — — — — —

The MConverter PWA shown in Android’s share sheet

--

--