Найти в Дзене
Кодовые решения

Разработка виджета для Android с нуля: Kotlin, Jetpack Compose и Glance 🚀

Привет, друзья! 👋 Если вы, как и я, фанат Android-разработки, то наверняка знаете, насколько круто иметь на домашнем экране смартфона персонализированные виджеты. Они не просто украшают интерфейс, но и делают жизнь проще: показывают погоду, напоминания или даже быстрые действия. А сегодня мы нырнем в тему создания виджета с нуля на Kotlin с использованием Jetpack Compose через библиотеку Glance. Это будет эпичное путешествие! 🌟 Я напишу эту статью так, чтобы она была не сухим мануалом, а настоящим приключением. Мы разберем реальный код из моего проекта. Готовы? Поехали! 🚗 Сначала давайте разберемся, зачем вообще заморачиваться с виджетами. Представьте: пользователь добавляет ваш виджет на экран, и бац! — он видит актуальную инфу без запуска приложения. Это повышает вовлеченность, удерживает юзеров и делает ваш app standout'ом в Play Store. 📈 Традиционно виджеты писали на XML с RemoteViews — это было как езда на старом велосипеде: работает, но скрипит и неудобно. А с Jetpack Compose
Оглавление

Привет, друзья! 👋 Если вы, как и я, фанат Android-разработки, то наверняка знаете, насколько круто иметь на домашнем экране смартфона персонализированные виджеты. Они не просто украшают интерфейс, но и делают жизнь проще: показывают погоду, напоминания или даже быстрые действия. А сегодня мы нырнем в тему создания виджета с нуля на Kotlin с использованием Jetpack Compose через библиотеку Glance. Это будет эпичное путешествие! 🌟

Я напишу эту статью так, чтобы она была не сухим мануалом, а настоящим приключением. Мы разберем реальный код из моего проекта. Готовы? Поехали! 🚗

Почему виджеты и почему Glance? 🤔

Сначала давайте разберемся, зачем вообще заморачиваться с виджетами. Представьте: пользователь добавляет ваш виджет на экран, и бац! — он видит актуальную инфу без запуска приложения. Это повышает вовлеченность, удерживает юзеров и делает ваш app standout'ом в Play Store. 📈

Традиционно виджеты писали на XML с RemoteViews — это было как езда на старом велосипеде: работает, но скрипит и неудобно. А с Jetpack Compose всё изменилось! Compose — это declarative UI, где вы описываете, что хотите видеть, а не как это рендерить. Но для виджетов Compose не подходит напрямую (из-за ограничений AppWidget API). Вот тут на сцену выходит Glance — это надстройка от Google, которая адаптирует Compose для виджетов. Она простая, мощная и поддерживает темы (светлая/темная). Плюс, всё на Kotlin — чистый, современный код без boilerplate. 💻

Glance появился в 2021 году как часть Jetpack, и с тех пор стал must-have для новых проектов. В моей аппке "KraevedSPB" (краеведение Питера) я использую виджет для показа случайных фактов о городе. Но в этой статье мы возьмем простой пример: виджет с текстом "Привет от Glance!" и кнопкой обновления. Это база, которую вы расширите под свои нужды.

Call to action: Если вы новичок, скачайте Android Studio (версия Iguana или новее) и создайте пустой проект. Готовы к коду? Давайте настроим зависимости! 🔧

Шаг 1: Настройка проекта в Android Studio 🛠️

Открываем Android Studio и создаем новый проект: "Empty Activity" с Kotlin. Назовем его "MyWidgetApp". Теперь добавим зависимости в build.gradle (модуль app). Glance требует Jetpack Compose, так что вот что пишем:

-2

Не забудьте в build.gradle (project) добавить репозитории, если нужно:

-3

Синхронизируем проект (Gradle sync). Если ошибки — проверьте SDK (минимум Android 8.0, API 26). 😅

Теперь в манифесте (AndroidManifest.xml) добавим разрешения. В моем примере их много, потому что app сложное, но для простого виджета хватит базовых: INTERNET (если фетчите данные) и RECEIVE_BOOT_COMPLETED (для обновлений после ребута). Вот фрагмент из моего манифеста:

-4

Это позволит виджету обновляться автоматически. Без этого он "заснет" после перезагрузки устройства. 📱

Шаг 2: Создаем XML для виджета 📄

Виджеты нуждаются в конфигурации. Создайте папку res/xml и файл my_app_widget_info.xml. Вот содержимое:

-5

Здесь initialLayout — это плейсхолдер, пока Glance рендерит контент. Glance предоставляет дефолтный loading_layout, но вы можете кастомизировать. Это минимальный XML — Glance берет на себя остальное. Круто, правда? Нет больше кучи атрибутов как в старых виджетах! 🎉

Теперь интегрируем в манифест. Добавьте ресивер:

-6

Этот ресивер "ловит" события обновления виджета. Package у меня com.websage.kraevedspb.utils — подставьте свой.

Интересный факт: В Android 12+ exported="true" обязательно для безопасности. Без этого виджет не запустится! ⚠️

Шаг 3: Пишем код виджета на Kotlin с Glance 💻

Вот где магия! Создайте файл MyAppWidget.kt в пакете utils (или где угодно). Разберем по частям.

Сначала callback для обновления:

-7

Это ActionCallback — он вызывается при клике на виджет. Мы просто обновляем все инстансы виджета через updateAll. Простота! 🔄

Далее, ресивер:

-8

GlanceAppWidgetReceiver — базовый класс, который связывает виджет с системой. Мы переопределяем glanceAppWidget, указывая наш класс.

Теперь сам виджет:

-9

Разберем подробно. provideGlance — это точка входа, где Glance рендерит контент. Мы используем provideContent с Composable-функцией WidgetContent.

В WidgetContent: Column — как в Compose, вертикальный контейнер. Modifier цепочкой:

  • background: ColorProvider для тем (day/night). Glance автоматически подстраивается под системную тему! 🌙☀️
  • cornerRadius(16.dp): Закругленные углы для стиля Material You.
  • clickable: При клике запускаем наш callback. actionRunCallback — это Glance-способ привязать действие.
  • padding(16.dp): Отступы для красоты.

Внутри: Два Text и Spacer. TextStyle с Bold для заголовка. Всё declarative — никаких findViewById! 😍

Почему это круто? В старых виджетах вы бы писали тонну кода для обновлений, а здесь — пара строк. Плюс, Compose-подобный синтаксис делает код читаемым.

Шаг 4: Полный манифест и разрешения 🔒

В моем проекте манифест жирный, потому что app имеет контакты, уведомления и т.д. Но для виджета ключевые части:

-10

Здесь SyncBootReceiver — для перезапуска синхронизации после ребута. Для простого виджета можете добавить похожий, чтобы обновлять данные автоматически.

Совет: Если виджет фетчит данные из сети, используйте WorkManager для фоновых задач. Glance интегрируется с ним seamlessly. 📡

Шаг 5: Тестирование виджета 🧪

Соберите проект (Build > Make Project). Запустите на эмуляторе или устройстве. Долгий тап по домашнему экрану > Виджеты > Найдите ваш "MyAppWidget". Добавьте — и вуаля! Виджет с текстом и кликабельный. Нажмите — он обновится (хотя в этом примере ничего не изменится, но callback сработает).

Если не работает:

  • Проверьте логи (Logcat, фильтр "Glance").
  • Убедитесь, что Glance версии совместимы.
  • На Android 13+ запросите разрешения runtime, если нужно.

Тестируйте в разных темах: светлой и темной. Glance сам адаптирует цвета! 🌗

Фан-факт: Glance рендерит виджет в отдельном процессе, так что он не крашит основное app. Безопасно! 🛡️

Расширение виджета: Добавляем реальные данные 📊

Наш пример простой, но давайте усложним. Предположим, вы хотите показывать случайный факт о Питере (как в моей аппке).

  1. Добавьте зависимость на Retrofit или Ktor для API.
  2. В provideGlance загрузите данные асинхронно.

Glance поддерживает State — используйте mutableStateOf для динамики.

Пример расширения WidgetContent:

-11

Для реального фетча: Используйте CoroutineScope в callback или WorkManager. Не блокируйте UI! ⏳

Call to action: Попробуйте добавить API-колл. Возьмите бесплатный API, например, random fact generator. Ссылка: Random Fact API — интегрируйте и увидите магию! 🔗

Лучшие практики и распространенные ошибки ⚠️

  • Обновления: Не обновляйте виджет слишком часто — Android лимитирует до 1 раза в 30 мин без AlarmManager. Используйте SCHEDULE_EXACT_ALARM для точности.
  • Размеры: Glance поддерживает resizable виджеты. Добавьте в XML: android:resizeMode="horizontal|vertical".
  • Темы: Всегда используйте ColorProvider для day/night.
  • Ошибки: Если "No Glance content provided" — проверьте provideContent. Если краш — смотрите StackOverflow (шучу, но seriously 😆).
  • Производительность: Держите виджет легким. Нет тяжелых анимаций — Glance не для этого.

В моей аппке я добавил уведомления (POST_NOTIFICATIONS) и foreground service для синхронизации контактов. Но для виджета это опционально.

История из жизни: Когда я первый раз делал виджет без Glance, потратил неделю на RemoteViews. С Glance — за вечер! Экономьте время, друзья. ⏰

Интеграция с другими фичами Android 🤝

Виджет может взаимодействовать с app. Например, клик открывает активность:

Вместо actionRunCallback используйте actionStartActivity.

-12

Добавьте в манифест intent-filter для deep links, если нужно.

Для уведомлений: В callback отправьте notification.

Плюс, поддержка Android TV? В манифесте я добавил uses-feature для исключения TV, потому что app для смартфонов. Если хотите TV-виджеты — адаптируйте.

Безопасность и разрешения 🔐

В манифесте куча разрешений: READ_CONTACTS для интеграции с контактами, CALL_PHONE для звонков. Но для виджета минимизируйте. Запрашивайте runtime permissions в app.

Android 14 ввел новые правила для foreground services — добавьте FOREGROUND_SERVICE_DATA_SYNC.

Совет: Тестируйте на разных API: от 26 до 35. Используйте @RequiresApi для conditional code.

Оптимизация и монетизация 💰

Виджет — отличный способ монетизировать: показывайте ads (но не навязчиво) или premium-функции.

Оптимизируйте: Используйте Glance preview в Android Studio для дизайна без запуска.

Для большого трафика: Сервер-сайд данные, чтобы не нагружать устройство.

В Дзене виджеты помогут: Добавьте в статью скриншоты (я опишу: светлый фон, закругленный, текст bold).

Заключение: Ваш первый виджет готов! 🎊

Мы прошли путь от нуля до рабочего виджета на Kotlin с Jetpack Compose и Glance. Это база для крутых фич: погода, todo-листы, крипто-курсы!

Call to action: Создайте свой виджет прямо сейчас! Поделитесь в комментариях, что получилось. Подпишитесь на канал, чтобы не пропустить обновления по Android-dev. Ссылки: Документация Glance 🔗. Удачи в разработке! 🚀