Сегодня стартовали официальные продажи Apple Watch. 90% умопомрачительных концептов приложений под них, которые можно найти в Сети, нереализуемы — тем, кто знаком с гайдлайнами Apple, это хорошо известно. О том, что реализовать на часах все же можно и как это лучше сделать с точки зрения разработки и дизайна — под хабракатом.
Наша команда сделала одно из первых в России© приложений под часы. Когда разработчик и дизайнер понимают особенности работы друг друга, вероятность появления фантастических дизайн-концептов стремится к нулю, а время разработки — к нескольким дням. Мы, Григорий Матвиевич ( fountainhead, разработчик) и Екатерина Сотова ( lost_in_purple, дизайнер), рассказываем, на что стоит обратить внимание, если вы делаете приложение для Apple Watch.
Речь пойдет о:
«Apple Watch — наше самое персональное устройство» — говорят в Apple. И это действительно так — гаджет, который постоянно находится на руке своего владельца, предполагает новые форматы взаимодействия с пользователем, которые были невозможны, либо не нужны на смартфоне. Приложения для часов должны быть адаптированы к контексту, в котором находится их обладатель. В первую очередь это означает, что на часах должна отображаться только самая полезная информация в очень сжатом виде, так как человек пользуется ими на ходу. Главная задача часов и хороших приложений для них — быть ненавязчивыми и полезными. В Apple сделали упор на тактильности (Taptic Engine обеспечивает тактильный отклик, когда приходят уведомления или происходит взаимодействие с часами) и попытались в буквальном смысле «размыть» границы между приложениями и физическими объектами: фон приложения незаметно перетекает в обрамление дисплея, зрительно сливаясь в единое целое. Часы не заменяют приложение на смартфоне, но дополняют его. Приложения на Apple Watch должны быть максимально легкими для взаимодействия. Информация должна просматриваться просто и быстро и зависеть от контекста, в котором находится владелец, при этом не становясь навязчивой. Так, например, уведомление отображается полностью, если пользователь задержал на нем взгляд, а Glances показывают самое актуальное и необходимое. Если сценарии взаимодействия пользователя с приложением на iPhone могут измеряться минутами, то длительность взаимодействия с часами не превышает, как правило, нескольких секунд. Все это надо держать в голове при проектировании своих приложений.
В первой версии умных часов Apple позволила сторонним разработчикам создавать приложения, которые являются расширением основного приложения (здесь и далее приложение, работающее на iPhone, будем называть «основным приложением»). А приложение, которое запускается на часах — «WatchKit-приложением», или просто «приложением» на iPhone. Разработку исключительно под Apple Watch обещают сделать в будущем. Сейчас функциональность часов доступна через фреймворк WatchKit и сильно ограничена по сравнению с тем, что вы могли видеть на презентации самих часов. Видно, что разработчики в Apple и еще в нескольких «избранных» компаниях имеют бoльшие возможности, чем остальные.
Разберемся, как устроено приложение на Apple Watch. С точки зрения интерфейса, приложения на Apple Watch состоят из следующих частей:
С точки зрения архитектуры, все устроено по-другому. Файлы приложения делятся на две части: WatchKit App и WatchKit Extension. WatchKit App хранится непосредственно на часах и состоит из сториборда (описания интерфейса) и ресурсов. WatchKit Extension хранится на iPhone и содержит код и ресурсы. Таким образом, весь код исполняется на телефоне, и без iPhone неподалеку ваше приложение на часах не запустится. Взаимодействие между телефоном и часами осуществляется через фреймворк WatchKit и скрыто от разработчика.
Каждый экран приложения управляется объектом-контроллером класса WKInterfaceController. Все контроллеры, включая Glance и уведомления, должны быть выполнены в cториборде WatchKit App. Когда пользователь открывает приложение на часах, WatchKit находит начальный контроллер в сториборде и сообщает на iPhone, что необходимо запустить WatchKit Extension и создать объект нужного класса контроллера. Аналогичные действия произойдут, если пользователь откроет Glance или получит уведомление.
Жизненный цикл контроллера похож на цикл своего старшего брата UIViewController. Методы init, awakeWithContext:,willActivate используются для выполнения следующих задач:
Начальный контроллер играет важнейшую роль. Несмотря на то, что по своей сути это контроллер экрана, на него возложены функции аналогичные делегату приложения на iPhone. Он всегда создается и запускается первым, он обрабатывает переходы из Glance и уведомлений в WatchKit-приложение. Методы инициализации начального контроллера — первая точка входа в приложение. Именно там приложение впервые может посмотреть на то, какие данные у него есть, и отобразить подходящий интерфейс. Если классы, количество, порядок внутренних экранов возможно задавать из кода, то выбрать, какой контроллер будет начальным можно только в сториборде во время проектирования приложения.
Расширение WatchKit Extension запускается только когда пользователь непосредственно взаимодействует с часами, и завершается сразу же, как пользователь выйдет из приложения или попросту опустит руку. Понятия работы в фоном режиме для WatchKit-приложения не существует. Однако, система умеет делать “скриншот” приложения. Если вы опустите руку или выйдете из приложения, а потом спустя небольшое время запустите его снова, то попадете на тот же экран, на котором и закончили. Вызовется только willActivate соответствующего контроллера.
Отличия от разработки основного iOS-приложения
Существенное отличие от разработки основного iOS-приложения — метод инициализации контроллеров init вызывается не разработчиком, а системой. Параметры и данные передаются от контроллера к контроллеру через контекст. Любой переход от экрана к экрану происходит либо автоматически по сигвею, либо из кода по идентификатору контроллера в сториборде. В обоих случаях WatchKit находит нужный экран в сториборде, после чего WatchKit Extension создает объект класса, указанного в сториборде у экрана с данным идентификатором (по данному сигвею), и вызывает у него метод init. Стэк контроллеров остается “под капотом” системы. Разработчик не видит его и работает с кодом контроллеров, как с абстрактными и изолированными сущностями.
Еще одно важное отличие — все элементы интерфейса являются прокси-объектами, доступными только на запись. Нельзя узнать у label, какой текст оно отображает, какой шрифт и цвет использует. Поэтому иногда приходится хранить состояние объектов в отдельных переменных. К тому же нельзя наследоваться от базового класса WKInterfaceObject, что усложняет проектирование приложения и делает невозможным создание кастомизированных объектов интерфейса.
Нет даже привычной иерархии View. Динамически нельзя создавать и добавлять объекты интерфейса. Весь интерфейс должен быть определен в сториборде, то есть на этапе проектирования приложения. Связывание происходит через IBOutlet. Ненужная часть интерфейса скрывается. Но надо стараться избегать ситуаций, когда на одном экране есть два полностью альтернативных интерфейса, один из которых скрыт в зависимости от контекста. Но в некоторых случаях, как например в Glance, это является единственным решением.
Метод didDeactivate вызывается системой, чтобы сообщить контроллеру, что он уже не на экране. При этом в теле этого метода и после его вызова бесполезно делать какие-либо изменения интерфейса — система их проигнорирует. Бывает очень неудобным, когда по наступлению некоторого события необходимо, например, изменить отображаемый текст на экране, который в данный момент не показывается. Приходится некоторым образом откладывать обработку события до вызова willActivate. Из-за этого willActivate может превратиться в череду проверок условий «а не надо ли нам заново переконфигурировать интерфейс».
Apple советует «ленивую» загрузку данных, где это уместно. В willActivate можно использовать dispatch_async и dispatch_after на главном потоке.
Главная сложность заключается в том, что основное приложение на iPhone и WatchKit Extension — это два разных изолированных процесса со своей «песочницей». С другой стороны, логично предположить, что если приложение на часах является дополнением основного, то данные оно должно получать от своего старшего брата. И здесь Apple предлагает несколько способов:
1. Использование App Groups, которые позволяют иметь общие NSUserDefaults и сохранять файлы в разделяемом контейнере для группы приложений и их расширений.
Этот способ позволяет получить данные практически моментально. Основное приложение может записывать в группу, как в процессе своей работы, так и в режиме background fetch. Здесь есть некоторые ограничения: во-первых, основное приложение не может простым способом оповестить часы, что данные обновились. Простое KVO на общий NSNotificationCenter не работает. Решение: использовать совместно со вторым способом или организовать передачу данных через один известный pod, который архивирует данные в файлы и использует дарвиновский центр уведомлений; во-вторых, при записи файлов следует обратить внимание на это предостережение от Apple.
2. Взаимодействие с основным приложением на iPhone напрямую.
Класс WKInterfaceController имеет метод openParentApplication:reply:, при вызове которого запускается в background основное приложение на iPhone. У него вызывается метод делегата application:handleWatchKitExtensionRequest:reply:, который обрабатывает входящий запрос. Из WatchKitExtension обязательно передается блок завершения запроса, который принимает NSDictionary в качестве ответа основного приложения. Помимо блока завершения из WatchKit Extension можно передать словарь с любой информацией, чтобы основное приложение на iPhone могло обрабатывать разные запросы в зависимости от контекста.
Если основному приложению необходимо выполнить асинхронный запрос, например, запросить свежие данные с сервера, рекомендуется зарегистрировать background task, иначе iOS может завершить его, не дождавшись окончания выполнения. Главное ограничение данного способа: он занимает время. Блокировать основной поток, ожидая ответа, естественно, недопустимо, поэтому и возникает вопрос, как показывать старые данные, как показывать пользователю, что что-то происходит, как визуально обновлять данные, что делать, если вернется ошибка и т.д. Другое серьезное ограничение: не передаются сложные объекты, необходимо их сериализовать. При проектировании приложения очень важно помнить, что данные надо откуда-то получать. Создатели некоторых концептов WatchKit-приложений явно об этом не задумывались. Еще необходимо учитывать вопросы безопасности. Если отображаемые данные конфиденциальны, то просто так их хранить нельзя. В этом вопросе основному приложению и WatchKit-приложению лучше действовать одинаково.
3. Handoff как способ начать смотреть информацию на часах, а продолжить на телефоне.
Handoff реализуется очень просто. Названия типов NSUserActivity добавляются в *-Info.plist основного приложения. У объекта контроллера вызывается метод updateUserActivity:userInfo:webpageURL: с параметром — именем нужного типа NSUserActivity. Можно передать необходимую дополнительную информацию в userInfo. В это время на экране телефона появляется иконка вашего приложения в левом нижнем углу и если потянуть за нее наверх, запустится основное приложение. У делегата приложения вызовутся методы application:willContinueUserActivity и application:continueUserActivity:restorationHandler, где можно обработать userActivity и показать нужную информацию. При этом, если пользователь не будет доставать из кармана телефон и пытаться разблокировать его, система сама позаботится, чтобы через некоторое время инвалидировать активность.
Сами Apple Watch не распознают и не обрабатывают NSUserActivities, за исключением сгенерированных в Glance. Но об этом в следующем разделе.
Glances — приложение, предназначенное для быстрого показа важной информации, которое вызывается прямо с экрана часов свайпом снизу вверх. По сути это перелистывающиеся виджеты приложений, показывающие самую актуальную информацию, например, погоду, биржевые индексы, информацию из календаря, пропущенные звонки, фитнес-цели и достижения. Порядок карточек приложений настраивается пользователем. К слову, приложение может не иметь отображения в Glance, если в этом нет необходимости
Конфигурация гланса — две части, верхняя смещена относительно центра:
Система предоставит универсальный интерфейс для ваших уведомлений, даже если вы не реализуете никакой контроллер интерфейса для них в сториборде. Но, конечно, хочется сделать их красивыми и удобными. Тут необходимо найти правильный баланс, чтобы уведомления не беспокоили пользователя слишком часто, но вместе с тем обеспечивали его актуальной для текущего контекста информацией. Формулировка уведомлений должна быть максимально четкой и короткой, ведь экран часов совсем крохотный. Это особенно актуально для кириллицы. Русские слова помещаются на экране с большим трудом.
Уведомления показываются в два этапа: Short Look и Long Look. При получении уведомления часы нежно вибрируют. Поднимая руку, пользователь видит «короткий вид» уведомления – ShortLook, который сразу же анимируется в LongLook, если пользователь задержал на нем взгляд:
Long Look содержит полный текст уведомления, иконку и название приложения, а также кнопку «Пропустить» уведомление. Прямо сюда можно запихнуть до четырех контекстных действий — в случае с нашим приложением, например, «продлить скорость». Кнопка «Dismiss» предоставляется системой всегда. Другие возможные кнопки и соответствующие им действия необходимо регистрировать в коде основного приложения на iPhone через UIUserNotificationSettings для определенных категорий уведомлений. То есть они определяются на этапе проектирования приложения, а не приходят вместе с push-ом. Поэтому иногда полезно завести универсальную категорию для уведомлений, если мы хотим всегда показывать кастомный интерфейс.
У действия кнопок может быть два типа режима активации: background и foreground. По нажатию на кнопку с foreground действием открывается WatchKit приложение и вызывается один из методов handleActionWithIdentifier:forLocalNotification или handleActionWithIdentifier:forRemoteNotification, которому передается идентификатор выбранной кнопки. По нажатию на кнопку с background действием запускается в background основное приложение на iPhone, и вызывается один из соответствующих методов делегата приложения.
Есть два типа интерфейса уведомлений: статический и динамический. Если вы реализуете кастомный интерфейс, то надо обязательно создать контроллер для статического типа. Статический тип интерфейса — это некоторый упрощенный, обобщенный вид уведомления по сравнению с динамическим. Система сама определит, какой интерфейс ей выбрать, в зависимости от заряда батареи и настроек пользователя. Динамический тип можно не реализовывать.
Внутри WatchKit-приложения на часах возможно изменить любой шрифт кроме заголовка и времени, а также контекстного меню, вызываемого через ForceTouch. Несмотря на то, что в пакете системного шрифта San Francisco нет кириллического начертания, на самих часах и в Xcode все в порядке. В Glance и Уведомлениях же использовать кастомные шрифты нельзя.
Внутри основного приложения для всех заголовков задается Global tint colour. Его нельзя менять в процессе выполнения в зависимости от контекста или данных, он задается на этапе проектирования приложения один раз и выполняет функцию цвета заголовков в приложении и названия приложения в уведомлениях «короткого вида». Цвет PageControl, к сожалению, поменять тоже нельзя никак, не верьте концептам. Не заставляйте пользователей вашего приложения чувствовать себя так, будто они смотрят рекламу. Для брендирования лучше использовать ненавязчивые средства: цвет, шрифты, образы.
Приложения поддерживают два вида навигации, которые, к сожалению, не могут быть совмещены друг с другом.
Иерархическая навигация — классический метод управления приложением, аналогичный навигации в приложениях iPhone c использованием UINavigationController, где пользователь «углубляется» в приложение. Такой тип навигации наиболее удобен и гибок в техническом плане, поскольку позволяет передавать информацию пользователю порционно и иметь неограниченное количество уровней вложенности.
Страничная навигация (PageControl) позволяет пользователю перемещаться между экранами «свайпом». Такая модель навигации подходит для небольших приложений, с простой моделью данных. При использовании постраничной навигации контент всех страниц загружается единовременно, а динамическое увеличение количества страниц не реализуется без ряда ухищрений.
Также в любом типе навигации возможно модальное отображение контента для привлечения внимания пользователя или для решения вопросов, требующих от пользователя однозначного принятия решения, без взаимодействия с основной частью приложения. При этом показать можно как одно окно, так и несколько окон, связанных через Page Control. В левом углу модального окна по умолчанию находится заголовок. Злоупотреблять модальным режимом крайне не рекомендуется.
Переход между экранами целиком обрабатывается системой, и его никак нельзя кастомизировать или дополнительно анимировать. В страничной навигации экраны появляются справа и слева, в иерархической — следующий экран наплывает с правого края экрана, как в iPhone или iPad, а модальный экран выплывает снизу.
Жесты
Экран часов слишком мал для полного списка жестов, используемых в iOS. Вот что доступно пользователю:
Кастомизировать жесты нельзя.
Контекстное меню
Контекстное меню вызывается по жесту Force Touch. В него можно спрятать от одного до четырех второстепенных действий. Экран будто бы по-настоящему вдавливается, а сверху наплывает контекстное меню. У него полупрозрачный фон и от одной до четырех кнопок системного вида.
Существует заблуждение, что в Apple Watch будет множество красивых анимаций. На самом деле нет, по крайней мере, в приложения сторонних разработчиков точно нет. Если возникает потребность в анимации, забудьте про программные средства (или почти забудьте). Анимировать можно только изображения. Покадрово. То есть приготовьтесь нарезать все кадры анимации по отдельности, прямо как для старых мультфильмов. Двигать объекты нельзя. Анимировать переходы между состояниями интерфейса, эффект параллакса, переходы между экранами — нельзя. Только менять кадр изображения. Все.
Задать изображение можно у background контроллера WKInterfaceController, кнопки WKInterfaceButton, группы WKInterfaceGroup. И есть специальный объект для отображения картинок WKinterfaceImage.
При указании имени изображения в сториборде и в параметрах методов, оканчивающихся на imageNamed, система ищет картинку в WatchKit App, то есть среди тех, которые хранятся на часах. Методы, оканчивающиеся на image и imageData, подразумевают, что изображение хранится в WatchKit Extension, то есть физически на телефоне. Поэтому когда вы их используете, картинка передается с iPhone на часы, что будет вызывать некоторую задержку. Кадры анимации должны быть проименованы одним именем плюс номер кадра: например, «image0@2x.png», «image1@2x.png», …, «image256@2x.png». При этом именем картинки, которое вы указываете в сториборде или передаете в параметре методов старта анимации, будет считаться «image».
Программно можно запускать и останавливать анимацию WKInterfaceImage и бэкграунд группы WKInterfaceGroup. Лучшее место для этого — в willActivate. При этом если хотите, чтобы анимация началась уже после того, как пользователь увидит экран, то вызов старта можно обернуть в dispatch_async или dispatch_after. Если хотите, чтобы анимация запускалась периодически, то для это можно использовать NSTimer.
В параметрах старта анимации можно указать:
Несмотря на ограниченные возможности и сложности анимация — это эффективный способ контакта с пользователем. Она не только делает приложение привлекательным и добавляет индивидуальность, но и позволяет делать давать подсказки, отображать состояние, мотивировать к действиям. И это особенно актуально для Apple Watch, так как помогает экономить пространство на маленьком дисплее.
Верстка приложений на часах немного напоминает табличную верстку html, сковывающую дизайнера и разработчика. В смартфоне есть слои, а в часах их нет. В часах вместо слоев группы. Группа — контейнер для других объектов интерфейса. Как говорилось выше, бэкграунд группы можно анимировать.
Соответственно, контейнеры могут находиться рядом друг с другом, либо друг в друге. Внутренняя группа не может выходить за рамки внешней. Существует два типа групп: объекты в группе располагаются друг за другом по вертикали, и объекты в группе располагаются друг за другом по горизонтали. Группы могут содержать в себе другие группы, причем как другого типа так и того же. Элементу интерфейса нельзя задать origin, вместо этого задается выравнивание по вертикали и по горизонтали. В соответствии с этим выравниванием элемент занимает первое свободное место в своей группе, следующий объект располагается рядом и так далее. Любые элементы интерфейса расставляются по этим законам. Это накладывает большие ограничения на возможности.
Во время исполнения программы нельзя динамически добавлять новые объекты интерфейса. То есть все должно быть предусмотрено в storyboard. Соответственно, в Glance для нескольких состояний по сути приходится одновременно иметь три интерфейса — только два из них все время скрыты. При запуске код в зависимости от данных выбирает нужный тип интерфейса, а два скрывает. Но они там есть — они создаются и вычисляются.
Рамки, в которые корпорация поставила разработчиков, при первом подходе вызывают раздражение. При более глубоком погружении становится понятно, что ограничения не столько лишают выразительных средств, сколько диктуют правила хорошего тона при работе с микроскопическими экранами. Ведь проектирование взаимодействия, а уж тем более разработка — это работа с данными и задачами, а не игра в пиксели и раскраску.
Конечно, хотелось бы использовать побольше привычных и изученных на iOS элементов, но для первой попытки предоставленных возможностей вполне достаточно. Очевидно, что через пару месяцев на ежегодной WWDC мы увидим новые фичи и новые инструменты, а пока нужно хорошенько прочувствовать то, что является одним из первых этапов на пути к получению информации в контексте. Быстро, незаметно и на бегу. А ведь такой информации не должно быть много: ни визуально, ни содержательно.
В следующем материале мы расскажем о том, как разрабатывали приложение для Apple Watch — "Мой Билайн".
Читайте также:
Material Design: на Луну и обратно
Стилизация iOS-приложений: как мы натягиваем шрифты, цвета и изображения
Редизайн приложения РЖД: концепт
Наша команда сделала одно из первых в России© приложений под часы. Когда разработчик и дизайнер понимают особенности работы друг друга, вероятность появления фантастических дизайн-концептов стремится к нулю, а время разработки — к нескольким дням. Мы, Григорий Матвиевич ( fountainhead, разработчик) и Екатерина Сотова ( lost_in_purple, дизайнер), рассказываем, на что стоит обратить внимание, если вы делаете приложение для Apple Watch.
Речь пойдет о:
- Архитектуре WatchKit-приложения
- Взаимодействии с основным приложением на телефоне
- Glances
- Уведомлениях
- Айдентике приложения: шрифтах, иконках, цветах
- Навигации
- Взаимодействии с пользователем через интерфейсы
- Изображениях и анимации
- Верстке/Layout
Идеология: персонализация, целостность, легкость
«Apple Watch — наше самое персональное устройство» — говорят в Apple. И это действительно так — гаджет, который постоянно находится на руке своего владельца, предполагает новые форматы взаимодействия с пользователем, которые были невозможны, либо не нужны на смартфоне. Приложения для часов должны быть адаптированы к контексту, в котором находится их обладатель. В первую очередь это означает, что на часах должна отображаться только самая полезная информация в очень сжатом виде, так как человек пользуется ими на ходу. Главная задача часов и хороших приложений для них — быть ненавязчивыми и полезными. В Apple сделали упор на тактильности (Taptic Engine обеспечивает тактильный отклик, когда приходят уведомления или происходит взаимодействие с часами) и попытались в буквальном смысле «размыть» границы между приложениями и физическими объектами: фон приложения незаметно перетекает в обрамление дисплея, зрительно сливаясь в единое целое. Часы не заменяют приложение на смартфоне, но дополняют его. Приложения на Apple Watch должны быть максимально легкими для взаимодействия. Информация должна просматриваться просто и быстро и зависеть от контекста, в котором находится владелец, при этом не становясь навязчивой. Так, например, уведомление отображается полностью, если пользователь задержал на нем взгляд, а Glances показывают самое актуальное и необходимое. Если сценарии взаимодействия пользователя с приложением на iPhone могут измеряться минутами, то длительность взаимодействия с часами не превышает, как правило, нескольких секунд. Все это надо держать в голове при проектировании своих приложений.
1. Архитектура WatchKit-приложения
В первой версии умных часов Apple позволила сторонним разработчикам создавать приложения, которые являются расширением основного приложения (здесь и далее приложение, работающее на iPhone, будем называть «основным приложением»). А приложение, которое запускается на часах — «WatchKit-приложением», или просто «приложением» на iPhone. Разработку исключительно под Apple Watch обещают сделать в будущем. Сейчас функциональность часов доступна через фреймворк WatchKit и сильно ограничена по сравнению с тем, что вы могли видеть на презентации самих часов. Видно, что разработчики в Apple и еще в нескольких «избранных» компаниях имеют бoльшие возможности, чем остальные.
Разберемся, как устроено приложение на Apple Watch. С точки зрения интерфейса, приложения на Apple Watch состоят из следующих частей:
- Приложение, которое имеет иконку и запускается с главного экрана часов
- Glance (превью) — аналог виджетов на iPhone
- Уведомления
С точки зрения архитектуры, все устроено по-другому. Файлы приложения делятся на две части: WatchKit App и WatchKit Extension. WatchKit App хранится непосредственно на часах и состоит из сториборда (описания интерфейса) и ресурсов. WatchKit Extension хранится на iPhone и содержит код и ресурсы. Таким образом, весь код исполняется на телефоне, и без iPhone неподалеку ваше приложение на часах не запустится. Взаимодействие между телефоном и часами осуществляется через фреймворк WatchKit и скрыто от разработчика.
Каждый экран приложения управляется объектом-контроллером класса WKInterfaceController. Все контроллеры, включая Glance и уведомления, должны быть выполнены в cториборде WatchKit App. Когда пользователь открывает приложение на часах, WatchKit находит начальный контроллер в сториборде и сообщает на iPhone, что необходимо запустить WatchKit Extension и создать объект нужного класса контроллера. Аналогичные действия произойдут, если пользователь откроет Glance или получит уведомление.
Жизненный цикл контроллера похож на цикл своего старшего брата UIViewController. Методы init, awakeWithContext:,willActivate используются для выполнения следующих задач:
- Получить данные, которые надо отобразить.
- Задать начальные значения и конфигурации у лейблов, изображений, кнопок и других объектов интерфейса.
- Скрыть ненужную часть интерфейса и показать нужную.
Начальный контроллер играет важнейшую роль. Несмотря на то, что по своей сути это контроллер экрана, на него возложены функции аналогичные делегату приложения на iPhone. Он всегда создается и запускается первым, он обрабатывает переходы из Glance и уведомлений в WatchKit-приложение. Методы инициализации начального контроллера — первая точка входа в приложение. Именно там приложение впервые может посмотреть на то, какие данные у него есть, и отобразить подходящий интерфейс. Если классы, количество, порядок внутренних экранов возможно задавать из кода, то выбрать, какой контроллер будет начальным можно только в сториборде во время проектирования приложения.
Расширение WatchKit Extension запускается только когда пользователь непосредственно взаимодействует с часами, и завершается сразу же, как пользователь выйдет из приложения или попросту опустит руку. Понятия работы в фоном режиме для WatchKit-приложения не существует. Однако, система умеет делать “скриншот” приложения. Если вы опустите руку или выйдете из приложения, а потом спустя небольшое время запустите его снова, то попадете на тот же экран, на котором и закончили. Вызовется только willActivate соответствующего контроллера.
Отличия от разработки основного iOS-приложения
Существенное отличие от разработки основного iOS-приложения — метод инициализации контроллеров init вызывается не разработчиком, а системой. Параметры и данные передаются от контроллера к контроллеру через контекст. Любой переход от экрана к экрану происходит либо автоматически по сигвею, либо из кода по идентификатору контроллера в сториборде. В обоих случаях WatchKit находит нужный экран в сториборде, после чего WatchKit Extension создает объект класса, указанного в сториборде у экрана с данным идентификатором (по данному сигвею), и вызывает у него метод init. Стэк контроллеров остается “под капотом” системы. Разработчик не видит его и работает с кодом контроллеров, как с абстрактными и изолированными сущностями.
Еще одно важное отличие — все элементы интерфейса являются прокси-объектами, доступными только на запись. Нельзя узнать у label, какой текст оно отображает, какой шрифт и цвет использует. Поэтому иногда приходится хранить состояние объектов в отдельных переменных. К тому же нельзя наследоваться от базового класса WKInterfaceObject, что усложняет проектирование приложения и делает невозможным создание кастомизированных объектов интерфейса.
Нет даже привычной иерархии View. Динамически нельзя создавать и добавлять объекты интерфейса. Весь интерфейс должен быть определен в сториборде, то есть на этапе проектирования приложения. Связывание происходит через IBOutlet. Ненужная часть интерфейса скрывается. Но надо стараться избегать ситуаций, когда на одном экране есть два полностью альтернативных интерфейса, один из которых скрыт в зависимости от контекста. Но в некоторых случаях, как например в Glance, это является единственным решением.
Метод didDeactivate вызывается системой, чтобы сообщить контроллеру, что он уже не на экране. При этом в теле этого метода и после его вызова бесполезно делать какие-либо изменения интерфейса — система их проигнорирует. Бывает очень неудобным, когда по наступлению некоторого события необходимо, например, изменить отображаемый текст на экране, который в данный момент не показывается. Приходится некоторым образом откладывать обработку события до вызова willActivate. Из-за этого willActivate может превратиться в череду проверок условий «а не надо ли нам заново переконфигурировать интерфейс».
Apple советует «ленивую» загрузку данных, где это уместно. В willActivate можно использовать dispatch_async и dispatch_after на главном потоке.
2. Взаимодействие с основным приложением на телефоне
Главная сложность заключается в том, что основное приложение на iPhone и WatchKit Extension — это два разных изолированных процесса со своей «песочницей». С другой стороны, логично предположить, что если приложение на часах является дополнением основного, то данные оно должно получать от своего старшего брата. И здесь Apple предлагает несколько способов:
1. Использование App Groups, которые позволяют иметь общие NSUserDefaults и сохранять файлы в разделяемом контейнере для группы приложений и их расширений.
Этот способ позволяет получить данные практически моментально. Основное приложение может записывать в группу, как в процессе своей работы, так и в режиме background fetch. Здесь есть некоторые ограничения: во-первых, основное приложение не может простым способом оповестить часы, что данные обновились. Простое KVO на общий NSNotificationCenter не работает. Решение: использовать совместно со вторым способом или организовать передачу данных через один известный pod, который архивирует данные в файлы и использует дарвиновский центр уведомлений; во-вторых, при записи файлов следует обратить внимание на это предостережение от Apple.
2. Взаимодействие с основным приложением на iPhone напрямую.
Класс WKInterfaceController имеет метод openParentApplication:reply:, при вызове которого запускается в background основное приложение на iPhone. У него вызывается метод делегата application:handleWatchKitExtensionRequest:reply:, который обрабатывает входящий запрос. Из WatchKitExtension обязательно передается блок завершения запроса, который принимает NSDictionary в качестве ответа основного приложения. Помимо блока завершения из WatchKit Extension можно передать словарь с любой информацией, чтобы основное приложение на iPhone могло обрабатывать разные запросы в зависимости от контекста.
Если основному приложению необходимо выполнить асинхронный запрос, например, запросить свежие данные с сервера, рекомендуется зарегистрировать background task, иначе iOS может завершить его, не дождавшись окончания выполнения. Главное ограничение данного способа: он занимает время. Блокировать основной поток, ожидая ответа, естественно, недопустимо, поэтому и возникает вопрос, как показывать старые данные, как показывать пользователю, что что-то происходит, как визуально обновлять данные, что делать, если вернется ошибка и т.д. Другое серьезное ограничение: не передаются сложные объекты, необходимо их сериализовать. При проектировании приложения очень важно помнить, что данные надо откуда-то получать. Создатели некоторых концептов WatchKit-приложений явно об этом не задумывались. Еще необходимо учитывать вопросы безопасности. Если отображаемые данные конфиденциальны, то просто так их хранить нельзя. В этом вопросе основному приложению и WatchKit-приложению лучше действовать одинаково.
3. Handoff как способ начать смотреть информацию на часах, а продолжить на телефоне.
Handoff реализуется очень просто. Названия типов NSUserActivity добавляются в *-Info.plist основного приложения. У объекта контроллера вызывается метод updateUserActivity:userInfo:webpageURL: с параметром — именем нужного типа NSUserActivity. Можно передать необходимую дополнительную информацию в userInfo. В это время на экране телефона появляется иконка вашего приложения в левом нижнем углу и если потянуть за нее наверх, запустится основное приложение. У делегата приложения вызовутся методы application:willContinueUserActivity и application:continueUserActivity:restorationHandler, где можно обработать userActivity и показать нужную информацию. При этом, если пользователь не будет доставать из кармана телефон и пытаться разблокировать его, система сама позаботится, чтобы через некоторое время инвалидировать активность.
Сами Apple Watch не распознают и не обрабатывают NSUserActivities, за исключением сгенерированных в Glance. Но об этом в следующем разделе.
В заключение параграфа приведем еще несколько советов от Apple:
- Оформляйте весь общий код во framework.
- Трафик между iPhone и Apple Watch необходимо минимизировать.
- «Тяжелую» работу должно выполнять основное приложение на iPhone.
3. Glances
Glances — приложение, предназначенное для быстрого показа важной информации, которое вызывается прямо с экрана часов свайпом снизу вверх. По сути это перелистывающиеся виджеты приложений, показывающие самую актуальную информацию, например, погоду, биржевые индексы, информацию из календаря, пропущенные звонки, фитнес-цели и достижения. Порядок карточек приложений настраивается пользователем. К слову, приложение может не иметь отображения в Glance, если в этом нет необходимости
Особенности: дизайн
- Не имеет вертикальной прокрутки.
- Не поддерживает интерактивные элементы: кнопки, свичи, слайдеры и меню.
- Позволяет работать только с системным шрифтом San Francisco, но есть разные начертания: regular, semibold, medium, light и другие.
- Строится по специальному шаблону состоящему их двух частей.
- Фон Glance — размытые часы.
- Apple не рекомендует использовать карты и таблицы, но они не запрещены.
- Гланс не всегда обновляется перед показом, иногда система отображает скриншот и надпись «Last updated on ***»
Особенности: разработка
- По тапу на гланс открывается соответствующее приложение на часах и грузится начальный контроллер. Через user activity можно обработать переход из гланс и с начального контроллера показать нужный интерфейс
- Базовый класс контроллера экрана гланс — стандартный WKInterfaceController. У гланс абсолютно идентичный жизненный цикл за исключением того, что между вызовом init и willActivate может пройти нетривиальное количество времени. Следовательно, в willActivate следует проверять актуальность данных
Конфигурация гланса — две части, верхняя смещена относительно центра:
4. Уведомления
Система предоставит универсальный интерфейс для ваших уведомлений, даже если вы не реализуете никакой контроллер интерфейса для них в сториборде. Но, конечно, хочется сделать их красивыми и удобными. Тут необходимо найти правильный баланс, чтобы уведомления не беспокоили пользователя слишком часто, но вместе с тем обеспечивали его актуальной для текущего контекста информацией. Формулировка уведомлений должна быть максимально четкой и короткой, ведь экран часов совсем крохотный. Это особенно актуально для кириллицы. Русские слова помещаются на экране с большим трудом.
Уведомления показываются в два этапа: Short Look и Long Look. При получении уведомления часы нежно вибрируют. Поднимая руку, пользователь видит «короткий вид» уведомления – ShortLook, который сразу же анимируется в LongLook, если пользователь задержал на нем взгляд:
Long Look содержит полный текст уведомления, иконку и название приложения, а также кнопку «Пропустить» уведомление. Прямо сюда можно запихнуть до четырех контекстных действий — в случае с нашим приложением, например, «продлить скорость». Кнопка «Dismiss» предоставляется системой всегда. Другие возможные кнопки и соответствующие им действия необходимо регистрировать в коде основного приложения на iPhone через UIUserNotificationSettings для определенных категорий уведомлений. То есть они определяются на этапе проектирования приложения, а не приходят вместе с push-ом. Поэтому иногда полезно завести универсальную категорию для уведомлений, если мы хотим всегда показывать кастомный интерфейс.
У действия кнопок может быть два типа режима активации: background и foreground. По нажатию на кнопку с foreground действием открывается WatchKit приложение и вызывается один из методов handleActionWithIdentifier:forLocalNotification или handleActionWithIdentifier:forRemoteNotification, которому передается идентификатор выбранной кнопки. По нажатию на кнопку с background действием запускается в background основное приложение на iPhone, и вызывается один из соответствующих методов делегата приложения.
Особенности Layout-уведомлений: дизайн
- Использовать разные начертания системного шрифта в LongLook.
- Поменять цвет плашки с названием приложения в LongLook.
- Задать цвет названия приложения через GlobalTintColor в ShortLook.
А вот использовать интерактивные элементы — кнопки, слайдеры и switches — в уведомлениях нельзя.
Есть два типа интерфейса уведомлений: статический и динамический. Если вы реализуете кастомный интерфейс, то надо обязательно создать контроллер для статического типа. Статический тип интерфейса — это некоторый упрощенный, обобщенный вид уведомления по сравнению с динамическим. Система сама определит, какой интерфейс ей выбрать, в зависимости от заряда батареи и настроек пользователя. Динамический тип можно не реализовывать.
Особенности статического интерфейса
- Все картинки должны содержаться в WatchKit App.
- Интерфейс не содержит таблиц и карт.
- Весь интерфейс статичен, кроме одной label, которая будет отображать сообщение уведомления.
Особенности динамического интерфейса
- Можно использовать и менять label, картинки, группы и сепараторы в зависимости от содержания уведомления.
- Можно при необходимости добавлять таблицы и карты.
5. Айдентика приложения: шрифты, иконки, цвета
Внутри WatchKit-приложения на часах возможно изменить любой шрифт кроме заголовка и времени, а также контекстного меню, вызываемого через ForceTouch. Несмотря на то, что в пакете системного шрифта San Francisco нет кириллического начертания, на самих часах и в Xcode все в порядке. В Glance и Уведомлениях же использовать кастомные шрифты нельзя.
Внутри основного приложения для всех заголовков задается Global tint colour. Его нельзя менять в процессе выполнения в зависимости от контекста или данных, он задается на этапе проектирования приложения один раз и выполняет функцию цвета заголовков в приложении и названия приложения в уведомлениях «короткого вида». Цвет PageControl, к сожалению, поменять тоже нельзя никак, не верьте концептам. Не заставляйте пользователей вашего приложения чувствовать себя так, будто они смотрят рекламу. Для брендирования лучше использовать ненавязчивые средства: цвет, шрифты, образы.
Советы: дизайн
- Не вставляйте всюду логотип, он съедает полезное пространство экрана, при этом не неся никакой функциональности.
- Цвета должны быть яркими и контрастными для легкого считывания в экстремальных условиях вроде яркого солнца.
- Не ограничивайтесь цветом для показа интерактивности элементов управления — используйте стандартные кнопки или анимацию.
- Текстам надо уделять особо пристальное внимание. Они должны хорошо читаться в любых ситуациях: на ходу, на бегу, как угодно. Не делайте текст слишком мелким или бледным.
- На часах рекомендуется использовать черный фон — не картинки и не яркие цвета. Картинка на экране не имеет отступов, тем самым продолжая приложение уже в физическом продукте — в часах. За счет того, что вокруг дисплея большая черная рамка, кажется, что и приложение, и сами физические часы представляют собой единое целое.
6. Навигация
Приложения поддерживают два вида навигации, которые, к сожалению, не могут быть совмещены друг с другом.
Иерархическая навигация — классический метод управления приложением, аналогичный навигации в приложениях iPhone c использованием UINavigationController, где пользователь «углубляется» в приложение. Такой тип навигации наиболее удобен и гибок в техническом плане, поскольку позволяет передавать информацию пользователю порционно и иметь неограниченное количество уровней вложенности.
Страничная навигация (PageControl) позволяет пользователю перемещаться между экранами «свайпом». Такая модель навигации подходит для небольших приложений, с простой моделью данных. При использовании постраничной навигации контент всех страниц загружается единовременно, а динамическое увеличение количества страниц не реализуется без ряда ухищрений.
Советы: разработка
- В страничной навигации лучше конфигурировать интерфейс в willActivate, а не в init или awakeWithContext. При загрузке нескольких экранов с PageControl все они создаются прежде, чем первый из них будет показан. Это означает, что у всех контроллеров вызовется init, awakeWithContext:, а потом только у первого контроллера — willActivate. И если поместить много действий в инициализацию, то пользователь увидит долгий индикатор активности прежде, чем покажется первый экран.
- Если начальный контроллер сториборда связан страничной навигацией, то нельзя передать контекст между экранами, что заставляет изобретать свой способ разделения данных.
- Нельзя динамически изменять количество экранов, которые связаны между собой через Page Control. Для этого надо “перезапустить” приложение полностью (метод reloadRootControllersWithNames:contexts: класса WKInterfaceController), что в глазах пользователя выглядит так, будто бы произошла какая-то ошибка.
Также в любом типе навигации возможно модальное отображение контента для привлечения внимания пользователя или для решения вопросов, требующих от пользователя однозначного принятия решения, без взаимодействия с основной частью приложения. При этом показать можно как одно окно, так и несколько окон, связанных через Page Control. В левом углу модального окна по умолчанию находится заголовок. Злоупотреблять модальным режимом крайне не рекомендуется.
Переход между экранами целиком обрабатывается системой, и его никак нельзя кастомизировать или дополнительно анимировать. В страничной навигации экраны появляются справа и слева, в иерархической — следующий экран наплывает с правого края экрана, как в iPhone или iPad, а модальный экран выплывает снизу.
7. Взаимодействие с пользователем через интерфейсы
Жесты
Экран часов слишком мал для полного списка жестов, используемых в iOS. Вот что доступно пользователю:
- Одиночные тапы.
- Вертикальные прокрутки для длинных экранов.
- Свайпы влево и вправо в страничной навигации.
- Force Touch для вызова контекстного меню.
- Колесико Digital Crown. В приложениях Apple от Apple с его помощью можно, например, зумить. Но для разработчиков доступна только функция скролла: чтобы не загораживать экран пальцем, можно просто крутить колесико.
- Жест с левого края, который возвращает на предыдущий экран, в иерархической навигации.
Кастомизировать жесты нельзя.
Контекстное меню
Контекстное меню вызывается по жесту Force Touch. В него можно спрятать от одного до четырех второстепенных действий. Экран будто бы по-настоящему вдавливается, а сверху наплывает контекстное меню. У него полупрозрачный фон и от одной до четырех кнопок системного вида.
Особенности: дизайн
- Можно кастомизировать контекстное меню только иконкой, при этом невозможно поменять ни цвет иконки, ни цвет круга.
- Шрифт также не кастомизируется, длина надписи ограничивается двумя строками.
- Пользователь может взаимодействовать со следующими объектами: кнопка, switch, слайдер, таблица (выбор строки), контекстное меню.
- Тап по карте открывает приложение карты на часах.
- Во время выполнения приложения у объектов можно менять конфигурацию (например, текст у label), можно менять ширину и высоту, а также свойства hidden и alpha.
- Двигать объекты (менять origin) затруднительно и лучше этого не делать.
8. Изображения и анимации
Существует заблуждение, что в Apple Watch будет множество красивых анимаций. На самом деле нет, по крайней мере, в приложения сторонних разработчиков точно нет. Если возникает потребность в анимации, забудьте про программные средства (или почти забудьте). Анимировать можно только изображения. Покадрово. То есть приготовьтесь нарезать все кадры анимации по отдельности, прямо как для старых мультфильмов. Двигать объекты нельзя. Анимировать переходы между состояниями интерфейса, эффект параллакса, переходы между экранами — нельзя. Только менять кадр изображения. Все.
Задать изображение можно у background контроллера WKInterfaceController, кнопки WKInterfaceButton, группы WKInterfaceGroup. И есть специальный объект для отображения картинок WKinterfaceImage.
При указании имени изображения в сториборде и в параметрах методов, оканчивающихся на imageNamed, система ищет картинку в WatchKit App, то есть среди тех, которые хранятся на часах. Методы, оканчивающиеся на image и imageData, подразумевают, что изображение хранится в WatchKit Extension, то есть физически на телефоне. Поэтому когда вы их используете, картинка передается с iPhone на часы, что будет вызывать некоторую задержку. Кадры анимации должны быть проименованы одним именем плюс номер кадра: например, «image0@2x.png», «image1@2x.png», …, «image256@2x.png». При этом именем картинки, которое вы указываете в сториборде или передаете в параметре методов старта анимации, будет считаться «image».
Программно можно запускать и останавливать анимацию WKInterfaceImage и бэкграунд группы WKInterfaceGroup. Лучшее место для этого — в willActivate. При этом если хотите, чтобы анимация началась уже после того, как пользователь увидит экран, то вызов старта можно обернуть в dispatch_async или dispatch_after. Если хотите, чтобы анимация запускалась периодически, то для это можно использовать NSTimer.
В параметрах старта анимации можно указать:
- Начальный кадр анимации и количество кадров, то есть, например указать «прокрутить 10 кадров, начиная с 23»
- Время, за которое должна пройти анимация. Причем если указать отрицательную величину, то анимация запустится в обратную сторону (с 32 кадра по 23 для предыдущего примера)
- Количество повторений, где ноль означает «продолжать пока не остановят»
Особенности: разработка
- Ввиду задержек при передаче с телефона на часы изображений во время работы приложения сейчас наилучшим сценарием выглядит создание анимации на все случаи жизни на этапе проектирования и хранение ее в ресурсах на часах.
- Уже существуют проекты на github, которые позволяют создавать средствами iOS анимацию, преобразовывать ее в серию картинок и передавать в режиме реального времени на часы. Но пока это не выглядит оптимальным сценарием работы.
- У каждого приложения есть кэш, объем которого составляет 5MB. Поэтому если есть изображение, которое мы получили в реальном времени и которое надо анимировать на Apple Watch не один раз, можно закэшировать его на часах с помощью класса WKInterfaceDevice. После этого им можно пользоваться, как изображением, хранящимся на часах.
- При необходимости графику нужно делать двух размеров под каждый тип часов. В ассете отмечаем в Devices, что картинки — для Apple Watch, и тогда при загрузке в часы iOS автоматически загрузит ресурсы только для нужного размера.
Несмотря на ограниченные возможности и сложности анимация — это эффективный способ контакта с пользователем. Она не только делает приложение привлекательным и добавляет индивидуальность, но и позволяет делать давать подсказки, отображать состояние, мотивировать к действиям. И это особенно актуально для Apple Watch, так как помогает экономить пространство на маленьком дисплее.
9. Верстка/Layout
Верстка приложений на часах немного напоминает табличную верстку html, сковывающую дизайнера и разработчика. В смартфоне есть слои, а в часах их нет. В часах вместо слоев группы. Группа — контейнер для других объектов интерфейса. Как говорилось выше, бэкграунд группы можно анимировать.
Соответственно, контейнеры могут находиться рядом друг с другом, либо друг в друге. Внутренняя группа не может выходить за рамки внешней. Существует два типа групп: объекты в группе располагаются друг за другом по вертикали, и объекты в группе располагаются друг за другом по горизонтали. Группы могут содержать в себе другие группы, причем как другого типа так и того же. Элементу интерфейса нельзя задать origin, вместо этого задается выравнивание по вертикали и по горизонтали. В соответствии с этим выравниванием элемент занимает первое свободное место в своей группе, следующий объект располагается рядом и так далее. Любые элементы интерфейса расставляются по этим законам. Это накладывает большие ограничения на возможности.
Во время исполнения программы нельзя динамически добавлять новые объекты интерфейса. То есть все должно быть предусмотрено в storyboard. Соответственно, в Glance для нескольких состояний по сути приходится одновременно иметь три интерфейса — только два из них все время скрыты. При запуске код в зависимости от данных выбирает нужный тип интерфейса, а два скрывает. Но они там есть — они создаются и вычисляются.
Советы: дизайн
- Apple Watch выпускаются в двух размерах, поменьше — 38mm, и побольше — 42mm. В приложениях лучше поддерживать один и тот же контент для обеих версий.
- По возможности пакет графики следует делать единым для обоих размеров.
- Рекомендуется выравнивать контент по левому краю — это улучшит вид приложения при увеличении экрана.
- Делайте кнопки на всю ширину экрана, чтобы текст кнопки всегда был виден целиком, и ни в коем случае не ставьте больше трех кнопок в одну строку.
Заключение
Рамки, в которые корпорация поставила разработчиков, при первом подходе вызывают раздражение. При более глубоком погружении становится понятно, что ограничения не столько лишают выразительных средств, сколько диктуют правила хорошего тона при работе с микроскопическими экранами. Ведь проектирование взаимодействия, а уж тем более разработка — это работа с данными и задачами, а не игра в пиксели и раскраску.
Конечно, хотелось бы использовать побольше привычных и изученных на iOS элементов, но для первой попытки предоставленных возможностей вполне достаточно. Очевидно, что через пару месяцев на ежегодной WWDC мы увидим новые фичи и новые инструменты, а пока нужно хорошенько прочувствовать то, что является одним из первых этапов на пути к получению информации в контексте. Быстро, незаметно и на бегу. А ведь такой информации не должно быть много: ни визуально, ни содержательно.
В следующем материале мы расскажем о том, как разрабатывали приложение для Apple Watch — "Мой Билайн".
Читайте также:
Material Design: на Луну и обратно
Стилизация iOS-приложений: как мы натягиваем шрифты, цвета и изображения
Редизайн приложения РЖД: концепт
Комментарии (6)
PeterOdUa
25.04.2015 18:12+1На часах рекомендуется использовать черный фон — не картинки и не яркие цвета. Картинка на экране не имеет отступов, тем самым продолжая приложение уже в физическом продукте — в часах. За счет того, что вокруг дисплея большая черная рамка, кажется, что и приложение, и сами физические часы представляют собой единое целое.
на самом деле ещё и в том, что там OLED дисплей. А значит черные пиксели не потребляют энергию. И чем больше черного на экране, тем дольше протянет батарейка.
avdept
Почему так урезаны возможности анимации, неужели только ради уменьшения потребления батарейки?
mc_murphy
Код исполняется на телефоне, а значит, никакого расчета анимаций на самих часах сделать нельзя. Так как рендеры анимаций большие, Apple устроили нам велосипед с их загрузкой в часы в момент установки приложения.
В результате все так, как вы предположили — выбранная архитектура увеличивает жизнь батареи, но лишает возможности визуализировать что-то на часах за пределами заранее определенного поведения ячеек и пр.
rule
Спрингборд на телефоне отлично ползуется OpenGL анимаацией. И многие системные штуки анимированы тоже очень хорошо.
Так что расчет анимации на часах вполне себе можно делать — там же для этого есть специальный чип.
Скорее всего просто нет нормального удобного фреймворка, чтоб отдать его разработчикам.
avdept
Как бы 1 версия часов. Даже сравнить первую ось айфона и текущую, разница огромная. Думаю через пару лет и часы тоже допилят до того что батарейку нужно будет заряжать не каждый день а хотя бы раз в 3-4 дня
egormerkushev
А я думаю, просто жадничают, не хотят скармливать батарейку сторонним приложениям.