Nadzeya Savitskaya 27 января 2023

📱 3 способа передачи информации из основного таргета приложения в таргет виджетов

В этой статье я расскажу о трех простых способах передачи различной информации из основного таргета приложения в таргет виджетов на примерах с кодом.
📱 3 способа передачи информации из основного таргета приложения в таргет виджетов

Так или иначе, но в виджеты необходимо передавать информацию из основного приложения. Это может быть все что угодно: от выбранного пользователем формата времени до полученных писем в почтовом клиенте. В этой статье я расскажу об основных способах передачи данных между таргетами приложения.

AppGroup

Таргет виджетов не является чем-то уникальным и работает примерно так же, как и остальные таргеты других app extensions. И для передачи информации по разным таргетам сначала надо добавить в приложение AppGroup. Во вкладке Signing & Capabilities основного таргета вашего проекта нужно нажать на кнопку + Capability и в новом окно выбрать App Groups. Хорошей практикой является назвать AppGroup как “group.” + buindle id приложения.

Рис. 1. Создание App Group
Рис. 1. Создание App Group

После этого можно добавить id вашей AppGroups в константы, добавить файл констант в таргет виджетов и иметь доступ к id везде, где понадобится, например, так:

        import Foundation

struct Constants {
    static let appGroupID = "group.com.nadzeya.widgetsSandbox"
}
    
Рис. 2. Добавление файла в таргет виджетов
Рис. 2. Добавление файла в таргет виджетов

Теперь мы готовы передавать данные между таргетами, и начнем с самого простого – UserDefaults.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека мобильного разработчика»

UserDefaults

UserDefaults в Swift – это класс, который предоставляет возможность сохранять пары ключ-значение в пользовательскую встроенную базу данных. В нее можно сохранять значения разных типов данных – String, Bool, Data, Date, Array, Dictionary и проч. В основном UserDefaults используются для хранения некоторых настроек приложения и/или пользовательских предпочтений, таких как выбранный формат времени и даты, темная или светлая тема приложения, если, конечно, приложение поддерживает это. Также еще в UserDefaults можно хранить что-то важное для аналитики или отображения некоторых экранов, например, дату первой сессии приложения. И для того, чтобы была возможность использовать в разных таргетах сохраненные в UserDefaults значения, нам надо их сохранять в главном таргете не в UserDefaults.standard:

        UserDefaults.standard.set("my_value", forKey: "myValueKey")
    

а в наш контейнер AppGroup:

        UserDefaults(suiteName: Constants.appGroupID)!.set("my_value", forKey: "myValueKey")
    

И мы тогда сможем читать сохраненные данные в таргете виджета таким образом. Допустим, мы сохранили что-то типом String:

        let savedValue = UserDefaults(suiteName: Constants.appGroupID)!.string(forKey: "myValueKey")
    

Вот так просто меняется работа с UserDefaults и теперь мы можем через них передавать нужные нам данные в таргет виджета.

File Container

UserDefaults отлично справляются с хранением чего-то небольшого, но если есть задача передать в таргет виджетов нечто большее, чем пользовательские настройки, а базы данных в приложении нет, то можно использовать File Container и хранить необходимые данные, например в .plist-файле или в .json-файле. Для этого нам надо создать нужный нам файл в File Container для нашей App Group и записать в него информацию:

        let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupID)!
let fileURL = containerURL.appendingPathComponent("savedDataForWidgets.json")

do {
   let encoded = try JSONEncoder().encode(myWidgetData)
   try! encoded.write(to: fileURL)
} catch {
    print( error)
}
    

И, соответственно, вот так можно читать эту информацию в таргете виджета:

        var widgetData: [MyWidgetData] = []
guard let data = try? Data(contentsOf: url) else {
        return widgetData
    }
    
do {
   widgetData = try JSONDecoder().decode([MyWidgetData].self, from: data)
} catch {
    print(error)
}
    

CoreData

В большом количестве приложений используются CoreData для хранения данных, и для того, чтобы можно было ею пользоваться в таргете виджетов, надо создать общий CoreData контейнере в AppGroup:

        let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupID)!
let storeURL = containerURL.appendingPathComponent("MyWidgetDataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)

let container = NSPersistentContainer(name: "MyWidgetDataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }
    

И теперь мы можем получать наши данные в таргете виджета вот так:

        let managedObjectContext = CoreDataStack.shared.managedObjectContext
let predicate = NSPredicate(format: "id == %@", "widgetID")
let request = NSFetchRequest<SomeItem>(entityName: "MyWidget")
let result = try managedObjectContext.fetch(request)
    

Кроме CoreData, есть и другие базы данных, но принцип везде примерно одинаковый: можно добавить файлы базы данных в таргет виджета и уже в нем напрямую запрашивать необходимую информацию. Есть только одно но: виджеты ни в каком виде не поддерживают асинхронный код, то есть и запросы за данными надо будет делать синхронно.

***

Я постаралась подробно рассказать об основных способах передачи данных из основного таргета приложения в таргет виджетов. Надеюсь, что эта статья была полезной. Я буду рада фидбэку и комментариям. Спасибо!

Савицкая Надежда, iOS-разработчик.

Материалы по теме

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