Pull to refresh
54.8
Arcadia
Заказная разработка, IT-консалтинг

Инфраструктура разработки приложения на PhoneGap для iOS и Android

Reading time 11 min
Views 45K
Сегодня я расскажу вам о нашем опыте разработки кросс-платформенных мобильных приложений на основе PhoneGap/Cordova. В проекте используются такие технологии, как HTML5, CSS3 и Angular.js. Grunt применяется в качестве task manager’а, позволяющего упростить и ускорить выполнение рутинных задач. Все сборки компилируются локально во время процесса разработки.


Источник: build.phonegap.com

Когда версия готова к этапу тестирования, она компилируется с помощью PhoneGap Build и загружается на Ubertesters — сервис дистрибуции мобильных приложений, который позволяет проводить тестирование быстро и эффективно на всех подключенных устройствах. Приложение поддерживает минимум iOS 6 и Android 4.1 (87.5 % доля рынка).

Настройка локальной сборки и структура проекта


Для локального тестирования приложения необходимо установить инструменты для PhoneGap/Cordova. Важно убедиться, что NodeJS уже установлен, открыть командную строку или Cygwin и выполнить следующее:

npm install -g phonegap

После завершения установки пустой проект может быть создан и скомпилирован для требуемой платформы:

phonegap create my-app
cd my-app
phonegap platform add android
phonegap run android

Внимание: phonegap = cordova. Можно использовать cordova вместо phonegap при написании команд:

cordova run android

Сборка для iOS может осуществляться только под Mac OS X (согласно условиям лицензионного соглашения Apple), не существует способа запустить сборку для iOS под Windows.

Платформа Android требует наличия SDK Tools, его можно скачать по ссылке (пакет SDK Tools Only внизу страницы). Сразу после установки необходимо проверить в Android SDK Manager, что Android 5.0 (API level 21) был установлен успешно. Android 5.0 используется как target для текущей версии Phonegap/Cordova при локальной сборке.

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


Файлы и папки

• platforms – включает в себя раздельный код под каждую из используемых платформ, компилируется каждый раз, когда выполняется сборка;
• plugins – это плагины, используемые в приложении. Плагины описываются подробнее далее;
• www – веб-приложение на основе HTML5/Angular.js, PhoneGap/Cordova отображает при помощи системного компонента Web View;
• config.xml – файл должен находиться в корневой папке проекта при локальной сборке. PhoneGap Build требует наличия файла config.xml в /www. Файл настроек является важной частью проекта на основе PhoneGap. Он включает в себя ссылки на ресурсы приложения, устанавливает необходимые разрешения и настраивает параметры для каждой из платформ (например, поведение status bar’а). Application (bundle) id и информация об издателе должна быть тоже указана в config.xml.

Plugins


Плагин это пакет, который позволяет автоматически внедрить native код в приложение и управлять native методами из Cordova Web View. Все основные функции PhoneGap/Cordova API реализованы при помощи плагинов, которые предоставляют доступ к возможностям и функциям устройства и платформы, которые недоступны обычному веб-приложению: сканирование QR кода, NFC, Push уведомления и даже Touch ID для iOS.

Существует реестр PhoneGap плагинов. Очень важно использовать плагины, совместимые с PhoneGap Build, иначе сборка будет возможно только локально.
Для добавления плагина в проект при локальной сборке используют команду plugin add из корневой папки проекта. Аргументом к этой команде является URL Git репозитория, содержащего код плагина:

cordova plugin add https://github.com/phonegap-build/PushPlugin.git

PhoneGap Build требует указания id в файле config.xml для каждого плагина (что-то вроде зависимостей). Указывать конкретную версию не обязательно, но желательно, так как различные сборки плагина могут быть несовместимы, и придётся долго выяснять причину внезапно появившихся ошибок. Пример со страницы плагина:

<gap:plugin name="com.phonegap.plugins.pushplugin" version="2.4.0" />

Соответствующие .js файлы должны быть импортированы на HTML странице:

<script type="text/javascript" charset="utf-8" src="PushNotification.js"></script> 

Все плагины обычно имеют документацию (пускай, и не всегда подробную) на GitHub.
Поскольку мы используем Angular.js framework, а не чистый JavaScript, дополнительный компонент требуется для того, чтобы «обернуть» плагины. Он называется ngCordova.

ngCordova

ngCordova это коллекция из более чем 60 Angular.js расширений на основе Cordova API, которые позволяют упростить создание, тестирование и сборку мобильных приложений PhoneGap/Cordova. Проект поддерживается и развивается командой Ionic Framework. ngCordova предоставляет простые Angular.js wrapper’ы для самых популярных и часто используемых плагинов PhoneGap/Cordova и позволяет сделать фото, отсканировать QR код, загрузить файл, включить вспышку, получить текущую локацию, а также многое другое с помощью нескольких строк кода.

