Рассказываем, что такое Аврора ОС, откуда появилась и где пригодится. Разберемся, что нужно для разработки под эту ОС, и установим необходимые для этого инструменты. На примере двух простых приложений рассмотрим, как можно разрабатывать приложения для Авроры.
Что такое Аврора ОС и ОМП
Аврора ОС — это российская операционная система для мобильных устройств. Она основана на финской системе Sailfish OS. У компании Jolla, которая занималась Sailfish, в 2015 году возникли финансовые проблемы, и проект перешел под крыло российских инвесторов. В 2016-м к Jolla присоединилась компания «Открытая мобильная платформа» (ОМП), получившая права на разработку и использование Sailfish OS. Так появилась Sailfish Mobile OS RUS. Спустя два года проектом заинтересовался Ростелеком и приобрел в нем значительную долю, а также контроль в компании Jolla. В 2019-м году Sailfish Mobile OS RUS сменила название на Аврора.
Где используется Аврора
Аврора уже устанавливается на целый ряд устройств, среди которых представлены как смартфоны, так и планшетные компьютеры. Список устройств можно посмотреть на этом сайте. Приложений для этой ОС на данный момент выпущено не так много, но уже есть мессенджеры, браузеры, несколько игр и даже фитнес-трекер. Весь список приложений можно увидеть здесь. Аврора позиционирует себя как сервис для корпоративного использования в крупных компаниях, где важна безопасность и стабильность ПО. Также это позволяет бизнесу обезопасить себя от сбоев в случае ухода зарубежных сервисов.
Приложения под Аврора ОС пишут на языке QML. Он нужен для описания графического интерфейса пользователя. Компоненты GUI (кнопки, поля ввода, текстовые метки, выпадающие списки и тому подобное) можно взять из библиотеки Sailfish.Silica. Логику приложения программируют на C++ и JavaScript. Также недавно появилась возможность писать приложения под эту ОС на Flutter.
Установка инструментов разработки
Чтобы создавать приложения, программисты из компании ОМП сделали среду разработки Aurora IDE. Она основана на Qt Creator и содержит все необходимое, чтобы писать программы под ОС Аврора.
Для начала эту среду необходимо скачать. Сделать это можно здесь. Выбираем версию для своей операционной системы и загружаем файл установщика. Если у вас на компьютере не установлена система виртуализации в виде VirtualBox или Docker, то мастер установки не сможет продолжить свою работу и предложит сначала установить ПО для виртуализации и вернуться к установке среды позднее.
Я скачал VirtualBox отсюда и продолжил установку IDE. Дальше просто нажимаем несколько раз на кнопку «Далее», соглашаемся с лицензионным соглашением и завершаем установку. Подробнее можно посмотреть здесь.
Пишем онлайн-радио для Аврора ОС
После установки среды можно приступать к созданию первого проекта. Открываем Aurora IDE и запускаем мастер создания проекта. Для этого на главной странице нажимаем на соответствующую кнопку. Вводим название проекта (radio). Проходим все остальные этапы, предлагаемые мастером, и получаем готовый шаблон. Подробнее о первоначальной настройке проекта можно прочитать в официальном руководстве.
Вот так выглядит окно IDE с открытым шаблоном проекта:
В левой панели разворачиваем дерево файлов проекта и находим в папке QML файл MainPage.qml. В этом файле и будет находиться код нашего приложения. Весь исходный код радио можно найти в этом репозитории.
Интерфейс
Для начала займемся интерфейсом программы. Его главным компонентом будут кнопки. Располагаем шесть штук в виде вертикального ряда. На каждой кнопке пишем название станции. При нажатии на кнопку эта станция должна воспроизводиться.
Сразу огорчу всех любителей визуальных конструкторов, при помощи которых можно за пару минут сделать простенький интерфейс. Здесь такого нет. Все приходится писать кодом. Вот так выглядит код для кнопок в самой IDE:
Для кнопок используется следующий код:
Button { id: deepHouse anchors.horizontalCenter: parent.horizontalCenter text: "1.FM - Deep House" onClicked: playDeepHouse() }
Подобных фрагментов нужно шесть. Также нужны две текстовые метки над кнопками. В верхней метке отображается название радиостанции, а в нижней — название текущей трансляции. Вот код этих меток:
Label { id: heading anchors.horizontalCenter: parent.horizontalCenter font.family: Theme.fontSizeExtraLarge } Label { id: metaDataTitle anchors.horizontalCenter: parent.horizontalCenter }
Метки и кнопки упаковываем все вместе при помощи контейнера Column, который располагает компоненты в один ряд по вертикали:
Column { id: mainColumn width: parent.width spacing: Theme.paddingLarge //здесь должен находиться код для компонентов }
Для остановки воспроизведения нужна отдельная кнопка в заголовке окна приложения. В качестве заголовка применяем PageHeader, и в нем уже есть одна кнопка, при нажатии на которую открывается страница с информацией о приложении. Чтобы добавить в PageHeader еще одну кнопку, используем контейнер Row. В отличие от Column, этот контейнер упаковывает компоненты по горизонтали. Вот код для наших кнопок:
Row { IconButton { objectName: "aboutButton" icon.source: "image://theme/icon-m-about" anchors.verticalCenter: parent.verticalCenter onClicked:pageStack.push(Qt.resolvedUrl("AboutPage.qml")) } IconButton { objectName: "stopButton" icon.source: "image://theme/icon-l-stop" anchors.verticalCenter: parent.verticalCenter onClicked: onStopClicked() } }
В заголовке используем не обычные кнопки (Button), а специальные IconButton, которые отображаются в виде иконки, прописанной в коде кнопки. Теперь займемся логикой.
Логика
Логика здесь написана на языке JavaScript. При нажатии на кнопку станции вызывается соответствующая функция. Вот пример функции playDeepHouse:
function playDeepHouse(){ heading.text = deepHouse.text metaDataTitle.text = "" player.stop() player.source = "http://strm112.1.fm/deephouse_mobile_mp3" player.play() }
Не забываем о том, что нужна кнопка для остановки воспроизведения. С ней связана вот эта функция:
function onStopClicked(){ player.stop() heading.text = "Stopped" metaDataTitle.text = "" }
В функциях для воспроизведения потока радиостанции используется объект player. Он создается таким образом:
MediaPlayer { id: player metaData.onMetaDataChanged: metaDataTitle.text = player.metaData.title }
Изменения метаданных в потоке вещания отслеживаются с помощью metaData.onMetaDataChanged. Заголовки трансляций добываются при помощи player.metaData.title и отображаются в метке metaDataTitle. Чтобы использовать MediaPlayer, нужно сначала произвести импорт модуля QtMultimedia. Делается это в самом начале исходника в секции импортов:
import QtQuick 2.0 import Sailfish.Silica 1.0 import QtMultimedia 5.6
Пожалуй, все готово к запуску проекта. О запуске приложений поговорим в последнем разделе этой статьи.
Калькулятор индекса массы тела
Это простое приложение позволяет определять ИМТ на основе данных о весе, росте, окружности запястья и половой принадлежности пользователя. Расчеты производятся по несколько модифицированной формуле Кетле с учетом пола и индекса Соловьева. Репозиторий с исходниками программы можно найти здесь. Код, так же как и в прошлом примере, находится в файле MainPage.qml. Начнем с интерфейса.
Интерфейс
Для ввода данных потребуются три специальных поля. Для выбора пола применим выпадающий список, а для вывода результатов будем использовать текстовые метки. Также нам потребуется обычная кнопка, при нажатии на которую все введенные данные будут обрабатываться, а в метках, по окончании всех вычислений, отобразится результат работы программы. Вот так выглядит запущенное приложение:
Для полей ввода используется следующий код:
TextField { id: weight focus: true inputMethodHints: Qt.ImhFormattedNumbersOnly label: qsTrId("введите вес в кг") EnterKey.iconSource: "image://theme/icon-m-enter-next" EnterKey.onClicked: height.focus = true }
Как видим, поле позволяет вводить только числа. Об этом говорит значение свойства inputMethodHints. Также для клавиши ввода устанавливаем иконку «Далее», при нажатии на которую фокус передается следующему полю. Для выпадающего списка применен такой код:
ComboBox { id: combo label: qsTrId("Выберите пол:") currentIndex: 0 menu: ContextMenu { MenuItem { text: qsTrId("мужской") } MenuItem { text: qsTrId("женский") } } }
Значение свойства currentIndex указывает на то, что по умолчанию в выпадающем списке будет отображен первый пункт. Код для кнопки не отличается какими-либо особенностями:
Button { id: calculateButton anchors.horizontalCenter: parent.horizontalCenter text: "ВЫЧИСЛИТЬ" onClicked: onCalculateClicked() }
При нажатии на кнопку будет вызвана указанная функция. О ней мы поговорим позднее. В программе используются три текстовые метки:
Label { id: result1 anchors.horizontalCenter: parent.horizontalCenter } Label { id: result2 anchors.horizontalCenter: parent.horizontalCenter } Label { id: result3 anchors.horizontalCenter: parent.horizontalCenter }
В каждой метке выводится свой тип результата вычислений. Все компоненты интерфейса упаковываем в контейнер Column, чтобы расположить их в виде вертикального ряда. Теперь настало время рассмотреть логику приложения.
Логика
Как и в прошлом примере, логика здесь написана на JavaScript. Главная функция, которая вызывается нажатием на кнопку «Вычислить», выглядит следующим образом:
function onCalculateClicked(){ var h=Number(height.text); var w=Number(weight.text); var c=Number(circle.text); if (isNullInField(height.text)||isNullInField(weight.text)||isNullInField(circle.text)){ result1.text = "Заполните все поля!"; result2.text = ""; result3.text = ""; return; } var gen,index,s; if (combo.currentIndex===0){ gen=19; }else{ gen=16; } h=h/100; index=w/(h*h); index=index*(gen/c); if(index<16)s="Дефицит веса"; else if(index>=16&&index<20)s="Недостаточный вес"; else if(index>=20&&index<25)s="Норма"; else if(index>=25&&index<30)s="Предожирение"; else if(index>=30&&index<35)s="Первая степень ожирения"; else if(index>=35&&index<40)s="Вторая степень ожирения"; else s="Морбидное ожирение"; result1.text = somatoType(gen,c) + "\nИМТ="+index.toFixed(2); result2.text = s if(s==="Норма"){ result2.color = "green" }else{ result2.color = "red" } result3.text = normalMassMin(c,h,gen) + "\n" + normalMassMax(c,h,gen); }
Здесь хотелось бы дать некоторые пояснения относительно выводов результата. В метке result1 выводятся тип телосложения и значение ИМТ. Во второй метке (result2) отображается информация о весе. Эта метка может быть окрашена в красный или зеленый цвет в зависимости от того, находится ли вес в пределах нормы или же нет. Третья метка (result3) служит для вывода значений нижнего и верхнего пределов нормального веса. Для вычисления этих пределов существуют такие функции:
function normalMassMin(x,y,z){ var im=x*(y*y)/z; return "Нижний предел нормального веса:\n"+20*im.toFixed(2)+" кг"; } function normalMassMax(x,y,z){ var im=x*(y*y)/z; return "Верхний предел нормального веса:\n"+25*im.toFixed(2)+" кг"; }
Для определения типа телосложения применяется следующая функция:
function somatoType(a,b){ var s=""; var asthenic = "Тип телосложения: астенический"; var normosthenic = "Тип телосложения: нормостенический"; var hypersthenic = "Тип телосложения: гиперстенический"; switch(a){ case 19: if(b<18)s=asthenic; else if(b>=18&&b<=20)s=normosthenic; else s=hypersthenic; break; case 16: if(b<15)s=asthenic; else if(b>=15&&b<=17)s=normosthenic; else s=hypersthenic; break; default: break; } return s; }
Теперь можно поговорить о запуске приложений.
Запуск приложений
Для запуска приложений будем применять эмулятор. После установки среды разработки главное окно программы VirtualBox должно выглядеть примерно так:
Aurora Build Engine — это сборочный движок. С его помощью приложения проходят этапы сборки перед установкой на устройство. AuroraOS-5.0.0.60-base — это виртуальное устройство, на котором запускаются собранные приложения. В запущенном виде оно выглядит приблизительно так:
Чтобы запустить готовое приложение, нужно нажать на кнопку запуска в нижней части левой панели IDE:
Там же можно увидеть кнопки для запуска сборочного движка и эмулятора. Если нажать на зеленый треугольник, то сначала запустится сборочный движок и произойдет сборка приложения, а потом запустится эмулятор, в котором мы должны увидеть запущенное приложение. То есть все должно произойти в автоматическом режиме, но никто не запрещает запускать движок и эмулятор вручную.
Чтобы узнать больше, изучите ресурсы, которые будут полезны для начинающего разработчика. На этой странице можно подробнее познакомиться с модулем Silica. Здесь находятся проекты с открытым исходным кодом, из которых можно почерпнуть для себя много полезного.