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
-
акселерометром
-
камерой
-
компасом
-
контактами
-
файловым хранилищем
-
геолокацией
-
базой данных
-
событиями, уведомлениями
- медиа и др.
Ссылки
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
PhoneGap
By Artyom Andreev
PhoneGap
- 544