Для локальной сборки всё так же необходимо добавить плагин с помощью команды:

cordova plugin add https://github.com/phonegap-build/PushPlugin.git

Для PhoneGap Build требуется ссылка на id плагина в config.xml:

<gap:plugin name="com.phonegap.plugins.pushplugin" version="2.4.0" />

ng-cordova.js импортируется из пакета ngCordova, script тэг должен быть расположен после импорта angular.js, иначе появятся ошибки, не имеющие отношения к проекту:

<script src="scripts/angular.js"></script>
<script src="scripts/ng-cordova.js"></script>

Важно не забыть добавить зависимость ngCordova к модулю:

angular.module('application', [
    'ngCordova'
])

Каждый ngCordova wrapper имеет свою документацию. Плагин для Push уведомлений и QR сканер были использованы и протестированы в нашем проекте. Сканер QR кодов (Barcode Scanner) был интегрирован без особых проблем, можно даже сказать «out-of-the-box», но настройка Push плагина заняла довольно длительное время в связи с недостатком документации – информацию приходилось собирать, просматривая огромный список issues на GitHub’е.

Push уведомления для Android (Google Cloud Messaging)

Краткая документация доступна на странице плагина ngCordova.

Важно! Payload часть push уведомления, отправляемая с сервера должна следовать определённому формату, иначе возможны проблемы с автоматическим появлением уведомлений в системном трее.

Было обнаружено, что объект data должен обязательно иметь поле «message» (в качестве текста уведомления) и «title» (если отсутствует, то заголовок уведомления будет пустым). Поле «uri» необходимо для того, чтобы указать действие, которое совершается при открытии уведомления.

{
    "data": {
        "message": "New message. You have 5 unread messages",
        "title": "Your Application",
        "uri": "http://www.yourapp.com/messages"
    }
}

Также важно отметить, что notificationReceived listener срабатывает тогда, когда приложение находится в foreground, а также в случае, когда пользователь открывает уведомление (переход из background’а в foreground). Push уведомления появляются автоматически в background’е и продолжают приходить даже после перезагрузки системы.

Uri может быть получен в условии ‘message’ структуры switch case listener’а.
$rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
    console.log(notification);
    switch (notification.event) {
        case 'registered':
            if (notification.regid.length > 0) {
                registerOnServer(notification.regid);
            }
            break;
        case 'message':
            console.log('message!');
            utils.goToApiUrl(notification.payload.uri);
            break;
        case 'error':
            console.log('GCM error: ' + notification.msg);
            break;
        default:
            console.log('An unknown GCM event has occurred: ' + notification.event);
            break;
    }
});


Push уведомления на iOS

Краткая документация доступна на странице плагина ngCordova.

В момент, когда разрабатывалось приложение, часть бэкенда, которая отвечает за отправку Apple Push уведомлений (APNS) была не готова. Решили использовать временное решение для тестирования и отладки. Node Push Server был выбран первоначально (т.к. по нему имелись рекомендации в некоторых мануалах по Phonegap/Cordova), но в ходе тестирования выяснилось, что в нём отсутствует поддержка кастомных полей для Push уведомлений на iOS (поддерживаются только badge, alert и sound, а нам нужно передавать uri для открытия определённой страницы) и из-за проблем с форматом некорректно работает на iOS 6 и iOS 7 (счётчик на иконке не отображается).

Существует несколько распространённых решений на рынке, но мы выбрали платформу Parse.com для наших тестовых уведомлений на iOS, т.к. условия Free Plan вполне достаточны для процесса разработки и тестирования.
Чтобы настроить уведомления: первым делом необходимо зарегистрироваться и зайти в настройки, раздел “Settings”, затем перейти в секцию “Push” для того, чтобы включить обработку push уведомлений и загрузить требуемый сертификат (*.p12). Вы можете узнать больше о работе Apple Push Notification Service здесь.

