Перейти к основному содержимому

SigmaSDK - Android

Sigma - это платформа для экспериментов, которая позволяет вам быстро оценивать влияние новых функций и предлагать продукты, которые нравятся вашим клиентам.

Требования

  • Android API level 21+

Настройка Gradle

В файле build.gradle, который находится в корневой папке проекта, нужно добавить репозиторий jitpack. Для этого в конце списка репозиториев добавьте maven { url 'https://jitpack.io' }:

allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}

Если ваши репозитории для получения зависимостей объявлены в файле settings.gradle, то добавьте следующий код в dependencyResolutionManagement:

dependencyResolutionManagement {
...
repositories {
...
maven { url "https://jitpack.io" }
}
}

Затем добавьте следующую зависимость в файл build.gradle нужного вам модуля приложения (например, :app):

dependencies {
...
//SigmaSDK
implementation "ru.expf-team.sigma:kotlin-sdk:VERSION"
...
}

VERSION замените актуальной версией Sigma-SDK.

Инициализация SigmaSDK

Для инициализации SigmaSDK в классе, унаследованном от класса Application, в теле переопределенного метода onCreate() добавьте вызов статического метода Sigma.initializeClient().

Данный метод принимает следующие параметры:

  • application - объект класса приложения.
  • projectToken - токен проекта (указан в панели управления).
  • initialUserProperties - необязательный параметр, лямбда для назначения свойств пользователя.
  • cacheTtlMillis - необязательный параметр, время жизни кеша полученного конфига из сети (по умолчанию равен 60 секундам, также если указать значение меньшее 10 секундам, то оно будет проигнорировано и будет использовано значение по умолчанию.).
  • retryCount - необязательный параметр, количество повторных попыток запрашивания конфига при неудачном запросе (по умолчанию равен 3).
  • tag - необязательный параметр, тег клиента Sigma (по умолчанию равен 'default'). Необходим для создания нескольких инстансов SigmaClient.
  • sigmaJsonAdapter - необязательный параметр, адаптер, который будет использоваться при получении значений типа JSON в параметрах эксперимента и Feature Flag (по умолчанию равен SigmaGsonAdapter с конструктором по умолчанию).
  • apiUrl - необязательный параметр, Web URL который используется SDK для запросов в сеть (по умолчанию равен https://api.expf.ru/api/v1).

Пример вызова метода:

import ru.expf.sigma.Sigma
...
Sigma.initializeClient(
application = this,
projectToken = "projectToken",
initialUserProperties = { setUserId("...") },
cacheTtlMillis = 20_000L,
retryCount = 10,
)

Получение объекта SigmaClient

Чтобы получить инстанс SigmaClient используется статический метод Sigma.getClient(). Данный метод принимает следующие параметры:

  • tag - необязательный параметр, тег клиента Sigma (по умолчанию равен 'default').

Завершение работы клиента

Когда работа с клиентом завершена, рекомендуется освободить память от уже ненужного объекта SigmaClient. Для этого используется статический метод Sigma.removeClient().
Данный метод принимает следующие параметры:

  • tag - необязательный параметр, тег клиента Sigma (по умолчанию равен 'default').

Пример создания нескольких клиентов Sigma

Инициализация:

import ru.expf.sigma.Sigma
...
const val TAG_1 = "TAG_1"
const val TAG_2 = "TAG_2"
...
Sigma.initializeClient(
application = this,
projectToken = "...",
tag = TAG_1,
)
Sigma.initializeClient(
application = this,
projectToken = "...",
tag = TAG_2,
)

Использование:

import ru.expf.sigma.*
...
val firstClient = Sigma.getClient(TAG_1)
val secondClient = Sigma.getClient(TAG_2)
...
async {
firstClient.getAllUserExperiments()
secondClient.checkFlag<Float>("...")
}.await()
...
firstClient.setUserProperties { setDeviceId("...") }

Свойства пользователя

Назначение свойств пользователя

Для назначения свойств пользователя используется интерфейс SigmaUserPropertiesSetter. Получить реализацию этого интерфейса можно вызвав методы:

  • Sigma.initializeClient(initialUserProperties = { ... }) - назначение свойств пользователя при инициализации клиента Sigma.
  • SigmaClient.setUserProperties { ... } - назначение свойств пользователя в уже существующем объекте клиента.

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

Описание методов SigmaUserPropertiesSetter

SigmaUserPropertiesSetter обладает методами для построения набора key-value свойств пользователя. Эти свойства можно разделить на следующие категории:

Идентификаторы использующиеся для назначения вариантов эксперимента:

  • setUserId() - назначение свойства пользователя с названием userId.
  • setDeviceId() - назначение свойства пользователя с названием deviceId.
  • setProfileId() - назначение свойства пользователя с названием profileId.

Свойства которые определяются на уровне SDK, но могут быть переопределены:

  • setAppVersion() - назначение cвойства пользователя с названием appVersion.
  • setGeoCode() - назначение cвойства пользователя с названием geo.code.
  • setGeoCountry() - назначение cвойства пользователя с названием geo.country.
  • setGeoState() - назначение cвойства пользователя с названием geo.state.
  • setGeoCity() - назначение cвойства пользователя с названием geo.city.
  • setOsName() - назначение cвойства пользователя с названием os.name​.
  • setOsVersion() - назначение cвойства пользователя с названием os.version.

Свойства которые определяются только разработчиком

  • setEmail() - назначение свойства пользователя с названием email.

Сustom свойства

Такие свойства могут иметь любое название, но при этом к их названию добавится префикс custom.* . (прим. custom.nickname, custom.language).

  • setCustomProperty() - назначение custom-свойства пользователя

Данный метод принимает название и значения свойства и имеет 3 варианта использования:

setCustomProperty("***" to "***")
setCustomProperty { "***" to "***" }
setCustomProperty("***", "***")

Пример использования SigmaUserPropertiesSetter


val client = Sigma.getClient()
client.setUserProperties {
setUserId("id")
setCustomProperty { "length" to "10" }
setAppVersion("7.2.1")
}

Изменение свойств пользователя

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

  • SigmaClient.editUserProperties { ... }

Работа с ним происходит аналогично с SigmaUserPropertiesSetter, но, в отличии от него, данный интерфейс обладает методами для удаления пользовательских свойств.

Пример:

import ru.expf.sigma.Sigma
...
val client = Sigma.getClient()
client.editUserProperties {
setGeoCountry("USA")
removeEmail()
removeOsVersion()
removeCustomProperty("myProperty")
}

Для удаления всех свойств пользователя используется метод SigmaClient.clearUserProperties().

Пример вызова метода:

import ru.expf.sigma.Sigma
...
val client = Sigma.getClient()
client.clearUserProperties()

Время жизни свойств пользователя

Каждое назначенное свойство пользователя используется Sigma-SDK в течении 24 часов. По истечению этого времени оно будет игнорироваться при расчетах.

Важно! При редактировании свойства отчет этого промежутка времени начинается заново.

Получение значения Feature Flag

Для получения значения Feature Flag используется метод: SigmaClient.checkFlag()

Данный метод принимает следующие параметры:

  • name - название Feature Flag.
  • jClass - необязательный параметр при использовании SigmaClient extension-функции с аналогичным названием, java-класс типа в который преобразуется значение получаемого Feature Flag (Float, Long, Int, Double, String, Boolean), (JSON-класс - см. SigmaJsonAdapter) или null
  • callback - необязательный параметр при использовании suspend версии метода, объект интерфейса SigmaCheckFlagCallback реализующий его методы onSuccess() и onError().

Примеры вызова метода:

Без использования kotlin.coroutines

import ru.expf.sigma.*
...
val client = Sigma.getClient()
client.checkFlag(
name = "***",
callback = object: SigmaCheckFlagCallback<String> {
override fun onSuccess(value: String?) {
/** Some code with received value */
}

override fun onError(throwable: Throwable) {
/** Some code with received error */
}
}
)

С использованием kotlin.coroutines

import ru.expf.sigma.*
...
async {
val client = Sigma.getClient()
val flagValue = client.checkFlag<String>(name = "***")
}.await()

Стоит обратить внимание на то, что в случае несоответсвия ни одному условию в правилах результат работы метода будет равен null.
Также, если в данный метод передать тип значения Feature Flag, который не поддерживается со стороны SDK, то он вернет ошибку InvalidParameterSpecException.

Получение эксперимента

Для получения эксперимента используется метод SigmaClient.getExperiment().

Данный метод принимает следующие параметры:

  • id - идентификатор эксперимента.
  • callback - необязательный параметр при использовании suspend версии метода, объект интерфейса SigmaGetExperimentCallback реализующий его методы onSuccess() и onError().

Примеры вызова метода:

Без использования kotlin.coroutines

import ru.expf.sigma.Sigma
import ru.expf.sigma.SigmaExperiment
import ru.expf.sigma.SigmaGetExperimentCallback
...
val client = Sigma.getClient()
client.getExperiment(
id = "***",
callback = object : SigmaGetExperimentCallback {
override fun onSuccess(experiment: SigmaExperiment?) {
/** Some code with received experiment */
}

override fun onError(throwable: Throwable) {
/** Some code with received error */
}
}
)

С использованием kotlin.coroutines

import ru.expf.sigma.Sigma
import ru.expf.sigma.SigmaExperiment
...
async {
val client = Sigma.getClient()
val experiment = client.getExperiment(id = "***")
}.await()

Стоит обратить внимание на то, что в случае непопадания пользователем в эксперимент результат работы метода будет равен null.

Данный метод возвращает объект интерфейса SigmaExperiment, который реализует следующие поля и методы:

  • поле groupIndex - возвращает индекс группы пользователя.
  • метод getParamValue() - принимают название параметра, возвращают его значение преобразованное в указанный тип (Float, Long, Int, Double, String, Boolean) или null.
  • метод getFeatureFlagValue() - работает аналогично Sigma.checkFlag(), но в пределах эксперимента. (см. Получение значения Feature Flag)

Пример использования

Без использования kotlin.coroutines

import ru.expf.sigma.*
...
val client = Sigma.getClient()
client.getExperiment(
id = "***",
callback = object : SigmaGetExperimentCallback {
override fun onSuccess(experiment: SigmaExperiment?) {
val featureFlagValue = experiment?.getFeatureFlagValue<String>("flagName")
val paramValue = experiment?.getParamValue<Double>("paramName")
}

override fun onError(throwable: Throwable) {
/** Some code with received error */
}
}
)

С использованием kotlin.coroutines

import ru.expf.sigma.*
...
async {
val client = Sigma.getClient()
val experiment = client.getExperiment(id = "***")
val featureFlagValue = experiment?.getFeatureFlagValue<String>(name = "flagName")
val paramValue = experiment?.getParamValue<Double>(name = "paramName")
}.await()

Получение всех экспериментов пользователя

Для получения всех экспериментов пользователя используется статический метод Sigma.getAllUserExperiments().

Данный метод принимает следующие параметры:

  • callback - необязательный параметр при использовании suspend версии метода, объект интерфейса SigmaGetAllUserExperimentsCallback реализующий его методы onSuccess() и onError() .

Примеры вызова метода:

Без использования kotlin.coroutines

import ru.expf.sigma.Sigma
import ru.expf.sigma.SigmaGetAllUserExperimentsCallback
...
val client = Sigma.getClient()
client.getAllUserExperiments(
callback = object : SigmaGetAllUserExperimentsCallback {
override fun onSuccess(experiments: String?) {
/** Some code with received experiments string */
}

override fun onError(throwable: Throwable) {
/** Some code with received error */
}
}
)

С использованием kotlin.coroutines

import ru.expf.sigma.Sigma
...
async {
val client = Sigma.getClient()
val experiments = client.getAllUserExperiments()
}.await()

Данный метод возвращает строку вида "expId.userGroupIndex|expId.userGroupIndex|...", где ** expId** - идентификатор эксперимента и userGroupIndex индекс группы пользователя в эксперименте.

Стоит обратить внимание на то, что в случае непопадания пользователем ни в один эксперимент результат работы метода будет равен null.

SigmaJsonAdapter

При получении значения Feature Flag или параметра эксперимента можно указать класс, в поля которого будут записаны значения указанные в JSON по логике выбранного адаптера.

Для того, чтобы не подключать к проекту ещё один JSON-сериализатор в SDK представлены 3 реализации SigmaJsonAdapter для самых популярных:

  • SigmaGsonAdapter - конструктор принимает объект типа Gson
  • SigmaMoshiAdapter - конструктор принимает объект типа Moshi
  • SigmaKotlinAdapter - конструктор принимает объект типа kotlinx.serialization.json.Json

Если в проекте используется не представленный SDK JSON-сериализатор, то можно реализовать свой адаптер. Для этого необходимо унаследовать абстрактный класс SigmaJsonAdapter и реализовать его метод convert.

Список свойств автоматически определяющихся на стороне SDK

  • appVersion - версия приложения пользователя (по умолчанию используется versionCode, а не versionName).
  • os.version - номер версии Android на устройстве пользователя (допустимые значения можно посмотреть тут) .
  • os.name​ - название операционной системы пользователя (сейчас всегда будет равно "* android**")*.
  • time - текущее время пользователя.
  • date - текущая дата пользователя.
  • geo.country - страна пользователя.
  • geo.state - район пользователя.
  • geo.city - город пользователя.
  • geo.ip - IP-адрес пользователя.

Работа с кэшем в SDK

Локальное хранилище представляет собой обычную коллекцию key-value пар значений реализованное через SharedPreferences. Главный идентификатор хранилища представляет собой комбинацию тега клиента (см. Пример создания нескольких клиентов Sigma) и токена проекта. То есть для клиента с тегом TAG_1 будет разный кэш с клиентом с тегом TAG_2, при одном указанном токен проекта.

Config cache

Схема config cache

Cache ttl

При инициализации клиента SDK с помощью метода Sigma.initializeClient можно указать cacheTtl значение. Это время жизни кэша полученного конфига из сети. По умолчанию оно равно 60 секундам, однако, если указать значение меньшее 10 секунд, то оно будет проигнорировано, и будет использовано значение по умолчанию.

к сведению

При первичной инициализации клиента происходит запрос за актуальным конфигом игнорируя указанный cacheTtl

Методы SDK использующие config

К методам использующие конфиг относятся следующие:

  • SigmaClient.checkFlag
  • SigmaClient.getAllUserExperiments
  • SigmaClient.getExperiment То есть, при вызове одного из них, будет произведен вызов приватного метода SDK, который возвращает конфиг. Он выполняет следующее:
  • Проверяет прошло ли errorCoolDown времени (сейчас 1 минута) после последней ошибки запроса в сеть за конфигом (configErrorTimestamp).
  • Проверяет прошло ли cacheTtl времени с последнего сохранения конфига в кэш.
  • Возвращает конфиг из кэша или сети. Более подробно работу данной функции можно наблюдать на диаграмме ниже.

Geo cache

Схема geo cache

Android cache config schema

Каждый раз при инициализации клиента SDK (Sigma.initializeClient) будет произведена попытка обновления данных о локации через запрос в сеть.

Методы SDK использующие geo

К методам использующие локацию относятся следующие:

  • SigmaClient.checkFlag
  • SigmaClient.getAllUserExperiments
  • SigmaClient.getExperiment
  • SigmaClient.getProperties То есть, при вызове одного из них, произойдет проверка на наличие данных о локации в кэше и при отсутствии будет произведен запрос в сеть. Соответственно, если кэш пуст и запрос провалился, то данные о локации при расчетах в методах SDK не будут использованы.

User Properties Cache

Схема user properties cache

Android cache config schema

Методы SDK редактирующие User Properties

К методам редактирующие свойства пользователя относятся следующие:

  • Sigma.initializeClient
  • SigmaClient.setUserProperties
  • SigmaClient.clearUserProperties
  • SigmaClient.editUserProperties То есть при вызове одного из них будет произведена правка в локальном хранилище.

Примечание: Помимо сохранения значения любого из свойств, записывается и время когда была произведена запись timestamp.

Методы SDK использующие User Properties

К методам использующие свойства пользователя относятся следующие:

  • SigmaClient.checkFlag
  • SigmaClient.getAllUserExperiments
  • SigmaClient.getExperiment
  • SigmaClient.getProperties
к сведению

При запросе свойств пользователя, будет произведена фильтрация на устаревшие сохраненные свойства. Сейчас это только userId который живёт 24 часа.