Разработчик ПО
На этом занятии мы подробно рассмотрим технические аспекты перехода от полноэкранных карточек к динамическим виджетам Wear OS частичной высоты.
Мы рассмотрим технические преимущества унифицированного Jetpack Glance API и нового движка Remote Compose, а также подробно расскажем, как они сочетаются с Modern Android Development.
В конце мы поделимся последними рекомендациями по UX и рассмотрим практические стратегии перехода, которые помогут вам создать интерфейс следующего поколения.
Расшифровка
Всем привет!
Меня зовут Фрэнк, и я руковожу разработкой виджетов для Wear OS.
Часы – это незаменимый спутник пользователей в течение всего дня. Сегодня мы расскажем, как использовать новые виджеты Wear OS.
Мы рассмотрим два способа доставки наиболее важных функций прямо на запястье ваших пользователей, и мы сделаем это с помощью новейших API, API, которые разработаны для того, чтобы сделать создание для Wear OS знакомым и интуитивно понятным для разработчиков Android, таких как вы.
Сегодня на сцене ко мне присоединится мой замечательный коллега и сосед по рабочему столу Юрий. Он расскажет, как именно мы это делаем.
Здравствуйте! Меня зовут Юрий Шимке.
Я инженер в команде Wear OS и в основном работаю с Remote Compose API.
Сегодня я кратко расскажу о Remote Compose, а также о процессе перехода от карточек к виджетам Wear.
А теперь я передаю слово Фрэнку.
Отлично!
Спасибо, Юрий.
Мы официально добавляем наручные устройства в единую экосистему виджетов Android, превращая полноэкранные карточки в виджеты Wear OS.
А поскольку эти виджеты теперь создаются с помощью Jetpack Glance, вы можете видеть, что используется та же базовая инфраструктура, что и для мобильных виджетов.
В будущем вы увидите, что разработка для Wear OS станет для вас ещё более привычной.
Чтобы обеспечить работу этих функций, мы развиваем стек пользовательского интерфейса – базовый стек пользовательского интерфейса.
Виджеты Wear OS работают на базе Remote Compose – нового фреймворка Android для удаленного интерфейса.
Это означает, что вы наконец-то можете использовать декларативный API, тесно связанный с Jetpack Compose, для создания элементов за пределами приложения, например виджетов.
Remote Compose позволяет использовать в виджетах современную графику и адаптивные макеты, обеспечивая при этом высокую производительность и эффективное энергопотребление.
А благодаря тому, что интерфейс отделен от процесса приложения, виджеты безопасно сериализуются и легко отрисовываются на самых разных устройствах Android.
Это означает, что вы можете с минимальными усилиями перенести этот богатый опыт практически на все поддерживаемые удаленные поверхности.
Чтобы переход от карточек к виджетам был максимально плавным, мы вводим два стандартных размера контейнеров: маленький и большой.
Они похожи на сетки 2 x 1 и 2 x 2, которые вы уже используете для мобильных виджетов.
Начиная с Wear OS 7 на устройствах некоторых производителей виджеты Wear OS будут находиться в вертикально прокручиваемой панели вместе с виджетами других приложений.
Вот как виджеты Wear OS выглядят на Samsung Galaxy Watch.
Архитектура платформы поддерживает вертикальную прокрутку, поскольку производители устройств могут начать использовать ее в будущем.
И вам не нужно беспокоиться о том, что вы оставите каких-либо пользователей или существующих пользователей позади.
API Jetpack Glance Wear поддерживают обратную совместимость вплоть до Wear 4.
На более старых устройствах, которые поддерживают горизонтальную панель виджетов или карточек, система будет обрабатывать это за вас.
Вам нужно лишь указать в коде, что вы хотите поддерживать полноэкранный режим, и система будет показывать ваш большой виджет как полноэкранную карточку на таких устройствах.
Теперь Юрий покажет нам код и расскажет, как перенести существующие карточки в виджеты Wear.
Спасибо, Франк.
Если вы создаете виджет для Wear OS с нуля, это просто.
Вы просто определяете GlanceWearWidgetService и создаете пользовательский интерфейс с помощью Remote Compose.
Если же в вашем приложении уже есть карточка, вам нужно будет перенести сервисы, интерфейс и данные.
Чтобы переход был максимально плавным, мы предусмотрели несколько вариантов для существующих пользователей.
Вы можете выбрать одну из двух стратегий: двойное или одиночное обслуживание.
Мы рекомендуем использовать двойной сервис: оставить TileService для старых устройств Wear OS и добавить GlanceWearWidgetService для Wear OS 7 и более поздних версий.
В отличие от этого, при использовании одного сервиса вы создаете новый, единый GlanceWearWidgetService, который обрабатывает оба протокола, работая в режиме совместимости для преобразования вашего виджета в плитку на старых устройствах.
В любом случае вы сможете обращаться к пользователям.
Это влияет только на то, какой код вы будете поддерживать в дальнейшем.
На сайте для разработчиков Android мы опубликовали подробную документацию о том, как и когда использовать эти шаблоны.
Ознакомьтесь с ним, чтобы узнать, какая стратегия лучше всего подходит для вашего приложения.
Теперь поговорим о слое пользовательского интерфейса.
При миграции ваша ментальная модель меняется.
Раньше для карточек использовалась библиотека ProtoLayout, созданная специально для карточек Wear OS.
Виджеты Wear OS, напротив, создаются на основе Remote Compose.
Remote Compose использует ту же основу, что и Jetpack Compose UI, включая компилятор и среду выполнения.
Он разработан так, чтобы быть похожим на библиотеки Compose UI, такие как foundation и Material 3.
Но вместо поля, столбца или текста вы просто заменяете их на RemoteBox, RemoteColumn или RemoteText.
В этом случае вы часто будете писать слово "remote".
Чтобы ускорить рабочий процесс, мы включили полный набор готовых к использованию компонентов Remote Compose, разработанных специально для виджетов.
Это значит, что существующие дизайны Wear Material 3, в том числе созданные в Figma, можно легко адаптировать для виджетов. Это удобно и для инженеров, и для дизайнеров.
Чтобы увидеть, насколько согласованы эти фреймворки, давайте рассмотрим конкретный пример.
Мы создадим собственный компонент приложения на основе кнопки-переключателя Material 3.
Слева показан стандартный компонент Wear Compose, который вы можете написать в своем приложении, а справа – версия Remote Compose.
// Wear Compose
@Composable
fun HistoryEraserButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
onCheckedChange: (Boolean) -> Unit = {},
)// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
onClick: Action,
modifier: RemoteModifier = RemoteModifier,
checked: RemoteBoolean = true.rb,
onCheckedChange: Action = Action.Empty,
)Обратите внимание, насколько похожи эти паттерны.
Однако при написании кода Remote Compose вы будете использовать аннотацию RemoteComposable.
А там, где вы используете знакомые параметры, такие как модификатор и логическое значение, у них есть эквивалентные типы Remote Compose, такие как RemoteModifier и RemoteBoolean.
И вы используете действия вместо лямбд.
Вместо того чтобы определять код, который будет выполняться внутри лямбда-выражения, вам нужно будет объявить действие, например запуск отложенного интента, вызов сервиса или обновление значения.
Перейдем к телу компонента.
Вы заметите, что даже тема выровнена.
Вы можете применить цветовую схему Material 3 к компоненту Remote Compose точно так же, как и в стандартном Compose, что позволяет вашему виджету точно соответствовать брендингу вашего приложения.
// Wear Compose
val colors = MaterialTheme.colorScheme
SplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser",
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
SwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { Text("History Eraser") },
secondaryLabel = { Text("Don't touch it!") },
)// Wear RemoteCompose
val colors = RemoteMaterialTheme.colorScheme
RemoteSplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser".rs,
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { RemoteText("History Eraser".rs) },
secondaryLabel = { RemoteText("Don't touch it!".rs) },
)И наконец, давайте посмотрим на результат. В результате получается именно то, что вы ожидаете: чистая, отзывчивая, анимированная кнопка-переключатель.
Разницу сложно заметить.
Чтобы вы могли проектировать, дорабатывать и проверять макеты виджетов, не запуская их на устройстве или в эмуляторе, мы добавили поддержку предварительного просмотра Compose для виджетов Wear.
Поскольку виджеты зависят от ограничений контейнера, специфичных для OEM, таких как размер, форма, отступы, радиус угла, мы строим на основе стандартной аннотации предварительного просмотра, но с дополнительным поставщиком параметров для внедрения этих конфигураций.
@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
@PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
@PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)Библиотека содержит предварительно настроенные реализации поставщика PreviewParameter, которые соответствуют реальным устройствам Wear OS.
Эти аннотации предварительного просмотра позволяют легко проверить макет на различных аппаратных формах.
Помимо тестирования макетов, вы можете использовать эти предварительные просмотры для создания статических изображений, необходимых для выбора виджетов на устройстве.
@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
@PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)В библиотеке есть параметр для прямоугольной формы предварительного просмотра, который имитирует полные необрезанные прямоугольные контейнеры.
Чтобы посмотреть, как это работает на практике, мы обновили пример приложения Horologist, добавив в него новый виджет, демонстрирующий возможности этого API.
Мы покажем, как добавить маленький и большой виджеты.
На GitHub вы можете сравнить устаревший код ProtoLayout и новую реализацию Remote Compose.
Уверены, вам понравится.
И наконец, в наше время ни один разговор не обходится без упоминания ИИ.
Чтобы ускорить переход, мы опубликовали на GitHub новый навык переноса карточек в виджеты.
Вы можете использовать его с выбранным агентом или добавить непосредственно в Android Studio с помощью Android CLI.
android skills add wear-widgets
android skills add --allА теперь я передаю слово Франсуа, который подведет итоги.
Спасибо!
Спасибо, Юрий.
Как видите, превратить карточки в виджеты Wear OS очень просто.
Подведем итоги. Переходя на Jetpack Glance Wear и Remote Compose, вы не просто обновляете интерфейс, а присоединяетесь к более унифицированной экосистеме виджетов Android.
Теперь вы можете создавать красивые виджеты с обратной совместимостью, используя современный декларативный фреймворк, полностью совместимый с Jetpack Compose.
Вы можете начать перенос карточек уже сегодня. Для этого ознакомьтесь с руководством по началу работы на сайте Android для разработчиков.
Мы с нетерпением ждем ваших новых выразительных и удобных приложений для носимых устройств.
Большое спасибо, что присоединились к нам сегодня утром. Надеемся, что вам понравится остальная часть конференции.
Спасибо!
// Wear Compose
@Composable
fun HistoryEraserButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
onCheckedChange: (Boolean) -> Unit = {},
)// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
onClick: Action,
modifier: RemoteModifier = RemoteModifier,
checked: RemoteBoolean = true.rb,
onCheckedChange: Action = Action.Empty,
)// Wear Compose
val colors = MaterialTheme.colorScheme
SplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser",
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
SwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { Text("History Eraser") },
secondaryLabel = { Text("Don't touch it!") },
)// Wear RemoteCompose
val colors = RemoteMaterialTheme.colorScheme
RemoteSplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser".rs,
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { RemoteText("History Eraser".rs) },
secondaryLabel = { RemoteText("Don't touch it!".rs) },
)@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
@PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
@PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
@PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)android skills add wear-widgets
android skills add --all