Пример кода на основе документации ngCordova
function registerInCordova() {
    var iosConfig = {
        "badge": true,
        "sound": true,
        "alert": true,
    };
    var authHeader = {
        headers: {
            'X-Parse-Application-Id': 'YOUR_APPLICATION_ID',
            'X-Parse-REST-API-Key': 'YOUR_REST_API_KEY',
            'Content-Type': 'application/json'
        }
    };
    $cordovaPush.register(iosConfig).then(function(deviceToken) {
        // Success -- send deviceToken to server, and store for future use
        console.log("deviceToken: " + deviceToken);
        $http.post("https://api.parse.com/1/installations", {
            "deviceType": "ios",
            "deviceToken": deviceToken,
            "channels": ["ALL"]
        });
    }, function(err) {
        console.log("Registration error: " + err);
    });
}
</spoiler>
Важно не забыть поменять 'YOUR_APPLICATION_ID' и ‘YOUR_REST_API_KEY' на значения из секции “Settings” -> “Keys”. Код listener’а выполняется, когда приложение запущено в foreground или переходит из background’а в foreground (после нажатия на push уведомление).
<spoiler title="Код listener'а">
<source lang="javascript">
function registerForegroundListener() {
    $rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
        console.log("Notification: " + JSON.stringify(notification));
        if (notification.sound) {
            var snd = new Media(event.sound);
            snd.play();
        }
        if (notification.badge) {
            $cordovaPush.setBadgeNumber(notification.badge).then(function(result) {
                console.log("Badge set successfully");
            }, function(err) {
                console.log("Error on badge setting: " + err);
            });
        }
        if (notification.uri) {
            utils.goToApiUrl(notification.uri);
        }
    });
}

Для того, чтобы отправить Push уведомление через Parse.com на все зарегистрированные устройства, необходимо выполнить HTTP POST запрос
curl -X POST \
  -H "X-Parse-Application-Id: YOUR_APPLICATION_ID" \
  -H "X-Parse-REST-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          ""
        ],
        "data": {
            "alert": "New Messages",
            "badge": 3,
            "uri": "api/messages"
        }      }' \
  https://api.parse.com/1/push  


PhoneGap Build


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

— Зачем нам PhoneGap Build?
PhoneGap Build позволяет делать сборки для iOS, Android и Windows Phone одновременно, без необходимости устанавливать какие-либо SDK tools (конечно, в этом есть доля лукавства – при разработке всё равно лучше делать сборку локально, хотя бы на Android, перед отправкой на тестирование). Но что более важно, этот сервис позволяет делать сборки для iOS в облаке без наличия Mac.

PhoneGap Build имеет собственный REST API, который может использоваться для автоматизации создания и обновления проектов, запуска сборки под iOS, Android и Windows Phone (можно выбирать платформу). Если вы используете GitHub, есть возможность настроить сервис для автоматической сборки после каждого коммита в репозитории. REST API позволяет авторизовать каждый HTTP запрос к серверу с помощью токена, вместо того, чтобы передавать имя пользователя и пароль в header’е.

Для использования PhoneGap Build нужно сделать настройки:
— После регистрации заходим в «create new app». Необходимо загрузить упакованное в zip содержимое папки www, config.xml должен быть внутри. Доступ к приватным GitHub репозиториям доступен только в платной версии аккаунта).
— Далее нужно перейти в настройки аккаунта: кликнуть по иконке в правом углу, “Edit account” -> “Signing keys”, добавить требуемые сертификаты и ключи (сборка для iOS прервётся при отсутствии сертификата *.p12 и профиля, сборка для Android будет выполнена в режиме AdHoc, если ключ отсутствует).

После того как установочные пакеты для всех требуемых платформ сгенерированы с помощью PhoneGap Build, можно вручную загрузить их на сервис дистрибуции. Существует множество альтернативных вариантов: HockeyApp, TestFlight, TestFairy, но далее мы рассмотрим Ubertesters и изучим, как произвести автоматизацию сборки и дистрибуции с возможностью интеграции Ubertesters Upload API.

Ubertesters


— Почему Ubertesters?
Особенности и преимущества этого сервиса обсуждаются в этой статье.

Сервис Ubertesters предоставляет SDK для всех основных платформ (даже Phonegap/Cordova). Upload API, как уже было сказано, позволяет использовать continuous integration и автоматизировать дистрибуцию.

Чтобы открыть доступ к Upload API необходимо перейти на страницу профиля.
Документация доступна по ссылке.

Установочные пакеты (ipa/apk) могут быть загружены с помощью curl
curl
    -X POST
    http://beta.ubertesters.com/api/client/upload_build.json
    -H "X-UbertestersApiKey:PERSONAL_API_KEY"
    -F "file=@upload.ipa"
    -F "title=build title"
    -F "notes=build notes"
    -F "status=in_progress"
    -F "stop_previous=true"

Чтобы разрешить автоматическую дистрибуцию на устройства команды тестировщиков и разработчиков, необходимо создать группу дистрибуции по умолчанию: “Administration” -> “Distribution Groups” -> “Add distribution group”, выбрать чекбокс “Default group”. Так как в нашем случае поддерживаются 2 платформы, нужно не забыть совершить операцию для каждого из проектов (iOS и Android).

