Разработка мобильных приложений: Синхронизация с сервером. Разработка серверной части для мобильных приложений Сервер для мобильного приложения

Офлайн в прошлом, быть Онлайн сегодня обязательно. По крайней мере для современного делового мира. Презентации продукции и услуг брендов, онлайн-заказ и доставка, ведение клиентской базы, общение с клиентами, а также многое другое - все это просто невозможно без присутствия в Интернете. Если вы нуждаетесь в приложении, вы должны иметь как Front-end (веб-интерфейс), так и Back-End (серверная часть вашего приложения). И если вы хотите иметь возможность редактировать контент вашего приложения без участия разработчиков, вам потребуется хорошая административная панель.

В то время как Front-end в сфере мобильных приложений создается с помощью таких технологий, как X-Code и Java, Back-end, где будет храниться база данных и вся логика приложения, требует профессионального знания языка программирования на стороне сервера. Хорошим примером является PHP, который является, пожалуй, самым популярным языком программирования, который используется для разработки почти любой серверной части. Это бесспорный лидер.

Существует много областей применения PHP: статические и динамические веб-сайты + системы пользовательского управления контентом, социальные сети, специализированные системы CRM, программное обеспечение для электронной коммерции, и многое другое. Конечно, есть бесплатные или дешевые серверные части и панели управления. Тем не менее, во многих случаях они не дают необходимого уровня удобства, настроек и возможности модернизации.

Наши программисты работают с технологиями, позволяющими реализовывать широкий спектр решений для различных бизнес-целей, потребностей и требований. Мы анализируем системные требования для каждого проекта индивидуально и применяем различное специализированное серверное программное обеспечение для оптимальной производительности вашего мобильного приложения.

Если вы ищете команду, которая может привести вас к наиболее разумному и экономичному решению для создания приложения с нуля или восстановить существующее для идеального восприятия пользователями, вам не нужно больше искать. Appsmob готов помочь найти лучшее решение для Вас.

Разработка серверной части приложения

Введение

Присутствие в интернете стало необходимостью для современных компаний. Без этого невозможно выстроить полноценного взаимодействия с клиентами. Часто для решения подобной задачи прибегают к созданию клиент-серверных приложений. Каждое из них состоит из клиентской части и Back-end. Под последним термином подразумевается серверная часть приложения. Если в дальнейшем нужно самостоятельно изменять контент мобильной программы, то Back-end должен быть создан особенно качественно. Компания Appomart гарантирует выполнение поставленных задач в соответствии предъявляемым требованиям. Поэтому, заказывая создание серверных приложений, можете быть уверены в надлежащем результате.

Для чего нужен Back-end?

Разработка клиент-серверных приложений подразумевает создание двух частей. Первая, Front-end, принимает запросы от пользователей. Она видна с экранов мобильных устройств клиентов. Вторая, серверное приложение, обрабатывает полученные запросы, выполняет роль административной панели. Здесь хранятся базы данных, логика программы. Без этого не будет работать ни одно клиент-серверное приложение. По сути Back-end - это сердце программы. Это интеллект, который отвечает за обработку запросов клиентов, скорость работы приложения. Поэтому важно, чтобы архитектура серверного приложения была продумана до мелочей, чтобы даже высоконагруженные сервисы работали бесперебойно и быстро.

Как выбрать язык программирования?

В ходе подготовки технического задания (части рабочей документации по проекту), архитектор проектирует систему баз данных и связей, описывает объекты и их свойства, а также разрабатывает необходимые методы сервера (запросы, которыми будут "пользоваться" мобильные приложения обращаясь к серверу).

Важность документации и "брошенные" проекты

В Appomart довольно часто обращаются заказчики, которых "бросили" по тем или иным причинам другие подрядчики. И мы берем чужой, порою даже некорректно работающий проект, осуществляем его аудит и последующую доработку и поддержку. В процессе изучения исходного кода и материалов, полученных от заказчика, мы сталкиваемся с тем, что многие разработчики намеренно не документируют методы сервера, чтобы привязать к себе клиента, за счет несоизмеримости трудозатрат передачи проекта в поддержку другому разработчику, ввиду отсутствия документации к серверной части, а порой просто из-за непрофессионализма. Данный факт, к сожалению, является не только печальным но и распространенным. Заказчику, в этом случае, необходимо оплачивать разработку документации по существующему проекту, а также аудит исходного кода, прежде чем можно будет судить о работоспособности, удобстве и целесообразности поддержки проекта. Сотрудники Appomart всегда ведут электронную документацию методов серверной части в формате, поддерживаемом Postman и Swagger, для последующего использования.

Как проверить подрядчика до подписания договора?

