Не так давно стартовало приложение Почты под WP7. Когда мы думали о том, нужно ли нам самостоятельное приложение для Windows Phone, или достаточно адаптировать Почту Mail.Ru для IE Mobile и его аналогов, вопрос решился быстро. У владельцев смартфонов на WP7 должно быть собственное полноценное приложение Почты, полностью адаптированное под платформу.
О том, какие требования мы предъявляли к приложению, с какими проблемами столкнулись и как их решали, расскажем под катом.
Концепция
Мы сразу определились, что в первую очередь приложение должно быстро обрабатывать большие объемы данных и обеспечивать высокую скорость работы даже при загрузке больших списков (например, списка входящих писем). В некоторых аспектах приложение должно напоминать встроенный почтовый клиент, чтобы не возникало дискомфорта при работе с ним. В то же время приложение должно иметь расширенные функции, выгодно отличающие его от встроенного клиента.
В частности, это акцент на управление жестами с применением всех возможностей тач-интерфейса. Переключение между папками и переход от письма к письму одним движением пальца – это и удобно, и соответствует духу платформы. Еще одной особенностью является мгновенная синхронизация с веб-почтой. Все действия пользователя в приложении сразу же отображаются в веб-интерфейсе; все новые письма сразу же видны в приложении.
Все, кто разрабатывал приложения для WP7, знают, что разработка в рамках стандартных элементов управления делается на раз-два; отступление от них на шаг влево или вправо существенно увеличивает время выполнения задачи.
Итак, по порядку о том, с какими трудностями мы столкнулись.
Переключение между папками
Для переключения между папками было решено использовать элемент управления Pivot. Все просто – постраничное переключение, каждая страница загружается по требованию.
Для «стандартного пользователя» все работает отлично – после регистрации в почтовом ящике есть всего 5 папок, приложение загружается быстро. Но у некоторых пользователей папок может быть много (и очень много).
Для тестирования в живой почтовый ящик были добавлены пользовательские папки (в сумме их было 40). В такой ситуации запуск приложения с момента тапа по тайлу на стартовом экране до отображения списка входящих занимал почти 30 секунд. Такой результат нас никак не устраивал.
Детальное изучение проблем с производительностью показало, что узким местом являлся контейнер ObservableCollection, в котором хранился список папок. После того как контейнер получал данные о папках, список загружался по одной папке. Множественное добавление ObservableCollection не поддерживает. А при добавлении каждого нового элемента перестраивается UI. Для Pivot это оказалось неприемлемым. Да, Microsoft в рекомендациях пишет: «Minimize the number of Pivot control pages when possible for performance considerations», но желание сделать переключение жестами пересилило. В качестве решения был выведен наследный класс SilentObservableCollection, у которого были добавлены три метода AddSilently, InsertSilently и RemoveSilently, а также метод Notify. Как следует из названия, первые три метода позволяют перестраивать список, не перестраивая UI при каждом изменении. Последний метод позволяет поменять UI после того, как список папок актуализирован.
Переключение между письмами
Затем было необходимо сделать переключение между письмами по свайпу. Первоначально для этой задачи, так же как и в случае со списком папок, использовался элемент Pivot. С ним возник ряд проблем.
Во-первых, он сразу создает все страницы под письма (хотя сами письма подгружаются по мере перехода к ним), что снова требует большого количества времени на открытие страницы чтения.
Списком писем для Pivot является список подгруженных заголовков. Если двигаться вниз по этому списку, то к имеющемуся перечню подгружаются блоки по 20 писем. Если переместиться достаточно далеко, то открытие письма может занять и несколько минут, пока Pivot построит страницы для каждого письма.
Во-вторых, Pivot закольцован. И, в отличие от Panorama, где по смещению фона можно примерно понять, на какой странице находишься, в Pivot переход от последней страницы к первой ничем не отличается от перехода к следующей странице. Это сильно вводило в заблуждение в случае со списком писем. Было неясно, где первое письмо, в какую сторону листать, чтобы посмотреть следующее, почему после какого-то письма снова попадаешь к первому.
Чтобы побороть все эти проблемы, был написан элемент управления под названием LongListPivot. В нем решены обе описанные проблемы. Он не закольцован, то есть перехода от первого письма к последнему не происходит. И в нем всего одна страница. Изменение данных на этой странице происходит в момент, когда она за экраном. После движения пальцем текущее письмо уезжает за экран, там подменяется на следующее, которое приезжает с другой стороны экрана. Плюс к этому, при подходе к последнему письму в списке, так же, как в случае со списком писем в папке, происходит подгрузка следующего блока из 20 писем.
Просмотр писем
Следующей задачей, на решение которой ушло больше всего времени, стал просмотр писем с html-разметкой.
Кажется, все просто: есть элемент WebBrowser. Располагаем его на странице, загружаем в него текст – и готово. Но бывают сценарии использования приложения, когда применение этого элемента невозможно. Например, если получателей много, а пользователь открыл весь список. Или если в письме есть несколько вложений. Все это приводит к тому, что шапка письма растягивается, и содержимое съезжает к низу экрана. В результате этого, а также того, что WebBrowser имеет свою внутреннюю прокрутку содержимого, получаем, что письмо прокручивается внутри небольшой области.
Рассматривали такой вариант решения: определять высоту письма и жестко указывать высоту для WebBrowser, чтобы исключить его внутреннюю прокрутку, и вписать его в общий поток элементов внутри ScrollViewer. Но, во-первых, в WP7 один элемент управления не может быть в ширину или высоту более чем 2048 пикселей (а это всего 2,5 высоты экрана). Во-вторых, нет никакой возможности определить высоту содержимого письма.
WebBrowser не предоставляет информацию о загруженной в него странице, а также не предлагает программных интерфейсов для управления отображением содержимого (прокруткой, шириной и масштабом). Единственное, что остается программисту — передавать команды в JavaScript с помощью InvokeScript и получать уведомления через событие ScriptNotify.
Дальнейшая разработка страницы чтения письма перешла на новый уровень – на CSS+JavaScript. Благодаря нашим коллегам из мобильной веб-почты удалось решить все вставшие на пути проблемы: как задать ширину письма, масштаб, прокрутку.
Ссылки в письмах
Еще одной из задач стала обработка ссылок. Ссылки должны открываться не внутри встроенного элемента WebBrowser, отображающего текст письма, а в системном браузере. Для этого перехватывалось нажатие на элемент WebBrowser. Далее через JavaScript определялся элемент верстки html, находящийся на позиции касания, проверялось, является ли этот элемент ссылкой, и, если это так, адрес открывался во внешнем браузере.
Проблема была с письмами от одного из агрегаторов скидочных сервисов. Исходный текст уведомлений от него в html составляет около 300-500 Кб. При попытке отображения такого письма программа завершала работу с ошибкой нехватки памяти. В конечном итоге было принято решение все письма с html-разметкой и размером больше 100 Кб отображать в адаптированном текстовом виде.
Работа с вложениями
Одной из особенностей платформы Windows Phone является изолированное хранилище данных. Существуют проблемы в работе с вложениями. Почтовая программа полноценно работает с изображениями из галереи, приложенными к письму, а также со снимками, сделанными с помощью камеры смартфона. В приложении Почты можно просмотреть изображения, вложенные во входящее письмо, и при желании сохранить их в галерею. Также программа может воспроизвести присланные видео- и аудиофайлы.
С документами MS Office и Adobe Reader ситуация следующая: программа формирует ссылку на скачивание этих вложений и передает во внешний браузер. Браузер, сохранив вложение, передает его в Office или в Adobe Reader. Вложенный файл остается в этих программах. Однако если попытаться открыть его снова из приложения Почты, путь придется повторить: будет сформирована ссылка, вложение будет скачано внешним браузером и откроется в соответствующей программе.
Тестирование
Отдельно стоит рассказать о тестировании. Тестирование WP-приложений связано с несколькими трудностями из-за особенностей самих устройств. Например, пока невозможно вести и выводить логи процесса тестирования и делать скриншоты экрана прямо с устройства.
Несмотря на то, что мы опубликовали 5 бета-сборок приложения, ни одна из них не была отдана пользователям. От момента публикации сборки до момента, когда она становится доступна для скачивания, проходит трое суток. За это время большинство ошибок сборки выявляются нашим тестировщиком, исправляются, и бета-версия морально устаревает. Для организации тестирования были заведены 4 учетных записи разработчиков, с помощью которых были разблокированы 12 устройств. Периодически, по завершении очередного этапа разработки, на большинство устройств устанавливалась последняя, актуальная версия и собирались отзывы, комментарии и жалобы.
В остальном, благодаря четким требования Microsoft к производителям устройств под управлением Windows Phone, приложение, за редким исключением, работает одинаково на разных моделях смартфонов (нет такой фрагментированности, как среди устройств под управлением Android).
Заключение
Надеемся, что эта информация была вам полезной. Также нам было бы очень интересно почитать об опыте других разработчиков под WP: если вы уже сталкивались с подобными задачами и решили их по-другому, расскажите нам об этом в комментариях.
Мы, в свою очередь, продолжаем работать над улучшением приложения. Замечания и предложения вы можете присылать нам на mailapps@corp.mail.ru. Скачать Почту Mail.Ru для Windows Phone 7 можно в Windows Phone Store.
Балашов Вадим, разработчик мобильных приложений
Mail.Ru