Программирование
10 советов по разработке виджетов для iOS 14
После экспериментов с фреймворком WidgetKit в бета-версиях iOS 14 и Xcode 12 я хочу поделиться 10 интересными советами, которые могут быть полезны при написании виджетов для ваших приложений.
Виджеты стали одной из главных премьер iOS 14 и самым большим изменением домашнего экрана iOS. С точки зрения пользователя виджеты представляют новый тип взаимодействия, новую точку входа для приложений. С технологической точки зрения это манифест Apple, представляющий ключевые технологии и будущее iOS-разработки — SwiftUI (единственный способ создания представлений для виджетов) и оптимизированную универсальность (виджеты доступны на iOS, iPadOS и macOS).
После экспериментов с фреймворком WidgetKit в бета-версиях iOS 14 и Xcode 12 я хочу поделиться 10 интересными советами, которые могут быть полезны при написании виджетов для ваших приложений.
Давайте начнем!
1. UserDefaults
Скорее всего, вам нужно будет использовать UserDefaults, чтобы читать пользовательские настройки или другие небольшие объемы данных. Для этого стандартный контейнер не подходит, потому что его содержимое не используется в виджетах. Вместо этого, как и для любого другого расширения приложения, вы должны полагаться на общий «набор», названный по имени App Group ID, используя выделенный API:
let userDefaults = UserDefaults(suiteName: “your-app-group-id”)
App Group доступна на вкладке «Signin & Capabilities» ваших таргетов: не забудьте добавить возможность группы приложений как в цель приложения, так и в цель виджета, иначе она не будет работать.
2. Разрешение на геолокацию
Как правило, виджеты наследуют каждое разрешение от родительского приложения, и им самим не разрешено создавать запросы. Разрешение на определение местоположения представляет собой исключение: начиная с пятой бета-версии, когда на главный экран добавляется виджет, использующий местоположение, пользователю будет автоматически предложено предоставить разрешение через предупреждение. Выбор можно изменить в любое время в настройках, так как доступен новый параметр «При использовании приложения или виджетов».
Кроме того, не забудьте поместить ключи NSWidgetWantsLocation (boolean) и NSLocationUsageDescription в расширение виджета Info.plist, чтобы службы определения местоположения работали правильно.
3. Карты с MKMapSnapshotter
Говоря о местоположении, может возникнуть другой вопрос: как лучше всего представить карту внутри виджета? Рекомендуемый вариант — использовать MKMapSnapshotter вместо MKMapView; на самом деле стандартный вид карты вообще не работает. Снимок отображает содержимое карты в виде простого изображения. Чтобы получить желаемый MKMapSnapshotter.Snapshot:
Замыкание идеально подходит для использования в функции getTimeline(in:completion:) протокола TimelineProvider: после загрузки изображения вы можете создавать свои записи и определять таймлайн. Снапшот легко настраивается, и вы можете найти полную документацию здесь.
4. Ограничение памяти
Изображение карты — отличный пример того, насколько легковесным должно быть содержимое виджета. Видео, анимация и т.д. недоступны — более того, обертки UIKit в UIViewRepresentable не работают в виджетах. В связи с этим, вы должны принять во внимание ограничение на выделение памяти: это явно не указано в документации, но виджеты, превышающие 30 Мбайт, похоже, крешатся в доступных бета-версиях, поэтому имейте это в виду.
5. Политики обновления
Я не говорю про разные способы обновления вашего виджета и управления ими (для этого потребуется отдельная статья :)), но главным вопрос — как часто можно обновлять виджет? В документации не указывается точная политика, но благодаря этой ветке на форуме разработчиков Apple мы можем сказать, что 15 минут, вероятно, являются минимальным интервалом времени, чтобы не исчерпать ограниченные доступные обновления.
6. ContainerRelativeShape
Еще один интересный трюк с простым пользовательским интерфейсом связан с формой представлений внутри виджетов. Чтобы соответствовать радиусу угла виджета (который меняется на разных устройствах), Apple предлагает использовать API SwiftUI ContainerRelativeShape вместо определения кастомного скругления: он автоматически сделает формы подходящими виджету. Вот пример:
Image("map-placeholder").clipShape(ContainerRelativeShape())
7. Ссылка или widgetUrl
Как только пользователь взаимодействует (касается) виджета, запускается родительское приложение для обработки запроса: вы можете указать URL-адрес, который будет передан приложению для выполнения определенных действий. Есть два способа: с помощью модификатора widgetUrl (_ :) для определения уникального поведения, которое будет применяться ко всем целевым объектам виджета, или с помощью элемента управления Link для определения разных URL-адресов для разных целей в иерархии представления. Поскольку маленький виджет позволяет использовать только одну цель касания, для него предпочтительнее использовать модификатор widgetUrl. Давайте посмотрим на пример:
В случае средних или больших виджетов вы можете использовать эти два варианта вместе: URL каждой ссылки используется для касаний в целевом представлении, а widgetUrl — для касаний в другом месте. URL-адрес обрабатывается методом application (_: open: options :) для приложений с классическим AppDelegate или onOpenUrl (perform :) API для приложений жизненного цикла SwiftUI, представленных в iOS 14.
8. Бандл виджетов
Еще одна замечательная функция — это возможность распространять больше одного виджета для приложения, используя WidgetBundle API:
После некоторых экспериментов кажется, что вы можете создать до 5 различных виджетов, каждый с 3 доступными размерами, но в этой ветке описывается способ преодолеть это ограничение.
9. WidgetPreviewContext
При программировании виджета очень удобно иметь предварительный просмотр того, что вы создаете, в области холста Xcode Previews. Этого можно добиться, указав PreviewProvider. Предварительный просмотр — это вид виджета, в котором PreviewContext установлен как WidgetPreviewContext:
Можно определить более одного предварительного просмотра, чтобы увидеть виджеты всех доступных типов, а также изменить некоторые ключи среды. Например, я просматривал виджеты в темном режиме.
10. Плейсхолдеры
Заполнители используются для отображения общего представления виджета, когда он загружается в первый раз и добавляется на рабочий стол. Благодаря бета-версиям способ определения заполнителя был упрощен, и теперь вам просто нужно реализовать требуемую функцию placeholder(in:) в TimelineProvider, возвращающую обычный TimelineEntry. Автоматически будет применен модификатор вида redacted(reason: .placeholder).
В заключение я настоятельно рекомендую проверить ресурсы Apple, в том числе коллекцию «Создаем Widget вместе» и сессию «Создание отличных виджетов» с WWDC20. Надеюсь увидеть много готовых виджетов, спасибо за чтение!