Native script (NS) – это библиотека, позволяющая делать кросс-платформенные приложения, используя XML, CSS, JavaScript. Native script решает ту же задачу, что и уже всем известный phonegap (создание кросс-платформенных приложений), но подходы у них разные. Phonegap использует движок браузера, чтобы отобразить ваш UI (фактически вы получаете веб-страницу), Native script использует нативный рендеринг, использует элементы нативного UI. Следующее важное отличие: чтобы получить доступ к камере, gps и так далее в phonegap необходимо устанавливать плагины, в то время как NS дает доступ из коробки.
Стоит подчеркнуть, что приложения можно писать для Android 4.2 и выше, и для iOS 7.1 и выше.
Быстрый старт
Чтобы установить native script, необходим nodejs, поэтому если у вас еще нет его, отправляйтесь сюда. Дальше все просто. Для установки NS в командной строке выполняем:
npm install -g nativescript
Для создания проекта:
tns create MyApp
После того, как проект создался, переходим в директорию проекта:
cd MyApp
И, как и в phonegap, добавляем платформы:
tns platform add android
tns platform add ios
Все готово, чтобы запустить наше первое native script приложение. Для того чтобы сделать это, нужно вести одну из следующих команд:
Запустить на устройстве, подключенном через USB:
tns run android
Запустить в эмуляторе:
tns run android --emulator
Можно также запустить в Genymotion:
tns run android --geny <device name>
В общем, как бы вы не запускали, у вас откроется приложение, которое подсчитывает количество нажатий на кнопку, оставшихся до вывода текста «Hoorraaay! You unlocked the NativeScript clicker achievement!».
Вот сравнение как выглядит приложение на iOS и Android.
Как можно заметить, кнопка везде нативная, хотя код для обоих платформ один и тот же.
Что там внутри?
Структура проекта представлена ниже:
Все, что касается вида приложения, лежит в файле main-page.xml. Всех, кто привык работать с html, ужаснет этот файл, но благо документация очень хорошая, и чуть позже все становится понятнее.
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
<StackLayout>
<Label text="Tap the button" cssClass="title"/>
<Button text="TAP" tap="{{ tapAction }}" />
<Label text="{{ message }}" cssClass="message" textWrap="true"/>
</StackLayout>
</Page>
app.js – точка входа в приложение. В NS используются модули, так же как и nodejs. Думаю, тут все итак понятно.
var application = require("application");
application.mainModule = "main-page";
application.cssFile = "./app.css";
application.start();
main-page.js – содержит код для main-page.xml.
var vmModule = require("./main-view-model");
function pageLoaded(args) {
var page = args.object;
page.bindingContext = vmModule.mainViewModel;
}
exports.pageLoaded = pageLoaded;
Функция pageLoaded будет выполнена, в момент загрузки страницы (см. main-page.xml). Строка page.bindingContext = vmModule.mainViewModel устанавливает binding контекст для данной страницы (что-то наподобие $scope в ангуляр). Ну и последняя строка экспортирует функцию.
Следующий файл, main-view-model.js, позволит подробнее рассмотреть механизм data binding в NS. NS поддерживает two-way и one-way binding.
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var observable = require("data/observable");
var HelloWorldModel = (function (_super) {
__extends(HelloWorldModel, _super);
function HelloWorldModel() {
_super.call(this);
this.counter = 42;
this.set("message", this.counter + " taps left");
}
HelloWorldModel.prototype.tapAction = function () {
this.counter--;
if (this.counter <= 0) {
this.set("message", "Hoorraaay! You unlocked the NativeScript clicker achievement!");
}
else {
this.set("message", this.counter + " taps left");
}
};
return HelloWorldModel;
})(observable.Observable);
exports.HelloWorldModel = HelloWorldModel;
exports.mainViewModel = new HelloWorldModel();
Чтобы dataBinding работал, в NS объект должен выбрасывать событие propertyChange. Это реализовано в классе Observable. В нашем случае он передается в функцию, в которой HelloWorldModel наследует его. Дальше уже через метод set полям присваиваются значения. Функция __extends в самом верху файла служит для осуществления наследования.
Проверим двухсторонний binding в деле. Добавим в main-page.xml две строчки перед тегом .
<TextField text="{{ name }}" hint="введите ваше имя"/>
<Label cssClass="{{name, !!name ? 'title ' : 'title hidden'}}" text="{{ name, 'Hello ' + name }}"/>
В файле main-view-model.js в функцию HelloWorldModel добавим строку:
this.set("name", "");
И наконец в app.css. Стоит подчеркнуть, что поддерживаются далеко не все CSS свойства, полный список можно найти тут.
.hidden {
visibility: collapsed;
}
В итоге получим:
Заключение
Native script для меня, как для веб-разработчика, оставил смешанные чувства. С одной стороны, видно, что авторы старались сделать все близко к вебу (JavaScript, CSS), но с другой, CSS свойства поддерживаются не все, чтобы разобраться с XML приходится постоянно лезть в документацию. Возможно NS решит проблемы, которые есть в phonegap, где то тут, то там появляются какие-то сложности, связанные с веб происхождением приложения. В любом случае, это круто, что появился еще один фреймворк, позволяющим знающим JavaScript писать кросс-платформенные приложения, т.к. на этом рынке становится тесно (phoneGap, Native Script, React Native) и как следствие качество фреймворков должно улучшаться.