How difficult is it?
It is easy to develop an add-on. You only need:
- JSON Manifest
- CSS or Javascript
- Set of icons
NO UPDATE.WEBAPP MANIFEST
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
What I tried to do?
Firefox OS has an NFC API.
But it doesn't have a background service to interact with other NFC devices.
This means that you need to open a specific Webapp to use NFC.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Implementation
- We are going to add an Add-on to the System Webapp
- This Add-on will use the NFC API.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Use cases
- Access control
- Mobile payments
- Loyalty programs
- In-store marketing
- Location based services
- Targeted marketing
- Information Exchange
- Social networks...
@CodingFree
Lets start!
Firstly, we have to define our manifest.json file:
It will be a Chrome manifest, quite different from the manifests used for Firefox OS Webapps.
Manifest File Format: Field summary.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Fields
Supported fields:
- name
- version
- description
- content_scripts <== Important!
- permissions <== ignore it
- web_accessible_resources
- background
- browser_action
- default_locale
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
Not supported:
- browser_action
- automation
- commands
- event_rules
- plugins
- sandbox
- storage
- key
- more...
@CodingFree
{
"manifest_version": 2, // WebApp Manifest = 1 (deprecated), WebExtension = 2
"version": "1.0", //My own version
"name": "NFC Sleep",
"description": "Turn off your WiFi and volume using a NFC Tag.",
"author": "Adrian Crespo",
"role": "addon", // Mandatory.
"type": "certified", // No effect! It's deliberately wrong,I wanted to point out that is has no effect!
"content_scripts": [
{
"matches": [
"app://system.gaiamobile.org/index.html" // My target will be the System App.
],
"js": [
"scripts/nfc.js" // My script
]
}
],
"icons": {
"1200": "/style/icons/1200.png", // Icons!
"128": "/style/icons/128.png", // Required by the Marketplace
"60": "/style/icons/60.png", // Standard size
"32": "/style/icons/32.png" // Why not?
}
}
Create the Zip archive
Do you remember...?
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
//... code ...
"content_scripts": [{
"css": [],
"js": ["scripts/nfc.js"]
}],
//... code ...
We have to zip the same
tree structure, or it won't
work!
(it's the same for the icons)
Javascript
Our target will be the System App, because we specified it in the "matches" field.
It supports regular expressions:
// More code
"content_scripts": [
{
"matches": [
"app://system.gaiamobile.org/index.html"
],
"js": [
"scripts/nfc.js"
]
}
],
// More code
["http://www.mozilla.com/*"].
For any URL it would be like this:
["<all_urls>"]
More examples: match patterns.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Considerations
First, notice that the wrapping function statement starts with (function... as opposed to just function....
(function foo(){ .. }) as an expression means the identifier foo is found only in the scope where the ... indicates, not in the outer scope (and this is safer and cleaner).
Extracted from: You Don't Know Javascript!
(because it is really awesome)
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Considerations
We are going to use the Notifications API (standard):
To create the notification:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
var notification = new window.Notification( ... )
- Notification.title
- Notification.body
- Notification.icon
- Notification.permission
- Notification.requestPermission()
@CodingFree
Considerations
And we are going to use the NFC API:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
if(window.navigator.mozNfc)...
nfc.ontagfound(...);
ndefObject.ndefRecords(...);
ndefRecords.length;
ndefObject.ndefRecords;
ndefRecords[i].payload.wrappedJSObject;
- Firstly, test if mozNfc is supported.
- If true, lets wait to find a NFC tag.
- When found, get how many records are there and retrieve them.
- And then, read the payload as a wrappedJSObject. <== ¿?¿?¿?
The payload will be the orders for the System App.
@CodingFree
Considerations
And we are going to use the NFC API:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
We are using wrappedJSObject because it is a nasty fix :(
The XPCOM model didn't allow me to read the payload directly, so I used that to "see" the object hidden by the wrapper.
It is fixed, but... if you find it, you will know how to fix it :)
@CodingFree
Considerations
At last, we will use the Settings API to modify the volume of the mobile phone:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
It's easy to use: you need to use a lock to change the settings (to avoid race conditions), and then use set() to change the values.
We could disable the WiFi: 'wifi.enabled': false
window.navigator.mozSettings;
settings.createLock();
result = lock.set({...});
result.onsuccess;
result.onerror;
@CodingFree
(function () {
this._started = false;
this.tag = null;
start();
function notify(titleid, body, bodyid, onClick) {
console.log("A notification would be send: " + titleid);
var canSend = false;
if (Notification.permission === "granted") {
// If it's okay let's create a notification
canSend = true;
}
// Otherwise, we need to ask the user for permission
if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
canSend = true;
}
});
}
if(canSend) {
var notification = new window.Notification(titleid, {
body: body,
icon: '/style/icons/32.png'
});
notification.onclick = function () {
notification.close();
if (onClick) {
new MozActivity({
name: "view",
data: {
type: "url",
url: body
}
});
}
};
}
}
function changeSettings(){
var settings = window.navigator.mozSettings;
var lock = settings.createLock();
var result = lock.set({
'wifi.enabled': false,
'bluetooth.enabled': false,
'powersave.enabled': true,
'ril.data.enabled': false,
'audio.volume.content': 0,
'audio.volume.notification': 0
});
result.onsuccess = function () {
console.log("NFC-Sleep: The setting has been changed");
notify("NFC-Sleep", "The setting has been changed");
}
result.onerror = function () {
console.log("NFC-Sleep: An error occure, the setting remain unchanged");
notify("NFC-Sleep", "An error occure, the setting remain unchanged");
}
}
function manageNDEFRecords(ndefRecords) {
console.log("NFC-Sleep: managing NDEF records.");
var ndefLen = ndefRecords ? ndefRecords.length : 0;
if(ndefLen != 0){
var outputString = '';
for (i = 0; i < ndefLen; i++) {
payload = dumpUint8Array(ndefRecords[i].payload.wrappedJSObject);
}
console.log("NFC-Sleep: "+payload);
if (payload.localeCompare("NFC-Pass1") === 0){
changeSettings();
}
}
}
function handleTagFound(ndefObject){
console.log("NFC-Sleep: Tag found");
var ndefRecords = ndefObject.ndefRecords;
var ndefLen = ndefRecords ? ndefRecords.length : 0;
// if no NDEF Records are contained, bail out.
if (!ndefLen) {
console.log("NFC-Sleep: The tag is blank")
return true;
}
console.log("NFC-Sleep: The tag is okay, lets read it");
manageNDEFRecords(ndefObject.ndefRecords);
return false;
}
function dumpUint8Array(array) {
if (!array) {
return 'null';
}
var str = '';
var i;
var arrayLen = array ? array.length : 0;
for (i = 0; i < arrayLen; i++) {
str += '' + hex2a(array[i].toString(16));
}
return str + '';
}
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
function stop() {
if (!this._started) {
throw 'Instance was never start()\'ed but stop() is called.';
}
this._started = false;
window.removeEventListener('mozChromeEvent', this.handleEvent);
}
function start() {
console.log("NFC Sleep Running LOL");
if (this._started) {
throw 'Instance should not be start()\'ed twice.';
}
var nfc = window.navigator.mozNfc;
if (!nfc) {
console.log('Go home NFC, you are not available. Please, disable this addon.');
return;
} else {
console.log('NFC Sleep enabled.');
this._started = true;
nfc.ontagfound = handleTagFound.bind(this);
}
}
}());
Upload and publish it!
Do you remember the ZIP file?
Just go to this webpage and upload it:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
It will be public as soon as it is reviewed by the Marketplace Reviewers Team.
@CodingFree
Thanks!
Thank you for attending the presenta
tion
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
Feel free to ask me any question:
@CodingFree
@CodingFree
Appendix
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Firefox OS Addons - NFC
By firefoxos
Firefox OS Addons - NFC
Developing Firefox OS Addons: implementing a background service for NFC.
- 1,752