Skip to main content

Multiplatform Settings

Ознакомьтесь с multiplatform-settings - библиотекой, позволяющей сохранять key-value данные в параметры устройства из общего кода, используя SharedPreferences для Android и NSUserDefaults для iOS
Разберем варианты ее подключения к проекту.

Подключение, используя expect/actual

Создайте expect/actual функцию, для получения settings на платформах

  • получение settings для Android
    androidMain:

    var appContext: Context? = null

    actual fun getSettings(): Settings {
    val delegate = appContext!!.getSharedPreferences("app", Context.MODE_PRIVATE)
    val settings: Settings = SharedPreferencesSettings(delegate)
    return settings
    }

    Перед тем, как обращаться к функции getSettings, проинициализируйте переменную appContext.

  • получение settings для iOS
    iosMain:

    actual fun getSettings(): Settings {
    val delegate = NSUserDefaults.standardUserDefaults
    val settings: Settings = NSUserDefaultsSettings(delegate)
    return settings
    }

Подключение no-arg библиотеки

Если вся работа с multiplatform-settings будет происходить в общем коде, вы можете использовать no-arg-module.
Используя его, вам не придется инициализировать Settings на платформе, для Android, в качестве делегата будет использоваться PreferenceManager.getDefaultSharedPreferences(), а для iOS - NSUserDefaults.standardUserDefaults.

  • подключите no-arg библиотеку к commonMain модулю: implementation("com.russhwolf:multiplatform-settings-no-arg:1.3.0")
  • создайте settings, сохраните значение, а затем прочитайте
  • протестируйте на обеих платформах

Подключение напрямую к платформе

Нам необходимо подключить библиотеку как api, чтобы ее классы были доступны за пределами общего модуля. Подробнее о разнице между api и implementation можете почитать здесь.
Добавьте подключение библиотеки к общему модулю:

commonMain {
dependencies {
// ...
api("com.russhwolf:multiplatform-settings:1.3.0")
}
}

Убедитесь, что класс SharedPreferencesSettings стал доступен в Android-проекте.

Однако, этого не достаточно, чтобы библиотека стала доступна и на iOS. Чтобы это сделать, необходимо добавить классы библиотеки в header iOS фреймворка, чтобы они стали видны из swift. По умолчанию, для api-зависимостей этого не происходит, потому что тогда бы бинарник фреймворка был бы огромный (кому интересно, почитайте об этом тут).
Но, при желании, добавить классы в хидер можно, для этого добавьте следующие строчки в раздел cocoapods/framework в shared/build.gradle файле:

export("com.russhwolf:multiplatform-settings:1.3.0")

Как должно получиться:

cocoapods {
summary = "Some description for the Shared Module"
homepage = "Link to the Shared Module homepage"
ios.deploymentTarget = "14.1"
podfile = project.file("../iosApp/Podfile")
framework {
baseName = "shared"
export("com.russhwolf:multiplatform-settings:1.3.0")
}
}

Более подробно о настройке фреймворка вы можете прочитать тут.

Наконец, выполните команду pod install и классы библиотеки mutliplatform-settings станут доступны на iOS, попробуйте создать NSUserDefaultsSettings.

KeyValueStorage

В работе мы делегируем работу с хранилищем устройства классу KeyValueStorage.

Это позволяет нам:

  • Не создавать константу-ключ для каждой переменной в хранилище
  • Не беспокоиться о том, что в переменной окажется что-то не то, потому что мы задали тип
class KeyValueStorage(settings: Settings) {
var platformName: String? by settings.nullableString("platform_name_key")
var language: String? by settings.nullableString("language_key")
}

Практическое задание

  1. Откройте проект, который вы изменяли в разделе expect/actual или создайте новый по инструкции
  2. Подключите multiplatform-settings, используя no-arg модуль библиотеки, убедитесь, что все работает
  3. Подключите multiplatform-settings напрямую к платформам, убедитесь, что все работает
  4. Подключите multiplatform-settings, используя expect/actual, убедитесь, что все работает
  5. Сохраните название платформы в хранилище устройства в общем коде
  6. Для iOS и Android выведите на экран значение, которое сохранили в общем коде используя библиотеку