В этой статье мы рассмотрим разработку расширения для Firefox, с помощью addon sdk, а также разберём ключевые моменты разработки: установка sdk(jpm), инициализация проекта, тестирование, компиляция и публикация нашего расширения на addons.mozila.org, на примере всё того же скриншотера…
![image](https://habrastorage.org/getpro/habr/post_images/b1a/1c1/68c/b1a1c168c806a3a063d66a8852d47e85.png)
Должен сразу оговориться, что расширение поддерживается только linux системами и разработана на linux.
И так, с начала мы должны установить пакет jpm в нашу систему, для этого устанавливаем nodejs и npm (если нету):
После установки node.js и npm устанавливаем jpm с помощью команды:
Эта команда установит нам jpm в глобальную область, его так же можно установить локально опустив ключ --global.
Далее нам необходимо создать директорию, для будущего расширения. Давайте назовём его habrscreen:
И инициализируем в этой директории расширение, для этого нам надо перейти в папку и выполнить команду инициализации:
После выполнения данной команды, в директории создаётся скелет будущего приложения.
habrscreen
— index.js
— package.json
— test
— test-index.js
Рассмотрим конфигурацию нашего addon package.json:
Что здесь может быть интересного? это тот же манифест только в формате json. Да это так тот же манифест с указанием версии, описанием и имени addons. А так же мы в нём определили настройки нашего модуля пока их будет 4:
1. client id — id клиента yandex oauth
2. get OAuth token — кнопка при клике переходим на яндекс и получаем токен авторизации
3. oauth token — собственно поле для ввода токена
4. autocopy to clipboard — флаг который автоматического копирования ссылки на скриншот в буфер обмена.
После определения настроек нам необходимо подумать о кнопке, при нажатие на которую будет запускаться наш скриншотер. Для этого открываем index.js на редактирование и описываем в нём эту кнопку:
Код довольно прост, для начала мы импортируем, нужные нам, компоненты sdk, и создаём объект кнопки. Нам необходимо создать папку data в ней директорию image, в последнею скопировать заранее заготовленные картинки кнопки, картинка должна быть 3-х размеров 64, 32, 16… Готово, картинки загружены, настройка создана. Попробуем запустить:
После выполнения команды запустится firefox с нашим модулем, мы увидим результат это кнопочка с права в верху, и настройка addon.
Обработаем логику кнопки getOauth в настройках расширения, для этого необходимо обработать событие генерируемое кнопкой:
И так по нажатию на кнопку, браузер откроет новую в кладку с яндекс аутентификацией, где мы можем согласиться с разрешениями и получить токен, который скопируем в поле токена в настройках.
Далее, обработаем нажатие кнопки 'make screen' выше, мы указали что обработчиком служит функция makeScreen:
Это функция тривиальна она запускает пакет, с помощью которого делается скриншот выделенной области. Далее запускается функция uploadToYandex с параметром имени файла скриншота.
Эта функция производит запрос с помощью класса Request к api диска. К сожалению не удалось реализовать запрос методом put, он есть в объекте но параметр content принимает либо объект, либо строку и по этому бинарные данные превращаются в строку тела запроса, что приводит к выгрузке битых файлов. Мне пришлось написать свой putRequest с помощью XMLHttpRequest, если кто знает как реализовать с помощью Request пишите в комментариях. Я буду благодарен если кто то поможет привести код к общему знаменателю.
Здесь тоже всё просто, мы открываем файл и создаём поток, который, собственно, и передаём в тело запроса. По документации «диска» мы должны всегда отправлять «Content-Type:application/binary» так и делаем. Всё наш запрос ушол, последним запросом мы публикуем файл publicateFile:
Эта функция отправляет на yandex запрос на публикацию, который возвращает ссылку, для следующего запроса, подтверждения. Второй запрос возвращает объект с информацией о файле, в котором есть ссылка на файл public_url. Если всё успешно открываем вкладку браузера со скриншотом, и в зависимости от настроек, копируем ссылку в буфер обмена…
Когда всё готово и проверена работоспособность расширения нам необходимо собрать его в фаил xpi для этого вводим команду:
Далее проходим регистрацию на addons.mozilla.org и заполняем форму для отправки расширения на модерацию здесь developer hub.
![image](https://habrastorage.org/getpro/habr/post_images/898/d82/c28/898d82c284514520bcda44652a36195e.png)
И на этом мы закончим наше приложение скриншотер разработано и опубликовано в addons.mozilla.org…
» Как всегда, делюсь ссылкой на полный код github.com: firefox-sdk-addons
» Вот и наша, ссылка на расширение habrahabr-screenshoter
Всем спасибо за внимание, и всего доброго.
![image](https://habrastorage.org/getpro/habr/post_images/b1a/1c1/68c/b1a1c168c806a3a063d66a8852d47e85.png)
Должен сразу оговориться, что расширение поддерживается только linux системами и разработана на linux.
И так, с начала мы должны установить пакет jpm в нашу систему, для этого устанавливаем nodejs и npm (если нету):
$ sudo apt-get install nodejs nodejs-legacy npm
После установки node.js и npm устанавливаем jpm с помощью команды:
$ sudo npm install jpm --global
Эта команда установит нам jpm в глобальную область, его так же можно установить локально опустив ключ --global.
Далее нам необходимо создать директорию, для будущего расширения. Давайте назовём его habrscreen:
$ mkdir ~/habrscreen
И инициализируем в этой директории расширение, для этого нам надо перейти в папку и выполнить команду инициализации:
$ cd ~/habrscreen
$ jpm init
После выполнения данной команды, в директории создаётся скелет будущего приложения.
habrscreen
— index.js
— package.json
— test
— test-index.js
Рассмотрим конфигурацию нашего addon package.json:
{
"title": "habrahabr screenshoter",
"name": "habrscreen",
"version": "0.0.1",
"description": "This add-on for make screenshot and upload to yandex disk",
"main": "index.js",
"author": "Roman",
"engines": {
"firefox": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
],
"preferences": [
{
"name": "hClientId",
"title": "client id",
"description": "client id",
"type": "string",
"value": "8fc231e60575439fafcdb3b9281778a3"
},
{
"type": "control",
"label": "get oAuth token",
"name" : "getYaToken",
"title": "Token"
},
{
"description": "oauth token",
"name": "oauthKey",
"type": "string",
"title": "oauth token"
},
{
"description": "automaticaly copy to clipboard",
"title": "autocopy to clipboard",
"name":"autoCopy",
"type":"bool",
"value":true
}
]
}
Что здесь может быть интересного? это тот же манифест только в формате json. Да это так тот же манифест с указанием версии, описанием и имени addons. А так же мы в нём определили настройки нашего модуля пока их будет 4:
1. client id — id клиента yandex oauth
2. get OAuth token — кнопка при клике переходим на яндекс и получаем токен авторизации
3. oauth token — собственно поле для ввода токена
4. autocopy to clipboard — флаг который автоматического копирования ссылки на скриншот в буфер обмена.
После определения настроек нам необходимо подумать о кнопке, при нажатие на которую будет запускаться наш скриншотер. Для этого открываем index.js на редактирование и описываем в нём эту кнопку:
var ui = require('sdk/ui');
var {ActionButton} = require('sdk/ui/button/action');
var button = ui.ActionButton({
id: "mozilla-link",
label: "Make screenshot",
icon: {
"16": "./image/camera16.png",
"32": "./image/camera32.png",
"64": "./image/camera64.png"
},
onClick: makeScreen
});
Код довольно прост, для начала мы импортируем, нужные нам, компоненты sdk, и создаём объект кнопки. Нам необходимо создать папку data в ней директорию image, в последнею скопировать заранее заготовленные картинки кнопки, картинка должна быть 3-х размеров 64, 32, 16… Готово, картинки загружены, настройка создана. Попробуем запустить:
$ jpm run
После выполнения команды запустится firefox с нашим модулем, мы увидим результат это кнопочка с права в верху, и настройка addon.
Обработаем логику кнопки getOauth в настройках расширения, для этого необходимо обработать событие генерируемое кнопкой:
var sp = require("sdk/simple-prefs");
sp.on("getYaToken", function () {
tabs.open('https://oauth.yandex.ru/authorize'
+ '?response_type=token'
+ '&client_id='
+ require('sdk/simple-prefs').prefs['hClientId']);
});
И так по нажатию на кнопку, браузер откроет новую в кладку с яндекс аутентификацией, где мы можем согласиться с разрешениями и получить токен, который скопируем в поле токена в настройках.
Далее, обработаем нажатие кнопки 'make screen' выше, мы указали что обработчиком служит функция makeScreen:
/**
* click to button screenshot
* @param state
*/
function makeScreen(state)
{
var date = new Date();
var fileScreen = date.getTime().toString() + '_screen.png';
var args = ["-s", "/tmp/" + fileScreen];
system(
'/usr/bin/scrot',
args
);
uploadToYandex(fileScreen);
}
Это функция тривиальна она запускает пакет, с помощью которого делается скриншот выделенной области. Далее запускается функция uploadToYandex с параметром имени файла скриншота.
/**
* upload screenshot to yandex
* @param name
*/
function uploadToYandex(name) {
var Request = require('sdk/request').Request;
const fileIO = require("sdk/io/file");
Request({
url: "https://cloud-api.yandex.net/v1/disk/resources/upload?path=" + name,
headers: getHeaders(),
onComplete: function (response) {
var result = JSON.parse(response.text);
if (result.method == "PUT") {
putRequest(result.href, '/tmp/' + name);
// publicate file
publicateFile(name);
}
}
}).get();
}
Эта функция производит запрос с помощью класса Request к api диска. К сожалению не удалось реализовать запрос методом put, он есть в объекте но параметр content принимает либо объект, либо строку и по этому бинарные данные превращаются в строку тела запроса, что приводит к выгрузке битых файлов. Мне пришлось написать свой putRequest с помощью XMLHttpRequest, если кто знает как реализовать с помощью Request пишите в комментариях. Я буду благодарен если кто то поможет привести код к общему знаменателю.
/**
* put request to yandex api
* @param url
* @param file
*/
function putRequest(url, file) {
const {Cc, Ci} = require("chrome");
// Make a stream from a file.
var stream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
var fileIo = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
fileIo.initWithPath(file);
stream.init(fileIo, 0x04 | 0x08, 0644, 0x04); // file is an nsIFile instance
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open('PUT', url, false);
req.setRequestHeader('Content-Type', "application/binary");
req.send(stream);
}
Здесь тоже всё просто, мы открываем файл и создаём поток, который, собственно, и передаём в тело запроса. По документации «диска» мы должны всегда отправлять «Content-Type:application/binary» так и делаем. Всё наш запрос ушол, последним запросом мы публикуем файл publicateFile:
/**
* publicate file on yandex disk
* @param name
*/
function publicateFile(name) {
var Request = require('sdk/request').Request;
var result;
Request({
url: "https://cloud-api.yandex.net/v1/disk/resources/publish?path=" + name,
headers: getHeaders(),
onComplete: function (responsePublic) {
result = JSON.parse(responsePublic.text);
if (result.method == "GET") {
Request({
url: result.href,
headers: getHeaders(),
onComplete: function (resp) {
result = JSON.parse(resp.text);
if (require('sdk/simple-prefs').prefs['autoCopy']) {
var clipboard = require("sdk/clipboard");
clipboard.set(result.public_url);
}
tabs.open(result.public_url);
}
}).get();
}
}
}).put();
}
Эта функция отправляет на yandex запрос на публикацию, который возвращает ссылку, для следующего запроса, подтверждения. Второй запрос возвращает объект с информацией о файле, в котором есть ссылка на файл public_url. Если всё успешно открываем вкладку браузера со скриншотом, и в зависимости от настроек, копируем ссылку в буфер обмена…
Когда всё готово и проверена работоспособность расширения нам необходимо собрать его в фаил xpi для этого вводим команду:
$ jpm xpi
Далее проходим регистрацию на addons.mozilla.org и заполняем форму для отправки расширения на модерацию здесь developer hub.
![image](https://habrastorage.org/getpro/habr/post_images/898/d82/c28/898d82c284514520bcda44652a36195e.png)
И на этом мы закончим наше приложение скриншотер разработано и опубликовано в addons.mozilla.org…
» Как всегда, делюсь ссылкой на полный код github.com: firefox-sdk-addons
» Вот и наша, ссылка на расширение habrahabr-screenshoter
Всем спасибо за внимание, и всего доброго.
Поделиться с друзьями
Комментарии (12)
hurtavy
27.09.2016 11:48Нам необходимо создать папку data, и в неё скопировать заранее заготовленные картинки кнопки
Не data, а image
Ну и использовать JSON ради одной только parse…lnroma
27.09.2016 11:49The data object is used to access data that was bundled with the add-on. This data lives in the add-on's data/ directory, immediately below the package.json file. All files in this directory will be copied into the XPI and made available through the data object.
hurtavy
27.09.2016 13:16Нам необходимо создать папку data, и в неё скопировать заранее заготовленные картинки кнопки
при этом в кодеicon: {
"16": "./image/camera16.png",
"32": "./image/camera32.png",
"64": "./image/camera64.png"
}
Gitkan
27.09.2016 11:49Автор обратил внимание на интересную проблему. Под Убунтой c Firefox 49 jpm run работает — только что проверял. А вот неделю назад при попытке запустить jpm run под Windows 10 c Firefox 48 выдавалось следующее:
и запускался Firefox без расширения. Как я понимаю, это связано с тем, что начиная с 48й версии в обыкновенной сборке (не ночной, не Unbranded Build) Firefox нельзя устанавливать не подписанные расширения. Оказывается, это ограничение распространяется только на windows-сборки.WARN Add-on @testaddon is not correctly signed.
Methos
27.09.2016 13:24После выполнения команды запуститься firefox с нашим модулем
запустится — без мягкого (что сделает)
botaniQQQ
Потёрто.
PS: Не прочитал текст под картинкой.
lnroma
У вас linux?
botaniQQQ
Какая особенность у расширения не даёт установить на Win?
lnroma
программа scrot которую он использует +пути к файлам.