Seven Awesome PWA Features Seven awesome web-platform features you didn't know about. 505 words. By Jeff Delaney Created Jan 5, 2021 Last Updated Jan 5, 2021 Code Slack #javascript #pwa Progressive Web Apps (PWA) represent a collection of capabilities that put web apps on a level playing field with native iOS, Android, and desktops apps. The following tutorial implements a 7 lesser-known web features. 1. App Shortcuts App Shortcuts file_type_config manifest.json { "name": "Fireship", //... "shortcuts": [ { "name": "Activity Feed", "short_name": "Feed", "description": "View your activity feed", "url": "/feed?utm_source=homescreen", "icons": [{ "src": "/icons/feed.png", "sizes": "192x192" }] }, { "name": "Recent Comments", "short_name": "Comments", "description": "View recent comments", "url": "/comments?utm_source=homescreen", "icons": [{ "src": "/icons/comments.png", "sizes": "192x192" }] } ] } 2. Contact Picker The Contact Picker requires an HTTPS connection. If developing locally, use Ngrok to setup an SSH tunnel that can broadcast localhost to a secure URL. file_type_js_official app.js const btn = document.getElementById('contacts'); btn.addEventListener('click', (event) => getContacts()); const props = ['name', 'email', 'tel', 'address', 'icon']; const opts = {multiple: true}; const supported = ('contacts' in navigator && 'ContactsManager' in window); async function getContacts() { if (supported) { const contacts = await navigator.contacts.select(props, opts); console.log(contacts); } else { alert('contact picker not supported!') } } 3. Device Motion Device Motion file_type_js_official app.js window.addEventListener('devicemotion', function(event) { const el = document.getElementById('motion'); console.log(event); el.innerText = (Math.round((event.acceleration.x + Number.EPSILON) * 100) / 100) + ' m/s2'; // el.innerText = event.rotationRate.beta; }); window.navigator.geolocation.getCurrentPosition(console.log) 4. Bluetooth & External Devices Bluetooth file_type_js_official app.js const button = document.getElementById('ble'); button.addEventListener('click', (event) => connectBluetooth()); async function connectBluetooth() { // Connect Device const device = await navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] }); const server = await device.gatt.connect(); // Get heart rate data const hr = await server.getPrimaryService('heart_rate'); const hrMeasurement = await hr.getCharacteristic('heart_rate_measurement'); // Listen to changes on device await hrMeasurement.startNotifications(); hrMeasurement.addEventListener('characteristicvaluechanged', (e) => { console.log(parseHeartRate(e.target.value)); }); } 5. Idle Detection Idle Detection file_type_js_official app.js if ('IdleDetector' in window) { const idleBtn = document.getElementById('idle'); idleBtn.addEventListener('click', (event) => runIdleDetection()); async function runIdleDetection() { const state = await IdleDetector.requestPermission(); console.log(state); const idleDetector = new IdleDetector(); idleDetector.addEventListener('change', () => { const { userState, screenState } = idleDetector; console.log(idleDetector) if (userState == 'idle') { // update database with status } }); await idleDetector.start({ threshold: 120000, }); } } 6. File System File System file_type_js_official app.js const getFileBtn = document.getElementById('fs-get') getFileBtn.onclick = async () => { const [handle] = await window.showOpenFilePicker(); const file = await handle.getFile(); console.log(file) }; const saveFileBtn = document.getElementById('fs-save') saveFileBtn.onclick = async () => { const textFile = new File(["hello world"], "hello.txt", { type: "text/plain", }); const handle = await window.showSaveFilePicker(); const writable = await handle.createWritable(); await writable.write(textFile); await writable.close(); }; 7. Web Share Use the Share Target API by updating the manifest with a share target: file_type_config manifest.json { "name": "Fireship", //... "share_target": { "action": "/share-photo", "method": "POST", "enctype": "multipart/form-data", "params": { "title": "name", "text": "description", "url": "link", "files": [ { "name": "photos", "accept": "image/png" } ] } }, } Use the Web Share API to open a share dialog on the native device: file_type_js_official app.js const shareBtn = document.getElementById('share'); shareBtn.onclick = async (filesArray) => { if (navigator.canShare) { navigator.share({ url: 'https://fireship.io', title: 'PWAs are awesome!', text: 'I learned how to build a PWA today', }) } }