If you’re looking to build a powerful PWA that takes advantage of the hardware on a device, things are only going to get better. In my previous post, I explained the fundamental concepts of PWA. In this article, I will discuss some PWA features that provide access to your hardware APIs:
To start with this tutorial you must install the following:
As a starting point for the tutorial, clone this Github repository:
Then in your terminal move to the following directory:
and install the dependencies through:
Open your app on: http:// localhost:8080
Media Capture API
The Media Capture API allows authorized Web applications to access the streams from the device’s audio and video capturing interfaces, i.e. to use the data available from the camera and the microphone. The streams exposed by the API can be bound directly to the HTML
<video> elements or read and manipulated in the code, including further more specific processing via Image Capture API, Media Recorder API or Real-Time Communication.
Media Capture API explanation
This prompts the user to access the media interface (video or audio).
Returns a collection of audio tracks provided by your device’s microphone.
Returns a collection of video tracks provided by your device’s camera.
mediaElement.srcObject = stream
Sets a stream to be rendered in the provided or HTML element.
Adjust the Progressive Selfies App to Take Selfies
Add this code to your index.html (Listing 1), directly below the tag: <div id = “create-post”>. In this code the “Capture button” is defined to take a snapshot (= selfie) of your video tracks.
The <video> and <canvas> tag is also defined for displaying your video and your snapshot (selfie) in your web page, respectively.
Add the following code into the existing feed.js to define your required variables (Listing 2). For example, the variable videoPlayer contains the HTML element <video> with the id = “player”. Your video tracks are rendered here. The canvasElement is for rendering your selfie, the captureButton is there to take a selfie.
Add the initializeMedia() function in feed.js to initialize your camera.
The call: videoPlayer.srcObject = stream, sets a stream (or video tracks), which is rendered in the provided <video> HTML element.
Add listing 4 in feed.js to define your “modal” to take a selfie. It also calls the above initializeMedia() function.
Add a click event handler to the “shareImageButton” in feed.js (see listing 5). This button (see figure 2) opens the “openCreatePostModal”.
Finally, add a click event handler for “Capture Button” in feed.js (listing 6).
With this “Capture Button” you can take a snapshot/selfie of your video tracks (see figure 3). This snapshot is rendered in the canvasElement and converted to a Blob (see listing 7) via the function: dataURItoBlob() for possible storage in a Database.
Add this in utility.js:
If necessary, restart the server with npm and take a selfie using the Capture button (figure 4).
Adjust the Progressive Selfies App to Determine Your Location
With the Geolocation API, web applications can access the location data provided by the device – obtained via GPS or through the network environment. Aside from the one-time location query, it also provides a way to notify the app of location changes.
Geolocation API explanation
Performs a one-time search for the location with coordinates, accuracy, elevation and speed, if available.
Location changes are observed.
Let’s use the Geolocation API to determine the position of your selfie. Add the code below in your index.html, directly under the tag: div#manual-location. In this code, the “Get Location button” is defined to determine the location where you took the selfie (Listing 8).
Add listing 9 in
feed.js, to define your required variables to determine the location.
Add this initializeLocation() function in feed.js (listing 10):
And add the initializeLocation() function in openCreatePostModal, immediately after the initializeMedia() function call in feed.js (see Listing 11).
Add a click event handler for the “locationButton” in feed.js. This “Location button” determines the location where you took the selfie (Listing 12).
This code checks whether the API of the “geolocation” is available in the navigator property of the window object. If so, this code performs a one-time search to determine the location (with coordinates), via the function: navigator.geolocation.getCurrentPosition(). The address is then searched for using these coordinates via the ‘openstreet map‘.
If necessary, restart the server with npm and retrieve the location using the “GET LOCATION” button (figure 5).
Send Selfies Online with BackgroundSync API
BackgroundSync API allows users to queue data that needs to be sent to the server while a user is working offline, and then as soon as they’re online again, it sends the queued data to the server.
Let’s say someone using our Progressive Selfies app wants to take and send a selfie, but the app is offline. Background-Sync API allows the user to queue a selfie while offline. As soon as it is back online, the Service Worker sends the data to the server. In our case we use an IndexedDB to store data in the meantime (figure 6). The library for this database can be found in the lib/idb.js folder. You can read about what and how a Service Worker works in my previous post about PWA.
Clone the server
First clone the PWA-server via:
We will send the selfies to this server.
Install the dependencies and start this server using:
The server runs on localhost: 3000
To apply BackgroundSync to our app, we need to create a “store” in our Indexed-DB database to keep our
“synchronized selfies” (Listing 13). We do that in
utility.js. This utility.js contains the code needed for both the
Service Worker and the app itself.
We need to use the BackgroundSync API when we send data to the server, via the
submit event. Add a submit event handler in feed.js (Listing 14).
In the first part of the code, the id is generated for the selfie to be sent. First we do a simple check to see if the browser supports serviceWorker and SyncManager. If this is the case and the Service Worker is ready, register a sync with the tag ‘sync-new-selfies’. This is a simple string used to recognize this sync event. You can think of these sync tags as simple labels for different actions.
Then we save the selfie in the IndexedDB using the writeData function.
Finally, all stored selfies are read using readAllData(“sync selfies“) and are shown in your PWA via the function: updateUI(syncSelfies). A message is also sent out: “Your Selfie was saved for syncing!”
For the Service Worker to work correctly, a sync event listener must be defined in sw.js (Listing 15).
sync event is only activated when the browser/device is
reconnected. The Service Worker can handle these types of events (see my
previous post about PWA). It also checks whether the current
sync event has a
tag that matches the string
“sync-new-selfies”. If we didn’t have this
sync event will fire every time the user is connected.
As soon we are back online again, we retrieve the selfies stored in the IndexedDB. After that, the
fetch API is used to send the selfies to the server, using the API_URL:
http://localhost: 3000/selfies. Finally, the selfies already sent are
removed from the IndexedDB.
Believe it or not, testing all this is easier than you think: once you’ve visited the page and the Service Worker is up and running, all you have to do is disconnect from the network. Every Selfie that you try to send offline will now be stored in the IndexedDB (see figure 7). All saved selfies will also be shown in your main screen (see figure 8).
Once you are back online, the Service Worker will send the selfies to the server (see your Network tab in your Chrome Developer Tools in figure 9). There you will see that a selfie has been ”
posted” three times to the server. This server contains a folder called ”
images“, which contains the
After this introduction you can continue with an extensive tutorial that you can find in: https://github.com/petereijgermans11/progressive-web-app/tree/master/pwa-workshop. In a subsequent article I will discuss other APIs such as Web Streams API, Push API (for receiving push notifications) and the web Bluetooth API.