PhoneGap

плюсы, минусы, подводные камни

Андреев Артем

ЧТО ЭТО ТАКОЕ?!

PhoneGap - бесплатный open-source, созданный Nitobi Software. Позволяет создать приложения для мобильных устройств используя JavaScript, HTML5 и CSS3, без необходимости знания «родных» языков

Немного истории

2009 - создан внутри канадского стартапа Nitobi

2011 - Adobe приобрели Nitobi и все права на PhoneGap

 

В чем разница?

- Cordova это OpenSource, а PhoneGap принадлежит Adobe

 

- Кроме разных имен пакетов, у PhoneGap и Cordova, разная документация

 

- При выходе новых версий ОС , Cordova обновляется быстрее, чем PhoneGap

 

- У Cordova нет облачного сборщика проектов

Возможности

- кросплатфоменность

 

- доступ к низкоуровневому API, с помощью простых плагинов

 

- компиляция вашего HTML5 в готовые приложения без головной боли поддержки нативных SDK

 

- паутина из рук

 

- гибкость  WEB приложений

Как сварить суп при помощи phoneGAP?!

1. инициализируем проект

 

2. пишем код

 

3. тестируем

 

3. собираем

Инициализация

phonegap create path/to/myApp

вариант 1

вариант 2

Структура приложения

• platforms – включает в себя раздельный код под каждую из используемых платформ

• plugins – это плагины

• www – веб-приложение на основе веб технологий

• config.xml – файл должен находиться в корневой папке проекта при локальной сборке. Он включает в себя ссылки на ресурсы приложения, устанавливает необходимые разрешения и настраивает параметры для каждой из платформ

 

Нарежем разметки

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8" />
    <meta name="format-detection" content="telephone=no" />
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
    <link rel="stylesheet" type="text/css" href="css/style.css" />
    <title>Погодка в Пензе</title>
</head>
<body>
    <div class="page">
        <div class="city" id="city-name"></div>
        <div class="current-weather" id="day0">
            <div class="current-weather__temperature temperature"></div>
            <i class="weather-icon"></i>
            <span class="weather__description"></span>
            <span class="date"></span>
        </div>
        <div class="weather-forecast">
            <div class="day" id="day1">
                <span class="temperature"></span>
                <i class="weather-icon"></i>
                <span class="weather__description"></span>
                <span class="date"></span>
            </div>
            <div class="day" id="day2">
                <span class="temperature"></span>
                <i class="weather-icon"></i>
                <span class="weather__description"></span>
                <span class="date"></span>
            </div>
            <div class="day" id="day3">
                <span class="temperature"></span>
                <i class="weather-icon"></i>
                <span class="weather__description"></span>
                <span class="date"></span>
            </div>
        </div>
    </div>
    <script type="text/javascript" src="cordova.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
    <script type="text/javascript" src="js/app.js"></script>
    <script type="text/javascript">
        app.initialize();
        getWeather();
    </script>
</body>
</html>

Подкинем стилей

* {
    margin: 0;
    padding: 0;
}

html {
    font-size: 10px;
}

@media screen and (max-width: 768px) {
    html {
        font-size: 9px;
    }
}

@media screen and (max-width: 640px) {
    html {
        font-size: 8px;
    }
}

@font-face {
    font-family: Roboto;
    src: url(../font/Roboto-Regular.ttf);
}

body {
    font-family: Roboto, arial;
    font-size: 1.6rem;
    font-weight: 400;
    background-color: #fff;
}

.page {
    height: 100vh;
    min-width: 100vw;
    display: flex;
    flex-direction: column;
}

.city {
    background-color: rgb(10, 57, 93);
    color: #fff;
    text-align: center;
    padding: 1rem 0;
}

.current-weather {
    position: relative;
    padding-top: 2rem;
    padding-bottom: 3rem;
    margin-bottom: 1rem;
    color: #fff;
    font-size: 2rem;
    text-align: center;
    height: 60vh;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    background-color: rgb(53, 117, 226);
    box-shadow: 0 0 0 rgba(0, 0, 0, 0.5), inset 0 -2px 3px rgba(0, 0, 0, 0.5);
}

