> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pnlight.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote Config

> Получайте типизированные значения PNLight Remote Config в приложениях на Swift, React Native и Flutter с локальными значениями по умолчанию и безопасными резервными значениями.

PNLight Remote Config доставляет типизированные настройки приложения из дашборда в SDK. Используйте его для несекретного поведения во время выполнения: флагов функций, вариантов текстов, лимитов и настроек пейвола.

Remote Config отделён от [Remote UI](/ru/sdk/remote-ui). Remote UI возвращает конфигурации экранов для отображения. Remote Config возвращает типизированные значения, которые приложение читает и применяет в своём коде.

<Warning>
  Не храните секреты в Remote Config. Никогда не помещайте в Remote Config API-ключи, учётные данные, общие секреты и другие чувствительные значения.
</Warning>

## Настройте значения в дашборде

Создайте базовую конфигурацию, добавьте целевые переопределения и опубликуйте черновик в разделе **Remote Config**. Рабочий процесс описан в разделе [Настройка Remote Config в дашборде](/ru/dashboard/remote-config).

Поддерживаемые типы значений верхнего уровня:

* Boolean.
* String.
* Number.
* String array.
* JSON.

Ключи плоские. Если переопределение меняет JSON-значение, оно заменяет значение целиком и не выполняет глубокое слияние вложенных полей.

## Инициализируйте SDK с локальными значениями по умолчанию

Задайте значения по умолчанию, принадлежащие приложению, во время инициализации SDK. Они остаются на устройстве и никогда не отправляются в PNLight. SDK использует их до первого успешного запроса, в офлайне или когда удалённое значение отсутствует либо имеет другой тип.

<CodeGroup>
  ```swift Swift theme={null}
  import PNLightSDK

  let config = PNLightConfig(remoteConfigDefaults: [
      "paywall_enabled": .boolean(false),
      "welcome_title": .string("Welcome"),
      "trial_days": .number(7),
      "enabled_plans": .stringArray(["monthly"]),
      "paywall_style": .jsonObject([
          "accent": .string("#6750A4"),
          "compact": .boolean(false),
      ]),
  ])

  await PNLightSDK.shared.initialize(apiKey: "pnlight_sdk_token", config: config)
  ```

  ```tsx React Native theme={null}
  import { initialize } from "@pnlight/sdk-react-native";

  await initialize("pnlight_sdk_token", undefined, {
    paywall_enabled: false,
    welcome_title: "Welcome",
    trial_days: 7,
    enabled_plans: ["monthly"],
    paywall_style: {
      accent: "#6750A4",
      compact: false,
    },
  });
  ```

  ```dart Flutter theme={null}
  import 'package:pnlight_sdk/pnlight_sdk.dart';

  await PNLightSDK.initialize(
    'pnlight_sdk_token',
    remoteConfigDefaults: {
      'paywall_enabled': false,
      'welcome_title': 'Welcome',
      'trial_days': 7,
      'enabled_plans': ['monthly'],
      'paywall_style': {
        'accent': '#6750A4',
        'compact': false,
      },
    },
  );
  ```
</CodeGroup>

## Получите и активируйте конфигурацию

Вызовите `fetchAndActivate` после инициализации, когда приложение готово обновить Remote Config.

По умолчанию SDK:

* Кратко ожидает атрибуцию AppsFlyer, чтобы PNLight мог применить переопределения на основе атрибуции.
* Ограничивает успешные запросы интервалом 15 минут.
* Сохраняет активную конфигурацию для токена SDK и пользователя PNLight.
* Сохраняет ранее активную конфигурацию, если запрос не удался.

Используйте немедленный запрос только для разработки, QA или запуска, который не должен ждать атрибуцию.

