Запилил за вечер приложение на часы. Что я могу сказать про это? Функциональность самих API, которые предоставляются Google, очень плохая.
Гайд: Как разрабатывать приложение на часы под Android в Wear OS
Шаг 1: Создание проекта
С чего вам нужно начать: используйте шаблон, создайте по официальной документации приложение под Android. У вас будет одно приложение, которое вы запускаете. Вы делаете второе так же, только будет другой SDK target и парочка других твиков.
⚠️ Критически важно: Package ID
Важный, суперважный момент: у вашего приложения package ID (не тот что джавовый, а который Android-овский) должен быть точно такой же, как у вашего основного приложения, иначе они друг друга не узнают и не подконнектятся.
Особенно внимательно смотрите, если у вас у дебага и релиза приложения разные package ID. Например, вы используете package ID суффикс какой-нибудь. У меня была такая проблема, что они друг друга не узнавали. У вас не будет никаких ошибок, просто отличаются package ID.
Я надеялся свой неудачный package ID поменять на красивый, который я уже давно поменял везде, кроме package ID в Android, ибо его нельзя менять. Придется использовать старый.
Шаг 2: Выбор библиотек
Создаете этот проект, можно использовать Compose, добавляете все зависимости нужные.
Я рекомендую Horologist использовать для Wear OS приложения, а для телефона нет, если у вас оно супер простое. Если вы просто отправляете на Wear OS данные, можно обойтись через эти слушатели, написать враперы, использовать Kotlin сериализацию, и в принципе пойдет. Я пока так решил, потому что там баги в Horologist, но возможно вы захотите Horologist и на телефон затащить, потому что там по сути тоже такие же плюшки с корутинами, все эти обертки и листнеры в корутины завернуты.
Шаг 3: Настройка wear.xml и capabilities
Там есть специальный wear.xml файл, в котором вам нужно прописать ключ, называется capability.
Для Horologist используйте те, которые они вам скажут, потому что они используют в исходниках захардкоженные строки, которые вы должны добавить в этот XML файл, иначе ничего не запустится. Если не используете Horologist, можете любую фигню написать в этом XML для capability.
Главное, чтобы у вас было их два: один для телефона, другой для watch. На watch вы чекаете, есть ли capability телефона, а на телефоне чекаете, есть ли capability watch. Вы проверяете, поддерживает ли девайс этот capability - возможность связи с вашим приложением.
Это даст возможность понять, установлено ли приложение на часах и установлено ли оно на телефоне. Чтобы человеку показать: “Хей, слушай, у тебя не установлено приложение на телефоне, давай тебя в Google Play направлю.” И наоборот, конечно же.
Это всегда нужно продумать, потому что человек может установить приложение на часы, но не установить на телефон, или наоборот. Как он узнает, что у вас есть приложение на часы? Это нигде не показывается. Вам нужно самим сделать flow: “Йоу, здорово, а у нас есть приложение на часы, хочешь установить?” Вам нужно будет правильно распознать, когда это сделано или не сделано.
Шаг 4: UI и Material Components
Добавляете Compose Material 3, нужно использовать все собственные компоненты с нуля. Делаете как в Horologist, я рекомендую стырить их исходники, копировать себе, потому что там немножко неправильно сделали с ограничениями по размеру.
Нужно проверять, есть ли круглый экран у часов или квадратный, и вы делаете разную верстку в зависимости от этого. Не рекомендую делать только одну, потому что будет смотреться как кусок кала.
Шаг 5: Data Layer API для синхронизации состояния
Подключаете Wear OS Play SDK, и через него у вас там будет Data Manager, Data Layer. Он нужен как глобальный broadcast на все устройства - какие данные там сейчас находятся. Считайте, что это какой-то стейт, который шарится между вашим приложением и всеми приложениями на часах, и наоборот.
Часы могут отправлять данные, и телефон может отправлять данные. У меня телефон отправляет все данные, часы только их отображают. Для простоты сделано.
Используйте эту API для штук типа стейта, которые должны синхронизироваться между всеми часами. Часов даже может быть несколько, и телефонов может быть несколько. Это тоже проблема, нужно это как-то обрабатывать. Я решил, что я просто беру самый первый - первый телефон будет главным, остальные все будут просто игнорировать часы. Чисто для простоты. Мало у кого будет несколько телефонов с одними часами, это бред.
Шаг 6: Messages API для RPC
Если вам нужно отправить сообщение, вы используете Messages API. Тоже есть отдельная штука на колбеках. Это по сути просто RPC - вы можете вызывать функции.
Протобаф можно добавить и все это прописать, но я не хочу добавлять протобаф, меня он бесит, он очень тяжелый. Поэтому я все запилил через Kotlin сериализацию и события как на вебсокетах. Там просто отправляются байты, которые парсятся на телефоне.
На телефоне практически тот же самый код, очень похоже. Делаете singleton с вашим репозиторием, который будет наблюдать за часами в нужное flow. Например, у меня ритуал стартует, и вы начинаете отправлять данные через Data Layer API. А часы будут через Messages API вам посылать события, которые вы должны использовать. Таким образом и строите взаимодействие. В принципе, ничего сложного.
Чеклист: Что обязательно нужно проверить
Только не забудьте проверить:
- Первое: наличие Google Play Services, иначе все крашится
- Второе: установлено ли приложение на обоих устройствах
- Третье: запущено ли приложение на обоих устройствах
- Четвертое: находится ли девайс вблизи, есть ли между ними связь, потому что может быть, что часы ушли слишком далеко и все похерилось. Для этого нужно UI показать отдельно, что мы потеряли связь
- Пятое: правильно сериализовать и передавать все эти данные между устройствами
- Шестое: ваши package ID и capabilities
Это основное. А дальше просто используйте все, что вы уже сделали, вот эту инфраструктуру, строите и делайте абсолютно все, что хотите.
Про токены и авторизацию
Если вам нужно с часов выходить в интернет или использовать токены авторизации, для этого есть специальные API - бандл токена идентификации. Вы можете пошарить токены между устройствами благодаря этому. Это единственный способ безопасно это сделать. Там начинается отдельная долбежка.
Поэтому я рекомендую все-таки делать приложение на часы обычным slave-приложением, а приложение на телефон источником данных. То есть оно просто будет неким куском UI, который будет работать на часах.
Мой опыт в 2024:
Проблема №1: Зависимость от Google Play Services
Все работает только через Google Play Services. Если на девайсе нет Google Play Services, или что-то с ним не так, или старая версия Android, то все пойдет наперекосяк. Это надо обрабатывать конкретно и пытаться помочь человеку решить этот вопрос или скрывать от него эту функциональность, чтобы он не оставил ревью на одну звезду.
Проблема №2: Древние API и нулевая документация
Там все написано на Java, древнеегипетские API через колбеки и слушатели. Документация вообще 0, просто API surface, ничего не объясняется, все обфусцировано в коде. В code labs ничего непонятно, специфичных use cases нет. Там только описана зачем-то авторизация, и как это все связать друг с другом тоже непонятно.
Там только отдельные куски: вот тебе функция, вызови ее. Где ее вызывать, когда вызывать, как вызывать, как получить результат, как создать нужные для нее объекты? Там какие-то билдеры все время, куча непонятных вещей, которые вообще никак не задокументированы.
Альтернатива: Horologist (но и тут не без проблем)
Если хочется чего-то на Kotlin получше, то есть только одна альтернатива - библиотека Horologist от самих Google на GitHub. Как Accompanist в свое время был игровой площадкой для команды Google, где они могли пушить в master что хотят и смотреть, что останется висеть на стене, так и здесь то же самое, только для часов.
Они сделали какую-то библиотеку, больше похожую на проект, где свой кусок своей кодовой базы выкинули в open source. Мол, нам это нужно было, мы это добавили. Например, сделали Kotlin функцию, чтобы как с Flow смотреть за результатами, но у этого 0 кастомизации.
Все заложено на их технический стек: Firebase, DataStore, ProtoBuf, Preferences и ProtoLite, который крашится. Сейчас там баг есть на GitHub, из-за него пользоваться этим тоже очень сложно, практически невозможно. Опять же, ничего не задокументировано, многие use cases не покрыты. Покрыто только то, что Google нужно было теоретически, и из-за того, что есть свой технический стек, который нужно как-то связать со стеком Respawn. У нас тоже много чего написано своего.
Так что это была просто эпопея. Самое сложное в разработке приложения на часы было в этом.
Плюсы Wear OS разработки
Это по сути приложение на Android. Можно все переиспользовать практически: подключить свои модули, подключить всю бизнес-логику и доменные модели, и писать UI на обычном Compose. Только там нет Material 3, только Material 2. Нужны отдельные компоненты. Обычные, конечно же, не получится использовать, потому что там очень ограниченный форм-фактор девайса.
Но все равно, за вечер, с божьей помощью, исходниками Horologist и собственного опыта, я смог создать приложение, которое показывает статус текущего ритуала, как медиаплеер, как Spotify на часах. Такой очень простой MVP-приложение-компаньон.