.current-weather__temperature {
    margin-top: 3rem;
    font-weight: 700;
    font-size: 6rem;
}

.current-weather__content {
    margin-top: 2rem;
    font-size: 2rem;
    position: relative;
}

.weather-forecast {
    height: 40vh;
    background-color: #fff;
    display: flex;
    justify-content: center;
    padding-bottom: 3rem;
    padding-top: 1rem;
}

.day {
    width: 32%;
    padding: 1%;
    text-align: center;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.dayName {
    display: block;
}

.temperature {
    display: block;
    padding-top: 2rem;
}

.weather__description {
    display: block;
    padding-top: 3rem;
}

.weather-icon {
    display: block;
    height: 40%;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    width: 80%;
    margin: 0 auto;
}

.date {
    display: block;
    padding-top: 2rem;
}

Щепотку логики

// weather
function setWeather(data, day, dayNum){
	var path = "weather-icons/";
	var icon = "";
    var date;
    day.querySelector(".temperature").innerHTML = parseInt(data.list[dayNum].main.temp) + " C°";
    day.querySelector(".weather__description").innerHTML = data.list[dayNum].clouds.all + " %";
    date = data.list[dayNum].dt_txt.substring(0, data.list[dayNum].dt_txt.indexOf(" "));
    day.querySelector(".date").innerHTML = date;

	var icon_id = data.list[dayNum].weather[0].icon;
	day.querySelector('.weather-icon').style.backgroundImage = "url("+path+icon_id + ".png)";
};

function getWeather(){
    var url = "http://api.openweathermap.org/data/2.5/forecast?q=Penza,ru&lang=ru&units=metric&APPID=123f78614c816b68a55c05c07be11ca7";
    var xhr = new XMLHttpRequest();

    xhr.open('GET', url, true);

    xhr.onload = function () {
        var data = JSON.parse(this.responseText);
        document.getElementById('city-name').innerHTML = data.city.name;
        setWeather(data, document.getElementById("day0"), 0);
        setWeather(data, document.getElementById("day1"), 8);
        setWeather(data, document.getElementById("day2"), 16);
        setWeather(data, document.getElementById("day3"), 24);
    }

    xhr.onerror = function () {
        console.log("не удалось подключиться");
    }

    xhr.send();
};

setTimeout(function() {
    getWeather();
}, 300000);

Приправим иконками для вкуса

сервис для получения погоды openweathermap.org

Первая дегустация

Добавим грамм 200 нативных функций

ocument.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log(navigator.camera);
}

var photoButton = document.getElementById("photo-button");
photoButton.addEventListener("click", function () {
    var image = document.getElementById('myImage');
    navigator.camera.getPicture(cameraSuccess, cameraError, { quality: 50,
    destinationType: Camera.DestinationType.FILE_URI });
});


function cameraSuccess(imageURI) {
    var image = document.getElementById('myImage');
    image.src = imageURI;
    image.style.display = "block";
}

function cameraError(message) {
    alert("message");
}
.cssui-btn {
  display: inline-block;
  cursor: pointer;
  font-family: inherit;
  font-size: 1em;
  font-weight: 400;
  margin-top: 3px;
  margin-bottom: 3px;
  vertical-align: middle;
  text-decoration: none;
  white-space: nowrap;
}

.cssui-btn_skin-material-round {
  background-color: #f22;
  width: 3em;
  height: 3em;
  color: #fff;
  padding: .7em .7em;
  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
  border-radius: 50%;
  border: none;
  color: #fff;
  outline: none;
  text-align: center;
  box-sizing: border-box;
}

.cssui-btn_skin-material-round:hover, .cssui-btn_skin-material-round:focus {
    box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 6px 0 rgba(0, 0, 0, 0.6), 0 3px 4px -2px rgba(0, 0, 0, 0.2);
}

