Enable Background Sync, Media Capture, and Geolocation APIs in Your PWA
Enable Background Sync, Media Capture, and Geolocation APIs in Your PWA
In this tutorial, I will discuss advanced PWA features that provide access to your hardware APIs. We are going to build an app for making selfies with the Media Capture API and posting selfies with the BackgroundSync Api.
Join the DZone community and get the full member experience.Join For Free
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:
- Media Capture API, to take a picture (in this article called a "selfie") with your camera. https://developer.mozilla.org/en-US/search?q=Media_Streams_API
- Geolocation API, to determine the location of your selfie. https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API
- and the commonly used Background Sync API, to put the selfies in a queue or database in the meantime, so that the user can also send a selfie to the server if it is not connected. https://developers.google.com/web/updates/2015/12/background-sync
To start with this tutorial you must install the following:
Stable node version 8.9 or higher (https://nodejs.org/en/download/)
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
stream.getAudioTracks()Returns a collection of audio tracks provided by your device's microphone.
stream.getVideoTracks()Returns a collection of video tracks provided by your device's camera.
mediaElement.srcObject = stream
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
Geolocation APIWith 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.
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 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
Sync selfiesTo 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.
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).
TestingBelieve 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).
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.
Follow or like me on twitter https://twitter.com/EijgermansPeter
Opinions expressed by DZone contributors are their own.