- PVSM.RU - https://www.pvsm.ru -

Все мы в определенные периоды жизни принимаем лекарства или витамины. При этом, зачастую, необходимо строго соблюдать режим приема. Но все мы люди. И лично я регулярно забываю принять лекарство.
В помощь себе и другим забывчивым товарищам я и написал Android — приложение «Medication — Прием лекарств» [1].
Идея написать приложение-«напоминалку» возникла у меня примерно полтора года назад. Чуть больше года назад в Google Play появилась первая версия приложения (идея должна хотя бы немного «настояться»).
С тех пор я веду неспешную разработку приложения в свободное от основной работы время.
Но прежде чем что-либо разрабатывать, необходимо обосновать эту разработку, поэтому:
В принципе, задача не выглядит такой сложной:
А теперь напишу окончательный список функций (сравните с исходной постановкой задачи):
Список дополнительных функций в Про-версии:
Целью я поставил скорейший выпуск приложения, пусть там были далеко не все функции, описанные выше.
Опишу те моменты, которые хотел бы выделить.
Любая разработка нуждается в контроле версий. Уже давно прошли те времена, когда я в этих целях использовал копии папок или файлов (а что новее «project_old» или «project_old_old»?).
На данный момент для контроля версий я предпочитаю Mercurial. Простота, функциональность и некоторая защита от дурака. Сервер разворачивается буквально одной командой… Стоп! Какой сервер? Спасибо bitbucket.org [2] за «Unlimited private code repositories».
Для напоминаний в Android есть специальный менеджер — AlarmManager [3]. Хотя и стандартный Java-класс Timer [4] с этим прекрасно справлялся. Но только пока телефон не заснет. AlarmManager — наш выбор.
Лично я от БД хотел ORM. Но и тянуть большую ORM в проект не хотелось — место необходимо экономить, т.к. перенести приложение на SD-карту нельзя (нарушается работа системы напоминаний). А основной памяти и так мало. По этой же причине отказался и от использования HoloEverywhere и многих других библиотек в проекте.
В итоге, как систему хранения я выбрал protobuf + SharedPreferences.
Protocol Buffers — язык описания данных, предложенный Google, как альтернатива XML. Предполагается, что Protocol Buffers проще и легче, чем XML (из википедии [5]).
Имеет генераторы классов для большинства языков программирования. Для работы необходимо сгенерировать классы и добавить библиотеку в проект (весом в 23КБ, что меня вполне устроило).
Как показала практика, скорость работы protobuf вполне достаточная, так что основная система хранения построена на нем и сейчас. Объекты protobuf сериализуются в массив байт, который затем перегоняется в BASE64-строку, и сохраняются в SharedPreferences.
Хотя все время хочу перевести систему хранения полностью на SQLite. Наверное, в дальнейшем остановлюсь на гибридном варианте: сериализация protobuf и хранение в SQLite, вместо SharedPreferences.
Система напоминаний тесно связана со временем. Время я храню как количество миллисекунд с 1.01.1970 00:00:00.000 GMT в типе long.
Java такую систему хранения полностью поддерживает.
Хранить полноценный DateTime не позволил protobuf. Там просто нет соответствующего типа данных (впрочем, как и в SQLite, так что я ничего не потерял).
От хранения времени в строке я отказался:
Стоит учитывать, что при смене часового пояса, время «25.09.2013 00:00» преобразуется или в «25.09.2013 01:00», или в «24.09.2013 23:00». Т.е. если я в программе предполагаю, что эта дата всегда указывает на полночь (00:00), то после смены часового пояса это уже не так. В принципе, часовой пояс меняется не так уж и часто. Но тем не менее, пользователи путешествуют, переезжают, отдыхают и т.д. Это штатная ситуация в работе программы. И портить напоминания для тех 5% пользователей, которые сменили часовой пояс, нельзя.
Выкрутился я следующими способами:
«Вытащить» разницу в часовых поясах из соответствующего BroadcastReceiver не удалось. Если кто знает способ — подскажите.
Не так давно вылезла и проблема: при переходе на летнее время событие о смене часового пояса не генерируется. Кто-нибудь может подсказать выход в данной ситуации? Гугл тут не сильно помог. Нашел рекомендацию помимо события «android.intent.action.TIMEZONE_CHANGED» подписываться на «android.intent.action.TIME_SET» и «android.intent.action.DATE_CHANGED». Но еще не проверял данное решение (полгода на исправление есть).
Оценка прогноза «на сколько хватит запасов лекарства?» — важная и нужная функция. Расчет такого прогноза — задача нетривиальная. Если бы у меня приемы хранились только как «в 8:00 каждый день», то все было бы просто. Имеем общий объем, имеем количество приемов в день, имеем объем одного приема.
Но расписание приема у меня можно задавать достаточно гибко. И каждые N дней, и по дням недели, и т.д. Причем для каждого времени можно указать с какого числа это время действует. И это не говоря уже про то, что для каждого приема можно установить персональную дозировку. В итоге прогноз запасов строился таким образом: я проигрывал «прием» по дням до тех пор, пока у меня не закончатся запасы. Отсюда и ограничение — в запасе не более 10000 базовых доз (кстати, расчет запасов идет не более чем на 10000 дней). Для реальных пользователей не думаю, что это как-то скажется. А вот как защита от дурака — пригодится.
Для слежением за CrashReport-ами я использую ACRA. Удобная, мощная и вместе с тем простая штука.
В своем приложении я добавил функцию «сообщить об ошибке».
Спасибо ACRA за возможность отправки BugReport-а буквально в пару строчек кода:
String email = ((TextView) findViewById(R.id.email)).getText().toString();
String msg = ((TextView) findViewById(R.id.msg)).getText().toString();
ACRA.getErrorReporter().putCustomData("email", email);
ACRA.getErrorReporter().putCustomData("msg", msg);
ACRA.getErrorReporter().handleSilentException(new Throwable("BUG REPORT"));
И все. Вместе со стандартными BugReport-ами придут и пользовательские сообщения.
При этом придут и настроенные приемы, что позволят очень легко воспроизвести ошибку.
В целях повышения уровня продаж про-версии я решил воспользоваться промо-кодами.
Нашел для этого сервис IndieYard [6], но их free-тариф меня не устроил (1 приложение, 2 компании, до 500 активаций). Других аналогов не обнаружил. В общем, решил написать свой велосипед. Кстати, добавил функцию чтения промо-кода по QR-коду (можно воспользоваться любым считывателем QR-кодов).
В итоге получился JSON-RPC сервис, написанный на PHP (я с ним немного знаком + был сервер, где уже развернуто необходимое окружение). Для JSON-RPC на Android есть готовые библиотеки, хотя и самостоятельно организовать общение не так уж и сложно. Можно было бы и REST, но JSON-RPC мне показался уместнее (да, если честно, то подход RPC мне ближе, чем REST).
Думаю, более подробную статью напишу позже (когда выпущу полноценный сервис или хотя бы его бетку). Сейчас же это 1 функция проверки промо-кода и «админка» в виде Adminer (аналог phpMyAdmin). Это даже не альфа-версия. О надежности решения говорить не приходится.
Из интересного, что можно отметить — использование базы SQLite.
Почему SQLIte? Проще переносить сервис из локального окружения в «боевое». Меньше мороки с резервным копированием (хотя тут под вопросом). Да и производительности хватает.
Изначально производительность была порядка 70 операций проверки промо-кода (каждая включает 3 select-запроса, 1 update, 1 insert) на локальной машине (i5, SSD). Но после оптимизации база позволила держать уже около 800 операций/сек. Оптимизация заключалась в добавлении индексов по используемым в запросах полям.
На сервере показатель несколько меньше: сначала было 30 операций/сек, оптимизация подняла до 120 (сервер облачный в Selectel, на самом «древнем» пуле).
К слову, тот же сервис, но использующий PostgeSQL (через PDO), давал порядка 150 операций в секунду. Оптимизация базы практически не сказалась: 165 запросов (для локальной машины, на сервере показатель очень непостоянный — от 50 до 120 запросов в секунду).
Интересен показатель MongoDB. 1900 запросов в секунду на локальной машине.
Но не стоит забывать, что MongoDB в первую очередь ориентирована на скорость.SQLIte ориентирован на надежность. А PostgeSQL в дефолтной настройке ориентирован на минимум потребления ресурсов. Так что, прямо скажем, сравнение не самое честное.
Для того, чтобы максимально удовлетворять пользователей, разработчик должен «знать» своих пользователей «в лицо». Для сбора статистики я встроил Google Analystics. И теперь могу смело сказать — приложением пользуются буквально во всем мире! Правда, в Африке больше всего «белых пятен», где не ступала нога человека с моей программой на телефоне.
Отзывы пользователей важны. Без обратной связи сделать качественное приложение, на мой взгляд, невозможно.
Для поддержания рейтинга рекомендую отвечать на отзывы с замечаниями. Как правило, пользователь просто не может найти нужную ему функцию. Иногда — просит новый функционал. Как правило, после ответа разработчика, пользователь меняет свой ответ и ставит выше балл.
Еще до начала разработки я выработал свою позицию в данном вопросе. Рекламу я отказался вставлять категорически. Причин было несколько:
Для монетизации я решил выпустить платную версию приложения, с расширенными функциями. Изначально я хотел делать отдельную, платную версию приложения. Но возникло несколько вопросов:
Остается In-App Purchase. Но и он меня не устроил:
В итоге опять написал свой велосипед (видел подобное у Note Everything). Я сделал плагин, который надо покупать в Google Play как отдельное приложение. А плагин уже и разблокирует про-функции в приложении. В итоге широчайшая поддержка устройств, вкупе с минимумом усилий (да, да, темный путь зовет меня).
Я особо не пиарил приложение. Еще в самом начале опубликовал на форуме 4pda тему с обсуждением. Собирался воспользоваться программой «Программы поддержки наших разработчиков» там же. Но ее не так давно отменили. В принципе, я не силен в пиаре и маркетинге. Поэтому хочу провести небольшой эксперимент.
Напишите обзор приложения в своем блоге или на любом другом ресурсе, и получите промо-код для разблокировки полной версии для Вас и Вашей семьи (5 активаций). Связаться со мной можно по адресу AndSDev@gmail.com [9].
Перед публикацией жду письмо, в котором не забудьте указать:
Я зарегистрирую промо-коды и вышлю временный промо-код на про-версию для написания обзора.
После публикации опять жду письмо. Не забудьте ссылку на обзор — для коллекции ). С меня код на про-версию (5 активаций).
Для тех, кто дочитал до конца, я решил сделать небольшой сюрприз. Как я уже говорил, я внедрил поддержку промо-кодов в свое приложение. А раз есть поддержка, то почему бы ей не воспользоваться?
Промо-коды (действительны до конца 2013 года):
Разблокировка лога приема: HABRALOG (QR [10])
Разблокировка профилей: HABRAPROFILE (QR [11])
Разблокировка слежения за запасами медикаментов: HABRASTOCK (QR [12])
Ссылка на скачку приложения: Medication [1] (QR [13])
Плагин про-версии: Medication PRO [14] (QR [15])
За 3 месяца продаж приложение принесло чуть больше 100$ прибыли (примерно по 1$ в день). Окупает ли это полтора года неспешной разработки? Нет, не окупает.
Окупает разработку другое. Множество людей благодарят меня по почте и в отзывах Google Play за разработку этого приложения. Этого хватает на то, чтобы я продолжал поддержку данного приложения.
Автор: SabMakc
Источник [16]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android-development/47458
Ссылки в тексте:
[1] «Medication — Прием лекарств»: https://play.google.com/store/apps/details?id=ru.sabmakc.medication
[2] bitbucket.org: http://bitbucket.org/
[3] AlarmManager: http://developer.android.com/intl/ru/reference/android/app/AlarmManager.html
[4] Timer: http://developer.android.com/intl/ru/reference/java/util/Timer.html
[5] из википедии: http://ru.wikipedia.org/wiki/Protocol_Buffers
[6] IndieYard: http://www.indieyard.com/developers
[7] здесь: http://www.mail-archive.com/sqlite-users@sqlite.org/msg05525.html
[8] «темным путем»: http://habrahabr.ru/post/192320/
[9] AndSDev@gmail.com: mailto:AndSDev@gmail.com
[10] QR: http://habrastorage.org/storage3/54b/165/8cb/54b1658cb2c3d11cb04b245275f0b0c4.gif
[11] QR: http://habrastorage.org/storage3/6e8/aca/e08/6e8acae080f2aa3fbf1c905c05058b54.gif
[12] QR: http://habrastorage.org/storage3/db6/cfd/4b9/db6cfd4b960042bd504e36cdfde69d45.gif
[13] QR: http://habrastorage.org/storage3/5ac/8fa/635/5ac8fa635497ce671716dfcabd43de6c.gif
[14] Medication PRO: https://play.google.com/store/apps/details?id=ru.sabmakc.medication.pro
[15] QR: http://habrastorage.org/storage3/99f/b8e/533/99fb8e5334c2e7114949ffd4a94a997d.gif
[16] Источник: http://habrahabr.ru/post/200752/
Нажмите здесь для печати.