Skip to content

Exercise 12 : Bitcoin Value Fetcher

Purpose and learning process

In this exercise you will learn the basics of the PWA development:

  • creating a app manifest file
  • registering service worker in index.html
  • understand install, activate and fetch events in service worker
  • caching files to use offline mode
  • fetching bitcoin value from the web
  • saving data to device's local storage
  • basic use of chrome development tools with PWA

In this exercise you will learn how to create a PWA application, which fetches Bitcoin value from CryptoCompare. The main purpose is to learn the basics of PWA. You will test your PWA in web browser and in a real device or mobile emulator.

Example screenshots

Demo app is a Bitcoin Fetch app which fetches bitcoin value from the web.

Bitcoin 01

Example Video

Here is an sample video how the app will/should work when this exercise is finished: https://youtu.be/aKHdwS2VaBM

Project

Create a new project folder for this exercise.

1
mkdir bitcoin

manifest.json

Create a manifest file for the app. You can download icons from here: bitcoin_icons.zip

Tip

Remember check PWA materials to understand manifest settings.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
    "name": "Bitcoin Fetcher",
    "short_name": "Bitcoin Fetcher",
    "description": "Fetch Bitcoin Value",
    "icons": [
      {
        "src": "icons/icon-128x128.png",
        "sizes": "128x128",
        "type": "image/png"
      },
      {
        "src": "icons/icon-144x144.png",
        "sizes": "144x144",
        "type": "image/png"
      },
      {
        "src": "icons/icon-152x152.png",
        "sizes": "152x152",
        "type": "image/png"
      },
      {
        "src": "icons/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
      },
      {
        "src": "icons/icon-256x256.png",
        "sizes": "256x256",
        "type": "image/png"
      },
      {
        "src": "icons/icon-512x512.png",
        "sizes": "512x512",
        "type": "image/png"
      }
    ],
    "start_url": "./",
    "display": "standalone",
    "background_color": "white",
    "theme_color": "#685f85"
}

index.html

Create a new index.html file, which now only have a few meta elements, link to styles and manifest and a few basic UI elements. We will later add here a few lines of JavaScript code and register Service Worker.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Bitcoin">
    <meta name="theme-color" content="#685f85"/>
    <title>Bitcoin Value Fetcher</title>
    <link rel="stylesheet" type="text/css" href="styles.css" media="all">
    <link rel="manifest" href="manifest.json">
  </head>
  <body>
    <div id="container">
      <h1>Bitcoin Value Fetcher</h1>
      <button>Get it!</button>
      <p id="bitcoinText"></p>
      <!-- add service worker register script here -->
    </div>
  </body>
</html>

styles.css

Create a styles.css file for your project.

1
2
3
4
5
6
#container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

Run local web server

You can use any “tools” to test your project in your local machine. One good way to test is to install Web Server App for Chrome. This tool serves web pages from a local folder over the network, using HTTP. Runs offline. You can install it from here: Web Server for Chrome.

Install it and launch. Choose folder point to your project folder and start web server. Use chrome and go to following address: http://127.0.0.1:8887.

Bitcoin 02

You should see index.html running in Chrome. Of course nothing is working yet – UI is only ready 🙂

Bitcoin 04

Service Worker

Next step is to add a service worker to your project. Create a serviceworker.js to your project.

Cache

First define files to be cached:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var cacheName = 'bitcoin-v1';
var filesToCache = [
  './',
  './index.html',
  './styles.css',
  './manifest.json',
  './icons/icon-128x128.png',
  './icons/icon-144x144.png',
  './icons/icon-152x152.png',
  './icons/icon-192x192.png',
  './icons/icon-256x256.png',
  './icons/icon-512x512.png',
];

Note

Remember, that service worker is running install, activate and fetch events.

Install event

In install event all the cache files will be cached. Add a following code to your service worker file.

1
2
3
4
5
6
7
8
9
self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] caching');
      return cache.addAll(filesToCache);
    })
  );
});

Activate event

Now activate event is not doing anything special, it only removes old cached files if service worker has been updated. Add a following code to your service worker file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
self.addEventListener('activate', function(event) {
    console.log('[ServiceWorker] activating');
    event.waitUntil(
        caches.keys()
        .then(function(cacheNames) {
            return Promise.all(
                cacheNames.map(function(cName) {
                    if(cName !== cacheName){
                        return caches.delete(cName);
                    }
                })
            );
        })
    );
});

Fetch event