Мы призываем Вас внимательно выбирать подрядчика, и ориентироваться не только на заманчивую цену, но и на перечень документов, которые вы получите вместе с проектом, а также условия передачи исходного кода, и покрытие кода комментариями, схемы баз данных (будь то Mongo DB или MySQL). Залогом успеха, как правило становится грамотная рабочая документация, которая явно указывает на требования к передаваемой Вам по завершению каждого из этапов работы материалов.

Особенности разработки

PHP для серверной части

Создание серверной части приложений (не путать с серверами как "железом" или компьютерами, так как речь идет о программной части) требует специфических профессиональных навыков и знания языка программирования, который применяется на стороне сервера. Если рассматривать примеры клиент-серверных приложений, то видно, что популярностью пользуется PHP. Это бесспорный лидер в области разработки серверных приложений. На этом языке написано в той или иной конфигурации более половины сайтов в мире. PHP удобен для разработки и поддержки, и кроме того существуют специальные framework-и для ускорения разработки на PHP.

Framework

Framework (программная платформа) - используется для систематизации и повышения уровней абстракции, что позволяет сделать проект более гибким и масштабируемым. Однако, стоит понимать, что framework должен быть выбран корректно, на основе глубинного анализа рабочей документации проекта, без которой невозможно разработать качественный продукт.

Delphi, JAVA, Python

Есть и другие языки, которые используются для создания Back-end. Так, распространены созданные в среде Delphi серверные приложения. С ее помощью программа получает улучшенную отладку, в среде также просто сформировать уникальные программы, предусмотрено визуальное создание, что дает возможность сделать красивый, понятный и удобный интерфейс. Также популярность получили серверные приложения на Java. Такие легко дополняются, легко исполняются на любых платформах и отличаются достойным уровнем безопасности. Еще одним популярным языком считается Python. Серверные приложения с его помощью создаются быстро, просто, без серьезных затрат.

Распространение

Создание клиент-серверных приложений пользуется спросом в корпоративной среде. Часто подобные программы используются для рабочих групп или создания информационных систем внутри предприятия. Подавляющая часть мобильных приложений для поддержания связи с клиентом также имеет подобную архитектуру. Популярность обусловлена тем, что использование возможностей сервера позволяет обеспечить контроль и целостность системы, уменьшая при этом нагрузку сети.

Создадим клиент-серверное приложение Android, iOS качественно и в срок

Разработка "под ключ"

Программисты Appomart опытны и квалифицированы, чтобы реализовать задачи самых разнообразных уровней. Мы одинаково хорошо реализуем социальные сети, высоконагруженные бизнес-проекты, или программную часть для небольших стартапов. При необходимости мы создадим клиентскую часть приложения под управлением Android, iOS в соответствии с имеющимися потребностями, предъявляемыми требованиями.

Back-end в Appomart

Наши программисты работают с различными технологиями и делают это в равной степени хорошо. В Appomart вы можете заказать клиент-серверное приложение на Java, PHP и Node.JS. Системные требования анализируются для каждого из проектов индивидуально, что позволяет обеспечить оптимальную производительность программы. Создадим клиент-серверное приложение Java, PHP и Node.JS с нуля или возьмем в саппорт существующее для улучшений и обновлений. Если Вас интересует разработка новой серверной части или поддержка существующей - оставьте заявку, чтобы получить подробный расчет стоимости работ и вариантов сотрудничества.

488 Часть IV. Ajax в примерах

ботки, и вызывает сервер, который динамически создаст ответные данные, основываясь на отправленном значении строки запроса. Первым параметром функции LoaciXMLXSLTDoc () является URL страницы РНР, которая генерирует XML-документ, объединенный со строкой запроса, сформированной ссылкой на значений поля HTML-формы О. Второй параметр - это имя XSLTфайла ©, используемого в преобразовании XML-данных. Третий параметр, требуемый функцией LoadXMLXSLTDoc (), представляет собой идентификатор элемента div, в который следует помещать результаты поиска. Идентификатор - это строковое имя выходного элемента, а не ссылка на объект; в данном случае в качестве идентификатора используется строка "results" .

На следующем этапе мы с помощью методов DOM добавляем на Webстраницу изображение-индикатор. Создается элемент изображения © и устанавливается атрибут источника изображения О. Этот созданный элемент добавляется к элементу div с результатами ©. Таким образом, когда наша функция вызывается из обработчика событий onsubmit формы, на страницу помещается файл изображения. Вообще, для пользователя важно создать визуальную обратную связь - сообщение или изображение, - указывающую, что обработка находится в процессе. Благодаря этому пользователь не будет повторно щелкать на кнопке отправки форы, думая, что ничего не происходит (помните, процесс Ajax - "незаметный").

