Привет, друзья! 👋 Если вы, как и я, фанат 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, так что вот что пишем:
Не забудьте в build.gradle (project) добавить репозитории, если нужно:
Синхронизируем проект (Gradle sync). Если ошибки — проверьте SDK (минимум Android 8.0, API 26). 😅
Теперь в манифесте (AndroidManifest.xml) добавим разрешения. В моем примере их много, потому что app сложное, но для простого виджета хватит базовых: INTERNET (если фетчите данные) и RECEIVE_BOOT_COMPLETED (для обновлений после ребута). Вот фрагмент из моего манифеста:
Это позволит виджету обновляться автоматически. Без этого он "заснет" после перезагрузки устройства. 📱
Шаг 2: Создаем XML для виджета 📄
Виджеты нуждаются в конфигурации. Создайте папку res/xml и файл my_app_widget_info.xml. Вот содержимое:
Здесь initialLayout — это плейсхолдер, пока Glance рендерит контент. Glance предоставляет дефолтный loading_layout, но вы можете кастомизировать. Это минимальный XML — Glance берет на себя остальное. Круто, правда? Нет больше кучи атрибутов как в старых виджетах! 🎉
Теперь интегрируем в манифест. Добавьте ресивер:
Этот ресивер "ловит" события обновления виджета. Package у меня com.websage.kraevedspb.utils — подставьте свой.
Интересный факт: В Android 12+ exported="true" обязательно для безопасности. Без этого виджет не запустится! ⚠️
Шаг 3: Пишем код виджета на Kotlin с Glance 💻
Вот где магия! Создайте файл MyAppWidget.kt в пакете utils (или где угодно). Разберем по частям.
Сначала callback для обновления:
Это ActionCallback — он вызывается при клике на виджет. Мы просто обновляем все инстансы виджета через updateAll. Простота! 🔄
Далее, ресивер:
GlanceAppWidgetReceiver — базовый класс, который связывает виджет с системой. Мы переопределяем glanceAppWidget, указывая наш класс.
Теперь сам виджет:
Разберем подробно. 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 имеет контакты, уведомления и т.д. Но для виджета ключевые части:
Здесь SyncBootReceiver — для перезапуска синхронизации после ребута. Для простого виджета можете добавить похожий, чтобы обновлять данные автоматически.
Совет: Если виджет фетчит данные из сети, используйте WorkManager для фоновых задач. Glance интегрируется с ним seamlessly. 📡
Шаг 5: Тестирование виджета 🧪
Соберите проект (Build > Make Project). Запустите на эмуляторе или устройстве. Долгий тап по домашнему экрану > Виджеты > Найдите ваш "MyAppWidget". Добавьте — и вуаля! Виджет с текстом и кликабельный. Нажмите — он обновится (хотя в этом примере ничего не изменится, но callback сработает).
Если не работает:
- Проверьте логи (Logcat, фильтр "Glance").
- Убедитесь, что Glance версии совместимы.
- На Android 13+ запросите разрешения runtime, если нужно.
Тестируйте в разных темах: светлой и темной. Glance сам адаптирует цвета! 🌗
Фан-факт: Glance рендерит виджет в отдельном процессе, так что он не крашит основное app. Безопасно! 🛡️
Расширение виджета: Добавляем реальные данные 📊
Наш пример простой, но давайте усложним. Предположим, вы хотите показывать случайный факт о Питере (как в моей аппке).
- Добавьте зависимость на Retrofit или Ktor для API.
- В provideGlance загрузите данные асинхронно.
Glance поддерживает State — используйте mutableStateOf для динамики.
Пример расширения WidgetContent:
Для реального фетча: Используйте 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.
Добавьте в манифест 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 🔗. Удачи в разработке! 🚀