.cssui-btn_skin-material-round:active {
    background-color: #cc0022;
}

.photo-button {
    position: absolute;
    bottom: 0;
    right: 5%;
    transform: translate(-50%, 50%);
}

.photo-icon {
    position: relative;
    display: inline-block;
    width: 100%;
    height: 100%;
    background-image: url(../img/camera.svg);
    background-size: cover;
    background-repeat: no-repeat;
}

#myImage {
    max-width: 100%;
    height: auto;
    display: none;
}
<div class="current-weather" id="day0">
    <div class="current-weather__temperature temperature"></div>
    <i class="weather-icon"></i>
    <span class="weather__description"></span>
    <span class="date"></span>
    <button type="button" name="photo-button" class="photo-button cssui-btn cssui-btn_skin-material-round" id="photo-button">
        <i class="photo-icon"></i>
    </button>
</div>

Больше плагинов

Пробуем наш суп еще раз

Быстрая проверка

что мы сварили?

Назовем наше приложение

Добавим иконок

Сборка

phoneGap client

phoneGap build

PhoneGap cli

$ phonegap remote login
$ phonegap remote build android
$ phonegap remote run android
$ phonegap remote logout

сборка на вашем устройстве

$ phonegap build android
$ phonegap run android

сборка в облачном сервисе

PhoneGap Build

— Что такое PhoneGap Build?

PhoneGap Build это бесплатный облачный сервис, построенный на основе PhoneGap/Cordova, который позволяет собирать кросс-платформенные мобильные приложения.

 

— Зачем нам PhoneGap Build?

PhoneGap Build позволяет делать сборки для iOS, Android и Windows Phone одновременно, без необходимости устанавливать какие-либо SDK tools. Но что более важно, этот сервис позволяет делать сборки для iOS в облаке без наличия Mac.

Создаем проект в PhoneGap Build

Тянем приложение из нашего Github

Жмём магическую кнопку

Скачиваем и радуемся

Нюансы сборки

- одно бесплатное закрытое приложение

- неограниченное количество открытых приложений

- не забываем блокировать viewport

- не забываем удалять json с id проекта после сборки закрытого приложения

- можно собирать приложения имея только файлы веб приложения

- помним о совместимости

Не забываем блокировать viewport

target-densitydpi=device-dpi

PhoneGap Build

PhoneGap client

Удаляя проекты из PhoneGap Build удаляйте его из config.json

Можно собирать имея только файлы веб приложения

Помним о совместимости

Почему так произошло?

Ещё немного о совместимости

Плюсы - Минусы

+ -
Быстро работает Долго и дорого разрабатывать
 
Почти не зависит от интернет-соединения.
 
Нужны разработчики именно под определенную ОС
Имеет полный доступ к техническим возможностям смартфона. Работает только с определенной платформой.
+ -
Кроссплатформенность (сделав одно приложение, его можно экспортировать под любую ОС).
 
Меньше возможностей по интеграции с «начинкой» смартфона (только основное).
Достаточно будет хороших веб разработчиков.
 
Сроки разработки меньше, чем нативного. Работает медленнее, чем натив.

Нативное

Гибридное

Для каких приложений целесообразно использовать PhoneGap

  • акселерометром

  • камерой

  • компасом

  • контактами

  • файловым хранилищем

  • геолокацией

  • базой данных

  • событиями, уведомлениями

  • медиа и др.

Ссылки

phonegap.com

build.phonegap.com - облачный сборщик

jquerymobile.com - удобная библиотека для нативных жестов

ngcordova.com - cordova/angular плагины

docs.phonegap.com/references/plugin-apis - описание использования плагинов

https://build.phonegap.com/plugins - основные плагины phonegap

play.google.com/store/apps/details?id=com.adobe.phonegap.app - мобильное приложение

cordova.apache.org/plugins - плагины Cordova

github.com/grachpower/Weather - дэмо

Андреев Артём

github.com/grachpower

PhoneGap

By Artyom Andreev