Последний этап - это вызов функции LoadXMLXSLTDoc () ®, инициирующей процесс отправки информации на сервер. Функция LoadXMLXSLTDoc (), описанная в разделе 12.4, обрабатывает вызов объекта ContentLoader (), который запрашивает документы с сервера. Задавая в качестве параметра выходное положение (а не кодируя значение жестко в функции LoadXMLXSLTDoc {)), мы можем многократно использовать данную функцию на одной странице, не требуя для разделения функциональных возможностей добавления множества процедур или операторов if. Следовательно, мы перенаправляем результаты различных поисковых запросов на различные части страницы. Однако, прежде чем мы все это сделаем, давайте посмотрим, как создать на сервере документы XML и XSLT.

12.3. Код серверной части приложения: РНР

В данном разделе мы создадим для проекта динамический XML-документ, используя РНР - популярный язык подготовки сценариев с открытым исходным кодом (как вы знаете, инфраструктура Ajax совместима с любым серверным языком или платформой). XML-документ генерируется динамически по набору результатов, полученному в ответ на запрос клиента к базе данных. Кроме того, мы покажем, как создать статический документ XSLT, который расположен на сервере и извлекается каждый раз, когда запрашивается динамический файл. Оба указанных документа возвращаются клиенту независимо, когда объект ContentLoader запрашивается в двух отдельных запросах (листинг 12.7). XSLT-код преобразовывает наш динамический XML-документ на стороне клиента и создает HTML-таблицу, которая отображается пользователю.

Глава 12 "Живой" поиск с использованием XSLT 489

12.3.1. Создание XML-документа

Поскольку мы используем XSLT, нам нужен структурированный XMLдокумент, представляющий собой простую запись информации, чтобы XSLфайл мог выполнить стандартное преобразование. В данном проекте мы создадим динамический XML-файл, когда клиент затребует РНР-файл.

Разработка XML-структуры

Прежде чем мы начнем создание XML-файла, необходимо создать шаблон для него. Этот шаблон должен отражать структуру данных, возвращаемых при поиске. В выбранной формулировке задачи (телефонная книга) мы будем возвращать название компании, имя контактного лица, страну и телефонный номер. В листинге 12.3 показан базовый XML-шаблон, содержащий четыре поля.

Листинг 12.3. Базовый XML-файл

Company Name Contact Name Country Name Phone Number

Первым элементом является phonebook. Следующий - элемент entry, содержащий подэлементы со всеми деталями, которые связаны со всеми контактными телефонами, найденными в запросе. Если у нас есть пять результатов, в XML-документе будет пять элементов entry. Имя компании отображается в элементе company. Кроме того, мы добавили имя контактного лица, название страны и номер телефона. Мы не ограничены только указанными полями; в зависимости от того, какую информацию необходимо отобразить, поля можно добавлять и удалять.

Если результаты не найдены, то вместо отображения предупреждающего сообщения можно создать элемент, отображающий эту информацию для пользователя. STO облегчит нам задачу возврата результата пользователю и не потребует дополнительного кода в клиентской части приложения. Код, приведенный в листинге 12.4, практически не отличается от кода из листинга 12.3, но на этот раз мы вводим текст в элементы XML, которые желаем показать пользователю, чтобы сообщить, что результаты не найдены.

Листинг 12.4. Файл XML без результатов

No Results

// О Вместо имени компании отображается "No R e s u l t s " N/A

490 Часть IV. Ajaxв примерах

// © Вместо оставшихся полей отображается "N/A"

N/A

N/A

С помощью данного кода мы отображаем пользователю единственную строку, сообщающую, что затребованная информация отсутствует. В дескрипторе company О отображается информация, сообщающая, что результатов нет. В других дескрипторах 0 пользователю сообщается, что информации нет. Если мы не желаем отображать текст "N/A" ("не доступно"), можно добавить вместо него неразрывный пробел, что позволит показать ячейки таблицы. Если бы мы не добавили вообще никакой информации, ячейки в таблице не появились бы.

Как видите, формат XML имеет очень простую структуру. Если бы данный XML-файл был статическим, пользователю было бы относительно просто добавить в файл нового абонента. Поскольку же он создается динамически, нам потребуется цикл, создающий XML-документ по набору результатов.

Создание динамического XML-документа

Как всегда, мы создаем XML-документ на сервере. Придерживаясь политики использования в примерах различных серверных языков, серверный код дайной главы написан на РНР. Еще раз напомним, что инфраструктуру Ajax можно создать с помощью любого серверного языка, и мы будем описывать только сам принцип реализации серверного кода, не вдаваясь в детали. Итак, в листинге 12.5 показан код серверной части приложения. Код получает параметр строки запроса и генерирует множество результатов запроса базы данных. Затем мы проходим по множеству результатов, создавая в XML-файле согласно приведенному в листинге 12.4 шаблону элемент для каждого номера телефона, полученного в ответ на запрос.

