Introduction
We can change the way that we interact with the browser and the way that we absorb all the information that are relevant to us simply by customizing the behavior of the chrome using extensions.
The greatest thing about chrome is that it is easy to create a great chrome extension.
Extensions like RSS readers and e-mail notifications are the most common in the chrome web store.
In this post I will show you how to create a simple extension that accesses an external API hosted by forecast.io
The source code of the extension is available in my github.
Starting a chrome extension
First of all, it is very important to setup your development environment.
The manifest.json file exists to group all the basic information that chrome needs to load the extension.
I show below the manifest.json file created for the extension that we are about to develop.
{
"manifest_version": 2,
"name": "Forecast.io",
"description": "Here you should write the description of your extension",
"version": "1.0",
"browser_action": {
"default_icon": "clear-day.png",
"default_popup": "popup.html"
},
"permissions": [
"geolocation",
"alarms",
"<all_urls>"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
- manifest_version = Must have the value 2, so the version 1 is deprecated since Chrome 18
- name = The extension’s name
- description = The extension’s description
- version = The extension’s version. This attribute is used to compare the installed version with the published version for autoupdate
- browser_action = It is used to put the icon of our extension in the toolbar
- permissions = We must declare our intents
- background = It is used to run code in background. In our case, to get the weather data.
We’ve defined the geolocation, alarms and <all_urls> permission.
The geolocation permission allows us to use the geolocation API without asking the users every time we need to get their location, because the user agrees with this condition when installs the extension.
The alarms permission allows us to use the chrome.alarms API which is responsible to schedule the task required in our chrome extension.
The <all_urls> permission asks for access to all URL for our chrome extension. This kind of permission must be used with care, it should be the URL that we are going to use. (i.e. “http://*.google.com/", you can check the documentation at https://developer.chrome.com/extensions/match_patterns.)
Background Service
In our extension, the background service is responsible for fetching the data and update the icon of the button in the toolbar.
The file background.js has the API key, the geolocation functions, the JSON parse functions and the chrome extension listeners.
Below is the file background.js:
var APIKEY = '6ee8de3e1a315894761e9006065cffde';
var latitude = 0;
var longitude = 0;
var lastResult = null;
function getLocation(callback) {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition, showError);
}
if (callback) {
callback();
}
}
function showPosition(position) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
getJSON('https://api.forecast.io/forecast/' + APIKEY + '/' +
latitude + ',' + longitude + '?units=si&lang=pt&exclude=minutely,hourly,daily,alerts,flags',
function(result) {
chrome.browserAction.setIcon({
path: "/" + result.currently.icon + ".png"
});
lastResult = result;
});
}
function getJSON(url, callback) {
var x = new XMLHttpRequest();
x.open('GET', url);
x.responseType = 'json';
x.onload = function() {
callback(x.response);
};
x.send();
}
function showError(error) {
var statusDiv = document.getElementById("status");
switch(error.code) {
case error.PERMISSION_DENIED:
console.log("User denied the request for Geolocation.");
break;
case error.POSITION_UNAVAILABLE:
console.log("Location information is unavailable.");
break;
case error.TIMEOUT:
console.log("The request to get user location timed out.");
break;
case error.UNKNOWN_ERROR:
console.log("An unknown error occurred.");
break;
}
}
chrome.runtime.onInstalled.addListener(function() {
chrome.alarms.create("forecast", {
delayInMinutes: 0,
periodInMinutes: 10
});
});
chrome.alarms.onAlarm.addListener(function( alarm ) {
getLocation();
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action == "getCurrentForecast") {
getLocation(function() {
sendResponse(lastResult);
});
}
});
In this file we have some listeners that are detailed below:
Runs during the installation of an extension and when the extension or chrome is updated.
In this listener we created an alarm to be called every 10 minutes.
Runs when an alarm reaches its defined time.
At this moment, we make a call to the function getLocation() which is responsible to get the geolocation.
After receive the geolocation, the function showPosition() is called to update the action button on the toolbar relative to the current weather.
Runs when a message is received from the popup. When we click the extension icon on the toolbar, we open a popup showing an image relative to the current weather, the weather description and the temperature in degrees celsius.
I will explain this flow in detail in the next section.
Popup
The popup is opened after the extension icon is clicked.
It is made with HTML, CSS and Javascript, so that it is very simple to build an extension.
The file popup.html has a very simple HTML code, showing only one image for the current weather, one div to show the description and another div for the temperature.
Below the file popup.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="popup.js"></script>
<link href="popup.css" rel="stylesheet">
</head>
<body>
<img id="ico" />
<div id="status">Carregando...</div>
<div id="temperature"></div>
</body>
</html>
Below the popup.css file:
body {
text-align: center;
width: 300px;
height: 300px;
font-size: 18pt;
font-family: Tahoma;
vertical-align: middle;
}
#ico {
display: none;
margin: 0 auto;
}
#temperature {
display: none;
font-size: 26pt;
}
Below the popup.js file:
function sendMessage() {
chrome.runtime.sendMessage({action: "getCurrentForecast"}, function(response) {
if (response == null) {
setTimeout(sendMessage, 2000);
} else {
showResult(response);
}
});
}
function showResult(response) {
var statusDiv = document.getElementById("status");
var icoImg = document.getElementById("ico");
var temperatureDiv = document.getElementById("temperature");
statusDiv.textContent = response.currently.summary;
temperatureDiv.style.display = "block";
temperatureDiv.textContent = response.currently.temperature.toString().split('.')[0] + "˚C";
icoImg.style.display = "block";
icoImg.src = chrome.extension.getURL("/" + response.currently.icon + ".png");
}
document.addEventListener('DOMContentLoaded', sendMessage);
The listener DOMContentLoaded takes care of the popup load.
When the popup is opened, chrome sends the event DOMContentLoaded and it is the event that we send the message to the background asking for the last known data.
If the response is not available (indicating that we still have not the API response), the function waits 2 seconds then tries again.
When we get the response, we send it to the showResult function to show the result in the popup.
Chrome extension installation
To install the chrome extension, you have to open your chrome and type chrome://extension in the address bar.
One page is opened with all installed extensions, like below:
To enable the developer mode, you have to check the Developer mode checkbox.
After checking the checkbox, you must click on Load unpacked extension… button.
Choose the folder which your extension is saved.
If all went right, your extension should be loaded an icon should be created on your chrome toolbar and hopefully it is working.
Conclusion
The extension can evolve to show the temperature changes alerts after every weather change, or you can store an history or maybe show the minimum and maximum temperatures for the day, it is up to you.
If you change or improve the extension, share with me and the other readers. You can comment on this post with your github link and a brief explanation of what you have done.
If you have any issue or suggestion leave your comment below.