<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Форум Firefox OS - русскоязычный форум по Firefox ОС — Разработка приложения для Firefox OS на реальном примере]]></title>
		<link>https://firefoxforum.ru/viewtopic.php?id=92</link>
		<atom:link href="https://firefoxforum.ru/extern.php?action=feed&amp;tid=92&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[The most recent posts in Разработка приложения для Firefox OS на реальном примере.]]></description>
		<lastBuildDate>Tue, 13 May 2014 20:38:17 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Разработка приложения для Firefox OS на реальном примере]]></title>
			<link>https://firefoxforum.ru/viewtopic.php?pid=321#p321</link>
			<description><![CDATA[<p>Активный участник нашего форума, юзер<br />Vladimir Sinotov<br />поделился ссылкой на полезную статью на Хабрахабре, я же для удобства скопирую её сюда:<br />Мобильные приложения созданные с помощью веб-технологий понемногу захватывают мир. Но создание таких приложений, под популярные платформы, связанны с кучей проблем — от неизвестных истории багов, зоопарка размеров экрана, до проблем с производительностью, которые не решаются просто переписыванием тонких мест.<br />Но к счастью, этот топик не будет наполнен обыденной трагедией разработки, подобных приложений. Поскольку сегодня, я покажу на реальном примере, как разрабатывать приложения под Firefox OS, которая поддерживает большую часть современных веб-технологий, и вообще говоря создана для них и благодаря им.<br />Рецепт<br />Для приготовления нам понадобиться:<br />0) Апи какого-нибудь сервиса, в нашем случае это ФотоФания (не сочтите за рекламу).<br />1) Angular js — в качестве основы<br />2) buildingfirefoxos.com/building-blocks/ — заготовки ui-блоков<br />3) jQuery и прочие либы по вкусу<br />0) Апи<br />Поскольку хочется показать реальное приложение, то и апи надо использовать реальное. ФотоФания это сайт с помощью которого из своих скучных сэлфи можно создать веселые фоточки. Так что нам, немного, придется работать с изображениями на клиенте (хотя основная работа будет происходить на сервере, разумеется).<br />1) Angular js<br />Angular хорош. Конечно у меня есть притенении к нему, с точки зрения производительности на мобильных девайсах, но он позволяет отстранится от рутинного кода, обновлений элементов и прочего, занимаясь только данными. Кроме того, приложение на Angular без особых усилий получается отлично структурированным.<br />2) Building Blocks<br />Building Blocks — это готовые элементы дизайна, взятые (частично) из исходников Gaia — UI прослойки Firefox OS. Эти заготовки не используют js, вся логика, которая там есть, реализована через псевдо-селекторы. При этом, весь код написан с помощью html5 элементов, и использует data-* атрибуты для обозначения роли блока.<br />Еще я заметил важную вещь — код Building Blocks работает быстрее и плавнее чем код, который я написал сам, как бы я не старался. По крайней мере, это касается списков. Возможно определённые элементы ускоряются нативно — не уверен насколько это правда. Так что по возможности пользуйтесь заготовками — они ускоряют разработку, делают приложение похожим на нативное и делают его плавнее.<br />3) jQuery и прочие<br />Вообще говоря, я бы с радостью избавился от jQuery, но он является зависимостью плагина для пинч-зума github.com/segdeha/jquery-pan-zoom. Подсадить плагин на Zepto не получилось. К счастью jQuery можно билдить из тех кусков которые вам нужны. Поэтому я беспощадно избавился от SIzzle и прочих ненужных в быту вещей.<br />Немного о структуре<br />Структуру приложения каждый использует какую хочет. В моем случае она похожа на<br />/build/ /build.js /build.css /scripts/ /vendors/ /controllers/ /services/ /.../ /app.js /dictionary.js /config.js /styles/ /helpers/ /variables.less /mixins.less /main.less /header.less /... /images/ index.html<br />Скрипты и стили билдятся с помощью grunt в реальном времени. А grunt release уже все минифицирует. Так же я использую grunt-angular-templates который все шаблоны превращает в js код, который так же добавляется в build.js<br />Первоначальная разметка страницы<br />&lt;!doctype html&gt; &lt;html ng-app=&quot;PhotoFunia&quot; ng-csp&gt; &lt;head&gt; &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no&quot;&gt; &lt;meta charset=&quot;UTF-8&quot;&gt; &lt;title&gt;PhotoFunia&lt;/title&gt; &lt;link rel=&quot;stylesheet&quot; href=&quot;build/build.css&quot;/&gt; &lt;/head&gt; &lt;body role=&quot;application&quot;&gt; &lt;!-- Прелоадер, который показывается при старте. Я не выношу его в отдельный файл, в надежде что так будет быстрее--&gt; &lt;section ng-controller=&quot;PreloaderController&quot;&gt; &lt;div id=&quot;preloader&quot; ng-hide=&quot;preloaderHide&quot;&gt; &lt;div class=&quot;preloader-content&quot;&gt; &lt;div class=&quot;logo&quot;&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/section&gt; &lt;!-- Это наш дроуэр (меню) которое будет выдвигаться слева --&gt; &lt;section data-type=&quot;sidebar&quot; ng-include=&quot;VIEWS.DRAWER&quot;&gt;&lt;/section&gt; &lt;!-- Это наш контент. Не знаю почему у него id=&quot;drower&quot; так нам сказал building blocks --&gt; &lt;section id=&quot;drawer&quot; role=&quot;region&quot; ng-view ng-class=&quot;{&#039;menu-opened&#039;: drawerOpened}&quot;&gt;&lt;/section&gt; &lt;!-- Это своеобраный toast для FF OS. http://buildingfirefoxos.com/building-blocks/status.html --&gt; &lt;section role=&quot;status&quot; ng-controller=&quot;ToastController&quot;&gt; &lt;p ng-if=&quot;text&quot; ng-bind=&quot;text&quot;&gt;&lt;/p&gt; &lt;/section&gt; &lt;!-- Тут скрывается универсальный код для попапов --&gt; &lt;section ng-include=&quot;VIEWS.POPUP&quot;&gt;&lt;/section&gt; &lt;script src=&quot;build/build.js&quot;&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt;<br />Важно<br />Думаю некоторые заметили ng-csp в элементе. Эта директива включает поддержку Content Security Policy — и это является обязательным, для создания приложения для Firefox OS. Кроме того, нам надо немного пропатчить сам angular!<br />Ищем в коде angular строчку window.XMLHttpRequest(); и заменяем на window.XMLHttpRequest({mozSystem: true});<br />А так же нам надо добавить руками в наши стили — вспомогательные стили angular.js. А именно — code.angularjs.org/1.2.16/angular-csp.css<br />Немного о js<br />Надо заметить, что я изначально пишу код на coffeescript, но буду вам показывать его javascript аналог. Возможно где-то всплывут неточности — тогда мы вместе их исправим.<br />Еще я надеюсь, что вы знакомы с angular и js достаточно хорошо, чтобы мне не останавливаться на каждом шагу. Иначе эту статью никто никогда в жизни не дочитает.<br />Мультиязычность<br />Наше приложение будет мультиязычным. Поэтому нам требуется словарь, его интерпретатор и какая-нибудь директива или фильтр, чтобы вставлять слова в код. Часто когда речь заходит об мультиязычности с помощью angular — всплывают какие-то фильтры, которые выглядят не очень приятно. Например нам предлагают писать так &lt;div ng-bind=&quot;&#039;header_search_title&#039; | l10n&quot;&gt;&lt;/div&gt; меня это немного корежит — зачем вызывать каждый раз лишнюю функцию и писать такой неудобный код, если можно просто использовать словарь в глобал-скоупе, и обращаться к нему? Например так &lt;div ng-bind=&quot;m.header.search.title&quot;&gt;&lt;/div&gt;. За всё время моей работы, такой способ меня не подводил. Давайте же его и реализуем.<br />Хочется чтобы он был любой вложенностью, поддерживал любое количество языков. Без проблем!<br />var DICTIONARY = { header: { search: { title: { ru: &#039;Поиск&#039;, en: &#039;Search&#039; }, favorites: { ru: &#039;Избранное&#039;, en: &#039;Favorites&#039; } } }, cancel: { ru: &#039;Отмена&#039;, en: &#039;Cancel&#039; } };<br />Структура есть, теперь, чтобы не обращаться напрямую переменной (а не языку), надо написать небольшой парсер.<br />App.run([&#039;$rootScope&#039;, function ($rootScope) { var lang = &#039;ru&#039;; // тут должна быть какая-то логика <img src="https://firefoxforum.ru/img/smilies/smile.png" width="15" height="15" alt="smile" /> $rootScope.m = (function() { var parse = function(obj, result) { result = result || {}; for (var key in obj) { var value = obj[key]; if (typeof value !== &quot;object&quot;) return obj[lang]; result[key] = parse(value); } return result; }; return parse(DICTIONARY); })(); }]);<br />То есть мы просто рекурсивно доходим, до того момента, когда значение переменной становится не объектом, и возвращаем значение с нужным языком. Все просто, и теперь у нас есть переменная m в рут-скоупе, к которой мы можем смело обращаться.<br />Кто-то наверняка засомневается в производительности такого решения, но могу вас уверить, что это капля в море. И вообще вам никто не мешает написать директиву, которая не будет вешать ватчер на переменную. Так что все в порядке.<br />Вернемся к разметке<br />Давайте доделаем drawer (Меню). Допустим у нас есть уже основа в виде js. Есть контроллер который обслуживает наше меню, и мы уже получили с помощью апи список категорий, которые будем выводить в меню. Тогда код меню получается очень простым.<br />Как видно, в своей разметке index.html мы уже использовали часть кода из Building Blocks. Сейчас мы возьмем код Drawer&#039;a и немного изменим под себя. buildingfirefoxos.com/building-blocks/drawer.html<br />&lt;nav ng-controller=&quot;DrawerController&quot;&gt; &lt;div class=&quot;empty-space&quot;&gt;&lt;/div&gt; &lt;ul&gt; &lt;li&gt; &lt;a ng-click=&quot;go(&#039;/favorites&#039;); closeDrawer()&quot;&gt; &lt;span class=&quot;text&quot; ng-bind=&quot;m.menu.favorite&quot;&gt;&lt;/span&gt; &lt;span class=&quot;counter&quot; ng-bind=&quot;favorite.get().length&quot;&gt;&lt;/span&gt; &lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;h2 ng-bind=&quot;m.category.title&quot;&gt;&lt;/h2&gt; &lt;ul&gt; &lt;li ng-repeat=&quot;cat in categories&quot;&gt; &lt;a ng-click=&quot;openCategory(cat.key)&quot;&gt; &lt;span class=&quot;text&quot; ng-bind=&quot;cat.title&quot;&gt;&lt;/span&gt; &lt;span class=&quot;counter&quot; ng-bind=&quot;cat.count&quot;&gt;&lt;/span&gt; &lt;span class=&quot;new-counter&quot; ng-if=&quot;cat.new_count&quot; ng-bind=&quot;&#039;+&#039;+cat.new_count&quot;&gt;&lt;/span&gt; &lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;/nav&gt;<br />Как видно у нас два списка в меню, в самом верхнем лежит только одна ссылка на избранное (заметили что мы уже используем нашу переменную m?), там же выводится кол-во избранных фотоэффектов, сбоку. Ниже у нас, собственно, сам список категорий.<br />И для полноты картины сделаем еще одну страницу — список эффектов, то есть страница категории.<br />buildingfirefoxos.com/building-blocks/headers.html — тут берем хедеры<br />buildingfirefoxos.com/building-blocks/lists.html — тут списки<br />buildingfirefoxos.com/building-blocks/filters.html — тут фильтры (табы)<br />buildingfirefoxos.com/building-blocks/buttons.html — а тут кнопочки<br />И получаем, упрощенно, что-то такое:<br />&lt;!-- Наш хедер, собсвенной персоной --&gt; &lt;header&gt; &lt;menu type=&quot;toolbar&quot;&gt; &lt;!-- Кнопочка для поиска --&gt; &lt;a ng-click=&quot;go(&#039;/search&#039;)&quot;&gt; &lt;span class=&quot;icon action-icon search&quot;&gt;&lt;/span&gt; &lt;/a&gt; &lt;/menu&gt; &lt;!-- Две кнопки для открытия / закрытия меню (drawer) --&gt; &lt;a ng-click=&quot;closeDrawer()&quot;&gt;&lt;span class=&quot;icon icon-menu&quot;&gt;&lt;/span&gt;&lt;/a&gt; &lt;a ng-click=&quot;openDrawer()&quot;&gt;&lt;span class=&quot;icon icon-menu&quot;&gt;&lt;/span&gt;&lt;/a&gt; &lt;h1 ng-bind=&quot;category.title&quot;&gt;&lt;/h1&gt; &lt;/header&gt; &lt;div role=&quot;main&quot; data-type=&quot;list&quot; id=&quot;category&quot;&gt; &lt;!-- Табы, которые устанавливают сортировку эффектов --&gt; &lt;ul role=&quot;tablist&quot; data-type=&quot;filter&quot; data-items=&quot;2&quot;&gt; &lt;li role=&quot;tab&quot; aria-selected=&quot;{{ sorting === &#039;new&#039;}}&quot;&gt; &lt;a ng-click=&quot;setSorting(&#039;new&#039;)&quot; text=&quot;m.category.new&quot;&gt;&lt;/a&gt; &lt;/li&gt; &lt;li role=&quot;tab&quot; aria-selected=&quot;{{ sorting === &#039;popular&#039;}}&quot;&gt; &lt;a ng-click=&quot;setSorting(&#039;popular&#039;)&quot; text=&quot;m.category.popular&quot;&gt;&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;!-- И наши эффекты собственной персоной --&gt; &lt;ul class=&quot;effects&quot;&gt; &lt;li ng-repeat=&quot;effect in effects&quot; ng-click=&quot;openEffect(effect.key)&quot;&gt; &lt;aside class=&quot;pack-end&quot;&gt; &lt;img ng-src=&quot;{{CONFIG.DOMAIN + effect.icon}}&quot;&gt; &lt;/aside&gt; &lt;a&gt; &lt;p ng-bind=&quot;effect.title&quot;&gt;&lt;/p&gt; &lt;p ng-if=&quot;effect.labels&quot;&gt; &lt;span ng-repeat=&quot;label in effect.labels&quot; ng-class=&quot;label&quot; class=&quot;label&quot;&gt;&lt;/span&gt; &lt;/p&gt; &lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;!-- Кнопочка для подгрузки эффектов --&gt; &lt;div class=&quot;load-more&quot; ng-if=&quot;isNeedMore &amp;&amp; effects.length&quot;&gt; &lt;button ng-click=&quot;showMore()&quot; text=&quot;m.category.show_more&quot;&gt;&lt;/button&gt; &lt;/div&gt; &lt;/div&gt;<br />Надеюсь все понятно. А понять надо следущее — мы берем готовые блоки и вырезаем из них самое нужное нам. Ими можно крутить и вертеть как угодно.<br />Таким же образом делаются все остальные страницы.<br />Об API Firefox OS<br />В приложениях Firefox OS версии &gt;= 1.3 input[file] работать не будет, в замен его, нам предлагают пользоваться MozActivity. Что даже упрощает работу.<br />Вот так выглядит получение картинки:<br />var pick = new MozActivity({ name: &quot;pick&quot;, data: { type: [&quot;image/*&quot;], nocrop: true } }); pick.onsuccess = function() { var blob = pick.result.blob; // что-то делаем с блобом };<br />Вот так шеринг:<br />[url]new MozActivity({<br />name: &quot;share&quot;,<br />data: {<br />type: &quot;image/*&quot;,<br />number: 1,<br />blobs: [blob]<br />}<br />});[/url]<br />И примерно так — сохранение:<br />var sdcard = navigator.getDeviceStorage(&quot;sdcard&quot;); var request = sdcard.addNamed(blob, name); request.onsuccess = function() {}; request.onerror = function() {};<br />После того, как приложение готово, его надо сбилдить и протестировать.<br />Чтобы билдить — можно использовать эмуляторы.<br />Я вам предлагаю использовать Менеджер приложений, который встроен по умолчанию в новые версии firefox. developer.mozilla.org/ru/docs/Mozilla/F … pp_Manager. Тут же можно устанавливать разные версии эмуляторов, подключать девайсы и дебажить! Что очень удобно.<br />Так же нам нужен манифест приложения. Выглядит и пишется он очень просто.<br />Приведу пример:<br />{ &quot;name&quot;: &quot;PhotoFunia&quot;, &quot;description&quot;: &quot;PhotoFunia is the best way to add a spark to your photos, make them special and more original.&quot;, &quot;launch_path&quot;: &quot;/index.html&quot;, &quot;version&quot; : &quot;1&quot;, &quot;type&quot;: &quot;privileged&quot;, &quot;developer&quot;: { &quot;name&quot;: &quot;&quot;, &quot;email&quot; : &quot;&quot; }, &quot;default_locale&quot;: &quot;en&quot;, &quot;icons&quot;: { &quot;256&quot;: &quot;/images/app_icon_256.png&quot; }, &quot;permissions&quot;: { &quot;device-storage:pictures&quot;: { &quot;description&quot;: &quot;Save result images&quot;, &quot;access&quot;: &quot;readwrite&quot; }, &quot;device-storage:sdcard&quot;: { &quot;description&quot;: &quot;Save result images&quot;, &quot;access&quot;: &quot;readwrite&quot; }, &quot;mobilenetwork&quot;: { &quot;description&quot;: &quot;Check for available connection&quot; }, &quot;systemXHR&quot;: { &quot;description&quot;: &quot;Need for internet connection&quot; } } }<br />Собственно говоря, засовываем все нужные файлы в .zip архив и отправляем в marketplace.firefox.com на проверку. Через пару дней (а может и к вечеру) приложение появится в маркете!<br />Что это было?<br />Я хотел донести до вас, что разработка под Firefox OS это очень просто, интересно и весело! Конечно, пока что, на этом денег не заработать. Но можно подумать, мы здесь ради денег собрались. Так что, берите IDE в руки, и создавайте приложения под Firefox OS!<br />Тем, лучшим из нас, у кого есть девайс на Firefox OS — прошу к столу marketplace.firefox.com/app/photofunia/<br />Отсюда</p>]]></description>
			<author><![CDATA[null@example.com (admin)]]></author>
			<pubDate>Tue, 13 May 2014 20:38:17 +0000</pubDate>
			<guid>https://firefoxforum.ru/viewtopic.php?pid=321#p321</guid>
		</item>
	</channel>
</rss>