Листинг 12.5. Сценарий phoneXML.php: генерация XML-документа на сервере

// О Объявить тип MIME header("Content-type: text/xml"); echo("\n");

// © Соединиться с базой данных

$db = mysql__connect ("localhost", "ajax", "action"); rnysql_select_db("ajax",$db);

$result = mysql_query("SELECT *

FROM Contacts WHERE ContactName like "%". // © Заполнить запрос

$_GET["q"] ."%"",$db); ?>

// О Проверить результаты

if ($myrow = mysgl_fetch_array($result)) { do {

// © Пройти по множеству результатов

Глава 12. "Живой" поиск с использованием XSLT 491

001">

}while ($myrow - mysql_fetch_array{$result)); }else{

12.3.2. Создание документа XSLT

Используя XSLT, наш XML-файл с помощью пары строк кода можно преобразовать в красивую таблицу HTML. XSLT-документ разрешает сопоставление с шаблоном, если оно необходимо для отображения данных в любом требуемом формате. При сопоставлении с шаблоном для отображения данных применяется структура-шаблон. При этом мы проходим по узлам дере-

492 Часть IV. Ajax в примерах

ва источника, используя XSLT. XSLT-доку мент принимает структурированный XML-файл и преобразует его в формат, который удобен для просмотра, обновления и изменения. В нашем случае XSLT-доку мент определяется статически.

Структура XSLT

XSLT-преобразование содержит правила для перевода исходного дерева в конечное. Весь XSLT-процесс заключается в сопоставлении со структуройшаблоном. Когда элементы исходного дерева соответствуют заданной структуре, согласно шаблону документа создается конечное дерево.

Структура конечного дерева не обязательно должна быть связана со структурой исходного. Следовательно, исходный XML-файл можно преобразовать в любой требуемый формат. Использовать только табличное представление набора данных не обязательно.

XSLT-преобразование называется таблицей стилей, поскольку оно определяет стилевое оформление конечного дерева. Таблица стилей содержит правила шаблона, состоящие из двух частей. Первая часть - это структурашаблон, с которой сравниваются узлы исходного дерева. Обнаружив соответствие, XSLT-процессор задействует вторую часть - шаблон, содержащий дескрипторы для построения исходного дерева.

Создание XSLT-документа

Сформировать XSLT-преобразование для данного проекта сравнительно просто. Поскольку мы собираемся получить таблицу, никакое необычное сопоставление с шаблоном не потребуется; мы просто последовательно пройдем по всем узлам-элементам исходного дерева. Ниже мы разработаем шаблон, формирующий таблицу HTML с четырьмя столбцами. Соответствующий XSLTфайл для данного проекта показан в листинге 12.6.

i Листинг 12.6. XSLT-файл

"ISO-8859-l"?>

// О Установить версию XML и кодировку

// © Задать пространство имен XSLT "http://www.w3.org/1999/XSL/Transform">

// © Установить правила шаблона

// О Добавить элемент table

// © Создать строку заголовка

Глава 12 "Живой" поиск с использованием XSLT 493

// 0 Последовательно пройти по элементам телефонной книги

select="phonebook/entry"> // © Отформатировать выходные данные

Company Contact Country Phone

При создании XSLT-преобразования необходимо указать кодировку и версию XML О, а также задать пространство имен XSLT ©. Пространство имен определяет правила и спецификации, которым должен соответствовать документ. Элементы в пространстве имен XML распознаются в исходном документе, но не распознаются в документе результатов. Для определения всех наших элементов в пространстве имен XSLT применяется префикс xsl. Далее молено установить правило шаблона - искать структуру / ©, которая соответствует всему документу.

Теперь можно начинать создание шаблона таблицы, в которой отображаются наши результаты. Мы добавляем дескриптор table О, сопоставляющий с таблицей идентификатор. После этого вводится строка заголовка таблицы ©, вмещающая имена столбцов, указывающих пользователю, какая информация содержится в таблице.

Последовательно проходя по множеству узлов исходного дерева, мы получаем остальные строки таблицы. В данном случае используется цикл for-each ©, в процессе обработки записей выдающий узлы, расположенные в phonebook/entry.

Поскольку мы последовательно проходим по дереву документа, необходимо выбрать значения столбцов. Чтобы выбрать значения из узлов, используется оператор value-of в, извлекающий значение элемента XML и добавляющий его в выходной поток преобразования. Чтобы задать элемент XML, текст которого мы желаем извлечь, используем с именем элемента атрибут select. Сформировав XSLT-фаЙл и создав код для динамической генерации документа XML, можно завершить создание JavaScript-кода и посмотреть, как объединение XSLT-преобразования со структурированным XML-файлом позволяет получить удобную для просмотра таблицу.

На следующем этапе мы снова возвращаемся на сторону клиента, извлекающего файлы, созданные только что с помощью НТТР-отклика.

Значительная часть современных приложений для мобильных платформ (iOS, Android и т.п.) работает в паре с сервером. Приложение с устаревшими данными теряет свою полезность. Поэтому важно обеспечить постоянное обновление данных с сервера на устройство. Это касается оффлайн приложений, которые должны работать и без интернета. Для полностью онлайн приложений, которые не работают (или бесполезны) без интернета (например, Foursquare, Facebook) есть своя специфика, которая выходит за рамки текущей статьи.

Я расскажу на примере одного нашего оффлайн приложения, какие подходы мы использовали для синхронизации данных. В первых версиях мы разработали простые алгоритмы и, в дальнейшем, с опытом, мы их совершенствовали. Аналогичная последовательность представлена и в статье – от простых очевидных практик к более сложных.

Следует уточнить, что в статье рассматривается передача данных только в одну сторону: от сервера к устройству. Здесь сервер является источником данных.

Общие положения для всех подходов

Для примера, мы будем рассматривать передачу на устройство справочника блюд (“dishes”). Будем считать, что устройство делает запрос на url “/service/dishes/update”, обмен идет по протоколу http в формате JSON (www.json.org). На сервере есть таблица “dishes” с полями: id (идентификатор записи), name (наименование блюда), updated (момент обновления блюда, лучше сразу делать поддержку timezone, “YYYY-MM-DDThh:mm:ssTZD”, например, “1997-07-16T19:20:30+01:00”), is_deleted (признак удаленной записи).

Ремарка касаемо наличия последнего поля. По умолчанию его значение равно 0. В приложении, где сущности синхронизируются между клиентом и сервером, физически удалять данные с сервера не рекомендуется (чтобы не было ошибок). Поэтому у удаленных блюд выставляется is_deleted = 1. По приходу на устройство сущности с is_deleted = 1 она удаляется с устройства.

При любом подходе, который будет рассматриваться ниже, сервер возвращает на устройства JSON массив объектов (может быть пустой):

[
{id: ,name: ,updated:,isDeleted: },…
]

Пример ответа сервера:

[
{id: 5625,name: "Bread",updated: "2013-01-06 06:23:12",isDeleted: 0},
{id: 23,name: "Cooked semolina",updated: "2013-02-01 14:44:21",isDeleted: 0},{

name: "Fish-soup",

updated: "2013-08-02 07:05:19",

Принципы обновления данных на устройстве

  1. Если пришел элемент, который есть на устройстве, и isDeleted = 0, то он обновляется
  2. Если пришел элемент, которого нет на устройстве, и isDeleted = 0, то он добавляется
  3. Если пришел элемент, который есть на устройстве, и isDeleted = 1, то он удаляется
  4. Если пришел элемент, которого нет на устройстве, и isDeleted = 1, то ничего не делается

Подход 1: Синхронизируется всегда все

Это самый простой метод. Устройство запрашивает список блюд у сервера и сервер отсылает весь список целиком. Каждый раз список приходит весь. Не сортированный.

Пример запроса: null, либо “{}”

Достоинства:

  • логика на сервере простая – отдаем всегда все
  • логика на устройстве простая – перезаписываем всегда все

Недостатки:

  • если запрашивать список часто (каждые 10 минут), то будет большой интернет трафик
  • если запрашивать список редко (раз в день), то будет нарушена актуальность данных

Область применения:

  • для приложений с небольшим трафиком
  • передача очень редко меняющихся данных (список городов, категорий)
  • передача настроек приложения
  • на начале проекта для самого первого прототипа мобильного приложения

Подход 2: Синхронизируется только обновленное

Устройство запрашивает список блюд, обновленный с предыдущей синхронизации. Список приходит отсортированный по “updated” в порядке возрастания (необязательно, но удобно). Устройство хранит значение “updated” у самого последнего присланного блюда и при следующем запросе шлет его серверу в параметре “lastUpdated”. Сервер присылает список блюд, которые новее “lastUpdated” (updated > lastUpdated). При первом запросе на сервер “lastUpdated” = null.

Пример запроса: { lastUpdated: “2013-01-01 00:00:00” }

На схеме: “last_updated” – значение, которое хранится на устройстве. Обычно на устройстве создается отдельная таблица для хранения этих значений “last_updated” по каждой сущности (блюда, города, организации и т.п.)

Этот подход годится для синхронизации простых линейных списков, у которых правила прихода на устройство одинаковые для всех устройств. Для более избирательной синхронизации см “Подход 5: Синхронизация со знанием того, что уже есть на устройстве”.

Обычно этот подход перекрывает большинство нужд. На устройство приходят только новые данные, синхронизироваться можно хоть каждую минуту – трафик будет небольшой. Однако тут возникают проблемы, связанные с ограничениями мобильных устройств. Это память и процессор.

Подход 3: Синхронизация порциями

У мобильных устройств мало оперативной памяти. Если в справочнике 3000 блюд, то парсинг большой json строки от сервера в объекты на устройстве может вызвать нехватку памяти. В этом случае приложение либо аварийно завершится, либо не сохранит эти 3000 блюд. Но даже если устройство смогло переварить такую строку, то производительность приложения в моменты синхронизации в фоне будет низкая (лаги интерфейса, не плавная прокрутка и т.п.) Поэтому необходимо запрашивать список более мелкими порциями.

Для этого устройство передает еще один параметр (“amount”), который определяет размер порции. Список присылается обязательно отсортированный по полю “updated” по возрастанию. Устройство, аналогично предыдущему подходу, запоминает значение “updated” у последней присланной сущности и передает его в поле “lastUpdated”. Если сервер прислал ровно это же количество сущностей, то устройство продолжает синхронизацию и снова делает запрос, но уже с обновленным “lastUpdated”. Если сервер прислал меньше сущностей, это значит, больше новых данных у него нет, и синхронизация завершается.

На схеме: “last_updated” и “amount” – значения, которые хранятся в мобильном приложении . “last_item” – последняя присланная с сервера сущность (блюдо). Именно новее этого значения будет запрошен следующий список.

Пример запроса: { lastUpdated: “2013-01-01 00:00:00”, amount: 100 }

Достоинства:

  • На устройство приходит столько данных, сколько оно в состоянии обработать за один раз. Размер порции определяется практическими тестами. Простые сущности можно синхронизировать по 1000 штук за раз. Но бывает и такое, что сущности с большим количеством полей и сложной логикой обработки сохранения синхронизируются нормально не более 5 штук.

Недостатки:

  • Если будет 250 блюд с одинаковым updated, то при amount = 100 последние 150 не придут на устройства. Такая ситуация вполне реальна и описана в следующем подходе.

Подход 4: Корректная синхронизация порциями

В предыдущем подходе возможна ситуация, что если в таблице есть 250 блюд с одинаковым “updated” (например, “2013-01-10 12:34:56”) и размер порции равен 100, то придут только первые 100 записей. Остальные 150 будут отсечены жестким условием (updated > lastUpdated). Почему так произойдет? При запросе первых 100 записей lastUpdated установится в “2013-01-10 12:34:56”, и следующий запрос будет иметь условие (updated > “2013-01-10 12:34:56”). Не поможет даже смягчение условия (updated >= “2013-01-10 12:34:56”), потому что устройство тогда будет бесконечно запрашивать первые 100 записей.

Ситуация с одинаковым “updated” не настолько редкая. Например, при импорте данных из текстового файла поле “updated” было выставлено в NOW(). Импорт файла с тысячами строк может занять меньше секунды. Может случиться и так, что весь справочник будет иметь одинаковый “updated”.

Чтобы это исправить надо использовать какое-то поле блюда, которое было бы уникальным хотя бы в пределах одного момента (“updated”). Поле “id” уникально вообще по всей таблице, так что следует дополнительно в синхронизации использовать именно его.

Итого, реализация этого подхода выглядит так. Сервер отдает список отсортированный по “updated” и “id”, а устройства запрашивают данные с помощью “lastUpdated” и нового параметра “lastId“. У сервера условие выборки усложняется: ((updated > lastUpdated) OR (updated = lastUpdated and id > lastId)).

На схеме: “last_updated”, “last_id” и “amount” – значения, которые хранятся в мобильном приложении. “last_item” – последняя присланная с сервера сущность (блюдо). Именно новее этого значения будет запрошен следующий список.

Подход 5: Синхронизация со знанием того, что уже есть на устройстве

Предыдущие подходы не учитывают факта, что сервер в реальности не знает насколько успешно данные сохранились на устройстве. Устройство могло просто не сохранить часть данных из-за невыясненных ошибок. Поэтому неплохо было бы получать от устройства подтверждение, что все (или не все) блюда сохранились.

Кроме этого, пользователь приложения может так настроить приложение, что ему нужна будет только часть данных. Например, пользователь хочет синхронизировать блюда только из 2 городов из 10. Описанными выше синхронизациями этого не добиться.

Идея подхода следующая. Сервер хранит у себя (в отдельной таблице “stored_item_list”) информацию о том, какие блюда есть на устройстве. Это может быть просто список пар “id – updated”. В этой таблице хранятся все списки пар “id – updated” блюд для всех устройств.

Информацию об имеющихся на устройстве блюдах (список пар “id – updated“) устройство отсылает серверу вместе с запросом на синхронизацию. При запросе сервер проверяет то, какие блюда должны быть на устройстве и какие есть сейчас. После этого на устройство отсылается разница.

Как сервер определяет, какие блюда должны быть на устройстве? В простейшем случае сервер делает запрос, который возвратит ему список пар “id – updated” всех блюд (например, SELECT id, updated FROM dishes). На схеме это делает “WhatShouldBeOnDeviceMethod()” метод. В этом недостаток подхода – серверу приходится вычислять (порой делая тяжелые sql-запросы), что должно быть на устройстве.

Как сервер определяет какие блюда есть на устройстве? Он делает запрос в таблицу “stored_item_list” по этому устройству и получает список пар “id – updated”.

Анализируя эти два списка, сервер решает, что следует послать на устройство, а что – удалить. На схеме это “delta_item_list”. Поэтому в запросе нет “lastUpdated” и “lastId”, их задачу выполняют пары “id – updated”.

Как сервер узнает об имеющихся на устройстве блюдах? В запросе к серверу добавляется новый параметр “items”, который содержит список id блюд, которые были присланы на устройство в прошлой синхронизации (“device_last_stored_item_list”). Конечно, можно отсылать список id всех блюд, которые есть на устройстве, и не усложнять алгоритм. Но если на устройстве 3000 блюд и они будут каждый раз все отсылаться, то расходы трафика будут очень велики. В подавляющем количестве синхронизаций параметр “items” будет пустой.

Сервер должен постоянно обновлять у себя “stored_item_list” данными, которые пришли с устройства в параметре “items”.

Следует реализовать механизм очистки серверных данных в stored_item_list. Например, после переустановки приложения на устройстве сервер будет считать, что на устройстве все еще актуальные данные. Поэтому при установке приложения устройство должно как-то проинформировать сервер чтобы он очистил stored_item_list по этому устройству. В нашем приложении мы посылаем дополнительный параметр “clearCache” = 1 в этом случае.

Заключение

Сводная таблица по характеристикам этих подходов:

Подход Объем трафика (5 – большой) Трудоемкость разработки (5 – высокая) Использование памяти устройства (5 – высокое) Корректность данных на устройстве (5 – высокая) Можно выделить конкретное устройство
1 Синхронизируется всегда все 5 1 5 5 нет
2 Синхронизируется только обновленное 1 2 5 3 нет
3 Синхронизация порциями 1 3 1 3 нет
4 Корректная синхронизация порциями 1 3 1 3 нет
5 Синхронизация со знанием того, что уже есть на устройстве 2 5 2 5 да

“Корректность данных на устройстве” – это вероятность того, что на устройстве есть все данные, которые отсылались сервером. В случае подходов №1 и №5 есть 100% уверенность, что устройство имеет все данные, которые нужны. В остальных случаях такой гарантии нет. Это не говорит о том, что остальные подходы использовать нельзя. Просто если на устройстве часть данных пропадет, то исправить это с сервера (а тем более узнать про это на стороне сервера) не получится.

Возможно, при наличии безлимитых тарифов на интернет и бесплатного wifi проблема ограничения трафика, генерируемого мобильным приложением, станет менее актуальна. Но пока приходится идти на всякие ухищрения, придумывать более “умные” подходы, которые позволяют снизить сетевые расходы и увеличить производительность приложений. Не всегда это работает. Порой бывает “чем проще – тем лучше”, зависит от ситуации. Надеюсь, из этой статьи можно подобрать подход, который пригодится.

В интернете на удивление мало описаний синхронизации сервера и мобильных устройств . Притом, что приложений, работающих по такой схеме, много. Для интересующихся пара ссылок.

Обратная сторона мобильных клиентов - сервер.

Дополнительные требования зависят от специфики приложения:
масштабируемость сервера – для SaaS, социальных приложений, где в идеале ожидается большой поток посетителей, это условие обязательно. Для бизнес приложений, где есть ограничения по числу пользователей или численность прогнозируется, данное свойство не требуется;
интерактивность: ряд приложений нужно обеспечить механизмом нотификаций – сообщить приложению (пользователю) о наступлении определенных событий, передать сообщение пользователю. Данным свойством должна обладать, например, биржевая система или автоматический диспетчер такси.
открытое API: предполагается, что сторонние разработчики могут воспользоваться функционалом системы посредством документированного протокола. Ведь клиентом может быть как мобильное, так и внешнее серверное приложение.
другие требования…

Команда
Состав проектной команды для разработки системы в идеале может быть следующим:
менеджер проекта: управляет, контролирует проект, напрямую взаимодействует с заказчиком;
разработчик серверного приложения: разрабатывает сервер бизнес логики, базу данных, сетевой протокол;
разработчик приложения администратора: разрабатывает Web приложение, пользовательский интерфейс для настройки и управления серверным приложением;
разработчик клиентского приложения для Android;
разработчик клиентского приложения для iOS;
разработчик клиентского приложения для …
тестировщик: тестирует приложение администратора и клиентские приложения.

Внимательный читатель заметит, что в случае написания серверного приложения с графическим интерфейсом, например, на HTML5, можно сэкономить. В этом случае не требуется разработка клиентских приложений – интерфейс пользователя предоставляет браузер. Данная статья не рассматривает такой случай, идет речь о разработке ”родных” (native) приложений для мобильных устройств.

Мне доводилось работать в команде с полным составом, но будет реалистами – не всегда человеческие ресурсы и бюджет позволяет собрать такую команду. И иногда роли приходится совмещать: менеджер проекта + разработчик серверного приложения, разработчик клиентского приложения + тестировщик.

Технологии, инструменты, библиотеки
Для разработки сервера мобильных клиентов обычно использую следующий стек “свободных” технологий:
Apache Tomcat – контейнер сервлетов;
MySQL – СУБД;
Subversion – система версионного контроля;
Maven – фреймворк для автоматизации сборки проектов;
JUnit – обеспечит ;
Apache Log4j – библиотека логгирования;
Jenkins – система непрерывной интеграции;
Hibernate – ORM (настройки, конфигурация в properties, xml файлах и в аннотациях);
hibernate-generic-dao – реализация DAO от Google, реализует основные методы для работы с данными базы данных, упрощает реализацию фильтрации и сортировки в методах;
– реализация аутентификации и авторизации (security), контейнер сервисов и бинов (конфигурация в xml файлах и в аннотациях), используем также при создании тестов.

В зависимости от специфики системы и требований к ней использую один из 2-ух вариантов реализации протокола обмена данными.
Когда требуются кроссплатформенность, быстродействие, простота, эффективность, масштабируемость, открытое API, то беру Jersey – реализацию Web-сервисов REST (RESTful Web services). Эта библиотека позволяет использовать сериализацию данных в формате JSON или(и) XML. Конфигурация REST ведется посредством аннотаций. Для обмена с мобильными устройствами взят формат JSON по причине того, что имеет более простую реализацию на стороне клиента (по этой причине не используем “классические” Web-сервисы), генерируется меньший объем трафика. Jersey позволяет настроиться на наиболее подходящий “вид” JSON.
В ином случае, если необходимы кроссплатформенность, высокое быстродействие, простота, эффективность, интерактивность, то беру
Apache MINA – framework для создания сетевых приложений,
Google protobuf – библиотека кодирования и декодирования структурированных данных. Структура данных определяется заголовочными файлами *.proto, компилятор генерирует из них Java классы (также есть возможность генерации для других языков программирования: C++, Objective-C и т. д., что обеспечивает свойство кроссплатформенности);
java.util.concurrent – используем стандартный пакет.
Данный вариант может масшабироваться, но на это требуется закладываться на этапе проектирования на уровне архитектуры, учитывая бизнес логику.

Рассмотрим гипотетическую задачу на примере выбора технологий для реального SaaS сервиса – “Аукцион услуг “Аукнем” , который позволяет людям сформировать заказ на выполнение требуемых услуг или работ, а организациям в свою очередь оставить для них свои предложения. Берем все базовые требования по умолчанию. Ввиду того, что регистрация в этой системе свободная и бесплатная, то однозначно к ним требуется добавить масштабируемость. А что на счет интерактивности? Было бы здорово сообщать подрядчикам (исполнителям) о создании новых заказов, а заказчиков информировать о поступивших предложениях в тот же миг в приложении, а не только по электронной почте. На основания этого возьмем для реализации Apache MINA, Google protobuf. Смотрим следующее свойство - открытое API. Сервис общедоступный, потому предположим, что внешние разработчики могут проявить интерес к интеграции с ним. Постойте! Не все так просто. Протокол на базе Apache MINA достаточно сильно зависит от реализации и интеграция без знания нюансов отнюдь не прозрачна. В такой ситуации придется взвесить, какой фактор важнее и сделать выбор.

Заключение
Мне интересно было бы узнать, а какие Вы использовали технологии, библиотеки при разработке сервера мобильных устройств или подобных систем? Все меняется, ничто не вечно, на каждом уровне имеются альтернативы со своими преимуществами и недостатками: MySQL -
Понравилась статья? Поделиться с друзьями: