I’ve frequently said that for web apps to compete effectively in the world ofapps, they need to be integrated in to all of the places that users expect appsto be. Inter-app communication is one of the major missing pieces of the webplatform, and specifically one of the last major missing features is nativelevel sharing: Web apps need to be able to get data out of theirsilo and into other web sites and apps; they also need tobe able to receive the data from other native apps and sites.
The File Share Target API is a game-changer of an API that is now in ChromeCanary. The API extends the Web Share TargetAPIthat lets apps and sites share simple links and text to web sites by integratingthem into the systems sharing functionality.
This very static file blog utilizes the Web Share Target API so I can quicklyshare links that I find interesting to it from anyAndroid application, and as of last week I enabled the File Share Target API sothat I can upload images to my blog directly from the Camera app onAndroid. This post is all about how Idid it (and stole some code from Jake Archibald — tbf he worked out a lotof the bugs for an integration they are doing in tosquoosh.app.)
The File Share TargetAPIis a very novel API in that it is fully progressive. If your application canhandle Form POST
requests then you can integrate easily with this API. Thebasic flow is: when the user chooses your application from the native picker,Chrome will send a Form POST
request to your server, it is up to you what youdo with it (handle in a service worker or on the server).
To add support for sharing files into your web app you need to do two things:
- Declare support for sharing files via the manifest file,
- Handle the Form
POST
request in your Service Worker.
The manifest declares to the host system how Sharing should be mapped from thehost application to the web app. In the manifest below it essentially says “Whena user shares a file of type ‘image/*’ make a Form POST request to‘/share/image/’ and name the data ‘file’“.
manifest.json
{
"name": "Blog: Share Image",
"short_name": "Blog: Share Image",
"start_url": "/share/image/",
"theme_color": "#000000",
"background_color": "#000000",
"icons": [ {
"sizes": "192x192",
"src": "/images/me.png",
"type": "image/png"
}],
"share_target": {
"action": "/share/image/",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"files": [
{
"name": "file",
"accept": ["image/*"]
}
]
}
},
"display": "standalone",
"scope": "/share/"
}
Once the user shares to your web application, Chrome will make the web requestto your site with the file data as the payload.
It is recommended that you handle the POST request inside your service worker sothat 1) it is fast, 2) resilient to the network not being available. You can dothis as follows:
serviceworker.js - demo
onfetch = async (event) => {
if (event.request.method !== 'POST') return;
if (event.request.url.startsWith('https://paul.kinlan.me/share/image/') === false) return;
/* This is to fix the issue Jake found */
event.respondWith(Response.redirect('/share/image/'));
event.waitUntil(async function () {
const data = await event.request.formData();
const client = await self.clients.get(event.resultingClientId || event.clientId);
// Get the data from the named element 'file'
const file = data.get('file');
console.log('file', file);
client.postMessage({ file, action: 'load-image' });
}());
};
There are a couple of interesting things happening above, which can quicklysummarized as:
- Render the UI as the result of the
POST
request by performing a redirect. - Read the data that is submitted via the form via
event.request.formData()
- Send the data to the open window (this will be the UI that we redirected theuser to in the first point).
It is entirely up to you what you do with the data that has been posted to yourservice worker, but in the case of my App I needed to show it directly in the UIso I have to find the window the user is using and postMessage
the data there.
index.html - demo
navigator.serviceWorker.onmessage = (event) => {
console.log(event);
imageBlob = event.data.file;
// Update the UI with the data that has been shared to it.
imageShare.src = URL.createObjectURL(imageBlob);
};
And that’s about it. If you already have an API endpoint for your web forms,then this is a simple, yet powerful addition that you can make to your site.
The Web Share Target API incredibly powerful platform primitive that breaks downanother barrier that web apps have had on their host platforms.