Bitcoin Value Fetcher

B

In this tutorial you will learn how to create a PWA application, which fetches the 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.

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

Example screenshots and video

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

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

Project folder

Create a new project folder for this exercise.

mkdir bitcoin

Application manifest file

Create a manifest.json file for the app. You can download icons from here: bitcoin_icons.zip. Note that you need to do a icons folder for the icons.

{
    "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"
}

Main 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.

<!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

Create a styles.css file for your project.

#container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

Testing

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.

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

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:

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',
];

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.

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.

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.

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.

<script>if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('./serviceworker.js')
    .then(function() {
       console.log('Service Worker Registered');
    });
}
</script>

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.

You can see above picture bigger, just select it with right mouse button and select “Open image in New Tab”.

Fetch a Bitcoin value

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

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

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

{"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.

<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>

Testing

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

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:

// 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.

<body onload="lastBTC()">

And create a lastBTC function inside a script element.

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

Testing

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.

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.

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.

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

Open development tools and select “Audits”. Leave default options as they are and “Run audits”.

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

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 from 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.

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

Page works normally from the web.

User can find a launch icon from the home screen.

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

Add comment

Pasi Manninen

Pasi Manninen

Pasi is a mobile and web application developer. Currently working as a senior lecturer in JAMK University of Applied Sciences. Pasi has programming experience over many decades and has taught dozens of courses since the 90's.

Recent Posts

Follow Me