Автоматизация задач


Существует несколько способов автоматизации процесса сборки для приложений на PhoneGap/Cordova. В качестве task manager’a можно использовать Grunt, Ant, Maven а в качестве среды для continuous integration Jenkins CI или Team City.

Конфигурация Grunt

Grunt требует наличия двух файлов: package.json (он определяет зависимости и базовые настройки) и gruntfile.js (конфигурация задач).
Для начала нужно установить grunt-cli:

npm install -g grunt-cli

Можно использовать следующие настройки для package.json
{
    "name": "Your application",
    "version":"1.0.0",
    "description": "Your App",
    "main": "index.html",
    "author": "",
    "licenses": "",
    "devDependencies": {
        "form-data": "^0.2.0",
        "fs": "0.0.2",
        "grunt": "0.4.5",
        "grunt-contrib-compress": "0.9.1",
        "grunt-http": "^1.6.0",
        "grunt-magikarp": "^0.2.5",
        "grunt-modify-json": "^0.1.1",
        "grunt-xmlpoke": "^0.8.0",
        "needle": "",
        "read": "~1.0.4"
    }
}

Зависимости, заданные в package.json, могут быть удовлетворены с помощью npm install
Все необходимые модули будут установлены в /node_modules
Но также потребуется установить grunt-phonegap-build вручную:

npm install grunt-phonegap-build

На Dropbox доступен пример Gruntfile.js:

Несколько параметров необходимо установить перед использованием:
  • var PHONEGAP_API_ID = «YOUR_PHONEGAP_API_ID»;
  • var PHONEGAP_TOKEN = «YOUR_PHONEGAP_TOKEN»;
  • var UBERTESTERS_API_KEY = «YOUR_UBERTESTERS_API_KEY»;
  • В конфигурации задачи phonegap-build должен быть указан пароль для сертификата iOS.

Далее мы рассмотрим все используемые в проекте задачи task manager’а Grunt в порядке использования в скрипте.

Список задач Grunt

1) http:phonegap_build_version

Мы получаем текущую версию из сервиса PhoneGap Build с помощью HTTP GET запроса:

http://build.phonegap.com/api/v1/apps/' + PHONEGAP_API_ID + '?auth_token=' + PHONEGAP_TOKEN

Методы и документация PhoneGap Build Read API доступны по ссылке.

2) readCurrentVersion

Результат http:phonegap_build_version возвращается в формате JSON и сохраняется по указанному пути:

ubertesters_response/phonegap_app.json

В данный момент скрипт имеет баг: phonegap_app.json должен быть создан вручную до запуска (можно просто создать пустой JSON file). Текущая версия передаётся как параметр к modify_json.

3) modify_json

Обновляет значение текущей версии в package.json.

4) magikarp

Magikarp инкрементирует текущую версию в package.json. Опции доступны: major, minor и build.

5) readNextVersion

Инкрементированная версия из package.json передаётся в xmlpoke.

6) xmlpoke

Изменяет версию в файле www/config.xml.

7) compress

Сжимает содержимое папки www (не саму папку, это важно!), исключая ненужные файлы. Сжатый zip файл сохраняется по указанному пути target/phonegapp.zip

8) phonegap-build:debug

В данный момент debug и release ничем не различаются (release ключ ещё не сгенерирован для Android). Сжатый zip файл отправляется на сервис PhoneGap Build. Задача завершается только после сборки (ios/android) и сохранения установочных пакетов (ipa/apk).
Методы и документация PhoneGap Build Write API methods доступны по ссылке.

9) http:ubertesters_ios

Эта задача загружает ipa сборку на Ubertesters с помощью Upload API. Здесь можно использовать любой сервис дистрибуции мобильных приложений, если он имеет REST API.

10) http:ubertesters_android

Та же задача, но для Android apk.

11) PROFIT!

Grunt запускается локально с помощью команды ‘grunt’ или на сконфигурированном build сервере (TeamCity в нашем случае). Также есть возможность настроить TeamCity, чтобы вызывать процесс сборки и дистрибуции при каждом коммите.

Так можно сэкономить немало времени, используя continuous integration при сборке и тестировании мобильных приложений.

Полезные ссылки


Automating PhoneGap builds
Сервисы дистрибуции мобильных приложений для iOS. Часть 3: Ubertesters
Tags:
Hubs:
+15
Comments 20
Comments Comments 20

Articles

Information

Website
arcadia.spb.ru
Registered
Founded
Employees
201–500 employees
Location
Россия
Representative
Дмитрий Адов