<CodeGroup>
  ```swift Swift theme={null}
  let result = await PNLightSDK.shared.fetchAndActivate()

  switch result {
  case .activated, .notModified:
      break
  case .throttled:
      break
  case .failed:
      break
  }

  let immediateResult = await PNLightSDK.shared.fetchAndActivate(
      minimumFetchInterval: 0,
      waitAttribution: false
  )
  ```

  ```tsx React Native theme={null}
  import { fetchAndActivate } from "@pnlight/sdk-react-native";

  try {
    const result = await fetchAndActivate();
    // "activated", "notModified" или "throttled"
    console.log("Remote Config fetch:", result);
  } catch (error) {
    // Ранее активные значения и локальные значения по умолчанию остаются доступны.
    console.warn("Remote Config unavailable", error);
  }

  await fetchAndActivate(0, false);
  ```

  ```dart Flutter theme={null}
  final result = await PNLightSDK.fetchAndActivate();

  switch (result) {
    case RemoteConfigFetchResult.activated:
    case RemoteConfigFetchResult.notModified:
      break;
    case RemoteConfigFetchResult.throttled:
      break;
    case RemoteConfigFetchResult.failed:
      break;
  }

  await PNLightSDK.fetchAndActivate(
    minimumFetchInterval: Duration.zero,
    waitAttribution: false,
  );
  ```
</CodeGroup>

## Читайте типизированные значения

Используйте типизированные геттеры с резервными значениями. Если ключ отсутствует или активное значение имеет другой тип, SDK возвращает резервное значение.

<CodeGroup>
  ```swift Swift theme={null}
  let paywallEnabled = PNLightSDK.shared.remoteConfigBoolean(
      forKey: "paywall_enabled",
      fallback: false
  )
  let title = PNLightSDK.shared.remoteConfigString(
      forKey: "welcome_title",
      fallback: "Welcome"
  )
  let trialDays = PNLightSDK.shared.remoteConfigNumber(
      forKey: "trial_days",
      fallback: 7
  )
  let plans = PNLightSDK.shared.remoteConfigStringArray(
      forKey: "enabled_plans",
      fallback: ["monthly"]
  )
  let style = PNLightSDK.shared.remoteConfigJSONObject(
      forKey: "paywall_style",
      fallback: ["accent": .string("#6750A4")]
  )
  ```

  ```tsx React Native theme={null}
  import {
    getRemoteConfigBoolean,
    getRemoteConfigJSONObject,
    getRemoteConfigNumber,
    getRemoteConfigString,
    getRemoteConfigStringArray,
  } from "@pnlight/sdk-react-native";

  const paywallEnabled = await getRemoteConfigBoolean("paywall_enabled", false);
  const title = await getRemoteConfigString("welcome_title", "Welcome");
  const trialDays = await getRemoteConfigNumber("trial_days", 7);
  const plans = await getRemoteConfigStringArray("enabled_plans", ["monthly"]);
  const style = await getRemoteConfigJSONObject("paywall_style", {
    accent: "#6750A4",
  });
  ```

  ```dart Flutter theme={null}
  final paywallEnabled = await PNLightSDK.remoteConfigBoolean(
    'paywall_enabled',
    fallback: false,
  );
  final title = await PNLightSDK.remoteConfigString(
    'welcome_title',
    fallback: 'Welcome',
  );
  final trialDays = await PNLightSDK.remoteConfigNumber(
    'trial_days',
    fallback: 7,
  );
  final plans = await PNLightSDK.remoteConfigStringArray(
    'enabled_plans',
    fallback: ['monthly'],
  );
  final style = await PNLightSDK.remoteConfigJSONObject(
    'paywall_style',
    fallback: {'accent': '#6750A4'},
  );
  ```
</CodeGroup>

## Рекомендации

* Храните критичные для приложения значения по умолчанию в приложении, чтобы первый запуск и офлайн-сессии работали.
* Читайте Remote Config через типизированные геттеры, а не через приведение сырого JSON.
* Используйте `minimumFetchInterval: 0` только в разработке или QA.
* Запрашивайте конфигурацию после передачи атрибуции, если важны переопределения для конкретных кампаний.
* Согласуйте имена ключей и типы значений между владельцами дашборда и разработчиками приложения перед публикацией.