A final step with a service worker is to add fetch event listener. Here we have added a few console.log lines that we can see from the console what is happening in our PWA app when it is launched and run in online/offline mode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
self.addEventListener('fetch', event => {
  console.log('[ServiceWorker] fetch event for ', event.request.url);
  event.respondWith(
    caches.match(event.request).then(response => {
      if (response) {
        console.log('Found ', event.request.url, ' in cache');
        return response;
      }
      console.log('Network request for ', event.request.url);
      return fetch(event.request)
    }).catch(error => { 
      console.log(error);
    })
  );
});

Register Service Worker in index.html

Service worker is now ready and it need to be registered in index.html file. Add a following script below container div in index.html.

1
2
3
4
5
6
7
8
<script>
if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('./serviceworker.js')
    .then(function() {
       console.log('Service Worker Registered');
    });
}
</script>

Save and test

Open a developer tools in Chrome, select Application tab and select Service Worker. Reload your web page. You should see that your service worker is now running. Note also messages from the console. Service worker has been installed and registered. Cached files will be saved and finally service worker is active.

!Bitcoin 05

Click image to see it bigger!

Fetch Bitcoin value

Modify your index.html file and add onclick event handling for the button.

1
<button onclick="fetchBitcoin()">Get it!</button>

Create a new <script> element and add fetchBitcoin function. You can use cryptocompare.com min API to fetch BTC data. Server will send BTC data with a following JSON format:

1
{"BTC":{"EUR":9262.72}}

Now a pure JavaScript is used so you need to use XMLHttpRequest to fetch data from the web. Finally BTC value will be displayed in UI.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<script>
function fetchBitcoin() {
  var url = 'https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=EUR';
  var request = new XMLHttpRequest();
  request.onreadystatechange = function() {
    if (request.readyState === XMLHttpRequest.DONE) {
      if (request.status === 200) {
        var response = JSON.parse(request.response);
        var now = new Date().toLocaleDateString();
        document.getElementById("bitcoinText").innerHTML = now + " : " + response.BTC.EUR + " €";
        // store value to local store here later
      }
    }
  };
  request.open('GET', url);
  request.send();  
}
</script>

Tip

Link : XMLHttpRequest

Save and test

Test your application and it should load and show BTC value.

Bitcoin 06

Save and load data to/from Local Storage

Next step is to save fetched BTC value to local storage. So when app is launched, the last value will be shown. Modify fetchBitcoin function to save value to local storage:

1
2
// store value to local store here later
localStorage.setItem("btc", now + " : " + response.BTC.EUR + " €");

Now BTC value with date will be saved to local storage with a btc key. Modify index.html body element to load value from the local storage.

1
<body onload="lastBTC()">

And create a lastBTC function inside a script element.

1
2
3
function lastBTC() {
  document.getElementById("bitcoinText").innerHTML = localStorage.getItem("btc");
}

Save and test

Your browser might cache your index.html file so you need to clear cache to get it working. Select Clear storage from developer console’s application tab and click Clear site data.

!Bitcoin 07

Refresh your page, fetch a new BTC value, refresh it again and it should display previously fetched BTC value from the local storage.

Offline

In this exercise, we don’t implement any fancy offline UI to the app, just only a nice alert prompt. But you can be a innovative and modify it better. Modify your fetchBitcoin function to display an alert message, if device is offline when a BTC value is tried to fetch from the server side.

1
2
3
4
5
6
function fetchBitcoin() {
  if (!navigator.onLine) {
    // you should visualize this better/nicer
    alert("Device is offline!");          
  }
  // ..  

Now use developer tool’s Application tab and switch browser to offline. Refresh your app and see how page contents are loaded from the cache and button gives above alert message.

!Bitcoin 08

Publish

Copy your project folder to web server which supports HTTPS-connection. Go to your server with a Chrome and test how it works from remote server. Yes – it should work the same way.

Testing with browser

Open development tools and select Lighthouse. Leave default options as they are and Generate report.

!Bitcoin 09

Now your page is tested and you should see there results – more importantly PWA results.

!Bitcoin 10

If everything went correctly, you should see that your app is working as a PWA. Scroll results to Progressive Web App and see there detailed results.

Testing with Mobile

Use your mobile device’s browser and go to your page. You will get best results with Android and Chrome. Test Safari with iOS.

You should see the same kind of page what you have seen in the desktop browser.

Bitcoin 12

Chrome detects this page is PWA and ask end user to add this page to the home screen.

Bitcoin 13

User can find a launch icon from the home screen.

Bitcoin 16

PWA is launched, notice there aren't location bar at the top of the app. App looks as a native one!

Bitcoin 17

Push to GitLab

Test your application in emulator, take screenshots (add those to your project folder) and commit/push your mobile-exercises repository back to JAMKIT/GitLab. Remember move your exercise/issue ticket from Doing to In Review in Issues Board and write your learning comments to issue comments.