# Feature flags dans le SDK iOS

`Pushwoosh.configure.featureFlags` fournit à votre application iOS les [feature flags](/fr/product/audience-data-and-segmentation/feature-flags/) configurés pour l'application dans le Control Panel. Pushwoosh évalue les règles du flag sur le serveur pour l'appareil et l'utilisateur actuels, et le SDK renvoie le résultat : si le flag est activé pour cet appareil et quelles valeurs de propriétés s'appliquent.

<Aside type="tip" title="Fonctionnalité bêta">
Les feature flags sont en bêta et disponibles uniquement avec les forfaits qui les incluent. Avec les autres forfaits, le serveur ne renvoie aucun flag, de sorte que chaque flag se rabat sur la valeur par défaut que vous transmettez dans le code.
</Aside>

## Prérequis

* Pushwoosh iOS SDK 7.2.10 ou version ultérieure, intégré comme décrit dans l'[Aperçu du SDK iOS](/fr/developer/pushwoosh-sdk/ios-sdk/). Les feature flags sont fournis dans les modules obligatoires `PushwooshFramework` et `PushwooshCore` : vous n'avez donc pas à ajouter d'autre module. Ils fonctionnent dans l'application iOS elle-même. Les extensions d'application, comme une Notification Service Extension, ne demandent jamais de flags.
* Au moins un flag créé dans **Audience** → **Feature Flags**. Vous avez besoin de sa **Key** ainsi que des clés et des types de ses propriétés. Utilisez les clés exactement telles qu'elles y apparaissent, casse comprise. Par exemple, `get("New_Checkout")` ne trouve pas un flag dont la clé est `new_checkout`.
* Si l'application envoie les requêtes du SDK via un proxy inverse, son URL doit se terminer par `json/1.3/`. Sinon, le SDK ne demande pas de flags et chaque flag se rabat sur votre valeur par défaut.

## Lire un flag

Transmettez toujours une valeur par défaut. Elle s'applique tant que le SDK n'a pas de flags pour l'appareil, ainsi que chaque fois que le flag n'existe pas, est archivé ou que le forfait n'inclut pas les feature flags.

```swift
import PushwooshFramework

let flags = Pushwoosh.configure.featureFlags

if let checkout = flags.get("new_checkout"), checkout.isEnabled {
    showNewCheckout(
        buttonColor: checkout.string(forProperty: "button_color", default: "blue") ?? "blue",
        maxItems: Int(checkout.number(forProperty: "max_items", default: 3))
    )
} else {
    showOldCheckout()
}
```

Pour vérifier uniquement si le flag est activé, utilisez `isEnabled` :

```swift
let isNewCheckout = Pushwoosh.configure.featureFlags.isEnabled("new_checkout", default: false)
```

En Objective-C, appelez `[PushwooshConfig featureFlags]`.

## Ce que renvoie un flag

`get(_:)` renvoie un objet `PWFeatureFlag`, ou `nil` lorsque le SDK n'a pas encore de flags pour l'appareil ou que le flag ne figure pas dans la réponse. Un flag archivé ne figure pas dans la réponse. `get` lit uniquement les flags stockés et n'attend jamais le réseau. L'objet possède les propriétés suivantes :

| Propriété | Type | Description |
| :---- | :---- | :---- |
| `key` | String | La clé du flag. |
| `isEnabled` | Bool | Indique si le flag est activé pour cet appareil. |
| `ruleId` | String | La règle qui a déterminé le résultat, par exemple `r_1a2b3c4d`. `default` lorsqu'aucune règle ne correspond à l'appareil, et une chaîne vide lorsque le flag est coupé (killed). |

Lisez les valeurs des propriétés avec la méthode qui correspond au type de la propriété. Lorsque le flag est désactivé, les propriétés contiennent les valeurs par défaut définies dans le Control Panel.

| Méthode | Renvoie |
| :---- | :---- |
| `string(forProperty:default:)` | La valeur d'une propriété **String**, ou votre valeur par défaut. |
| `number(forProperty:default:)` | La valeur d'une propriété **Number** sous forme de `Double`, ou votre valeur par défaut. |
| `bool(forProperty:default:)` | La valeur d'une propriété **Boolean**, ou votre valeur par défaut. |
| `jsonObject(forProperty:)` | La valeur d'une propriété **JSON** contenant un objet, sous forme de dictionnaire, ou `nil`. |
| `jsonArray(forProperty:)` | La valeur d'une propriété **JSON** contenant un tableau, ou `nil`. |

Chaque méthode renvoie votre valeur par défaut, ou `nil` pour les méthodes JSON, lorsque la propriété est absente ou contient une valeur d'un autre type.

`isEnabled(_:default:)` renvoie la valeur par défaut lorsque `get(_:)` renvoie `nil`.

<span id="keep-flags-up-to-date" />

## Maintenir les flags à jour

Le SDK stocke la dernière réponse sur l'appareil pendant 24 heures au maximum. Les flags stockés ne sont valides que pour le User ID et l'Application Code de l'application pour lesquels ils ont été demandés. Le SDK les actualise :

* au début d'une session, c'est-à-dire lorsque l'application devient active pour la première fois ou après au moins 30 minutes en arrière-plan ;
* toutes les heures tant que l'application est au premier plan ;
* après l'enregistrement de l'appareil aux notifications push, si la requête précédente a été envoyée avant l'enregistrement ;
* juste après le changement du User ID avec `setUserId`. Les flags stockés de l'utilisateur précédent sont supprimés, de sorte qu'un nouvel utilisateur ne les voit jamais.

Pour réagir aux nouvelles valeurs, ajoutez un listener conforme à `PWFeatureFlagsUpdateListener`. Sa méthode `featureFlagsDidUpdate()` est appelée sur le thread principal après une actualisation qui a modifié un flag. Le SDK conserve les listeners par référence faible. Gardez une référence forte au vôtre, sinon il est libéré et n'est jamais appelé :

```swift
final class CheckoutViewController: UIViewController, PWFeatureFlagsUpdateListener {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        Pushwoosh.configure.featureFlags.addUpdateListener(self)
    }

    override func viewWillDisappear(_ animated: Bool) {
        Pushwoosh.configure.featureFlags.removeUpdateListener(self)
        super.viewWillDisappear(animated)
    }

    func featureFlagsDidUpdate() {
        render()
    }
}
```

Pour demander les flags vous-même, par exemple après une action susceptible de faire passer l'utilisateur dans un autre segment, appelez `refresh(completion:)`. Tant que les flags stockés sont valides, la méthode envoie au plus une requête toutes les 5 minutes et, dans cet intervalle, répond à partir des flags stockés. La completion s'exécute sur le thread principal :

```swift
Pushwoosh.configure.featureFlags.refresh { error in
    if let error = error as NSError? {
        let status = error.code
        // the stored flags, or your defaults, stay in effect
    }
    render()
}
```

En cas d'échec, l'erreur appartient au domaine `PWFeatureFlagsErrorDomain` et son `code` est le statut HTTP. Le code vaut `0` lorsque la requête n'a reçu aucune réponse HTTP ou n'a pas été envoyée, et `200` lorsque le serveur a répondu mais que la réponse n'a pas pu être utilisée.

Pour tester les actualisations sans la limite de 5 minutes, définissez la clé Boolean `Pushwoosh_FEATURE_FLAGS_DISABLE_THROTTLE` dans `Info.plist` sur `YES`.

Si Pushwoosh ne parvient pas à déterminer à temps les segments de l'appareil, il renvoie une réponse partielle. Le SDK ne la stocke pas sur l'appareil, et l'actualisation suivante apporte la réponse complète.

Lorsqu'un flag est coupé (kill) dans le Control Panel, les appareils le reçoivent désactivé, avec les valeurs de propriétés par défaut, lors de l'actualisation suivante. Lorsque le SDK ne peut pas joindre le serveur, il continue d'utiliser les flags stockés jusqu'à ce qu'ils aient 24 heures, puis vos valeurs par défaut.

<span id="log-impressions" />

## Enregistrer les impressions

Une impression indique à Pushwoosh qu'un utilisateur a réellement atteint le code contrôlé par un flag, afin que vous puissiez comparer les utilisateurs qui ont reçu la fonctionnalité à ceux qui ne l'ont pas reçue. Appelez `logImpression(_:)` au moment où l'utilisateur voit la fonctionnalité ou son ancienne version, dans la branche activée comme dans la branche désactivée, car les utilisateurs dont le flag est désactivé constituent votre groupe de comparaison :

```swift
let flags = Pushwoosh.configure.featureFlags
let isOn = flags.isEnabled("new_checkout", default: false)
flags.logImpression("new_checkout")
if isOn {
    showNewCheckout()
} else {
    showOldCheckout()
}
```

Le SDK envoie l'événement `PW_FeatureFlagImpression` avec les attributs suivants :

| Attribut | Type | Valeur |
| :---- | :---- | :---- |
| `flag_key` | string | La clé du flag. |
| `rule_id` | string | La règle qui a déterminé le résultat, comme dans `ruleId`. |
| `enabled` | boolean | Indique si le flag était activé. |

Vous n'avez pas besoin de créer l'événement à l'avance, car Pushwoosh ajoute `PW_FeatureFlagImpression` avec ces attributs à **Audience** → **Events** à l'arrivée de la première impression. Le SDK envoie une impression par flag, règle et état au cours d'une session, et n'envoie rien lorsqu'il n'y a pas de flag pour la clé. Si l'envoi échoue, le prochain appel à `logImpression` pour ce flag la renvoie.

Les impressions permettent aussi aux équipes marketing de créer un segment des utilisateurs qui ont atteint la fonctionnalité : l'état **a vu la fonctionnalité (30 jours)** de la [condition de feature flag](/fr/product/audience-data-and-segmentation/feature-flags/#find-users-who-reached-a-feature).

## Référence des méthodes

`Pushwoosh.configure.featureFlags` possède les méthodes suivantes :

| Méthode | Description |
| :---- | :---- |
| `get(_:)` | Renvoie le `PWFeatureFlag` de la clé, ou `nil`. Lit uniquement les flags stockés. |
| `isEnabled(_:default:)` | Indique si le flag est activé, ou renvoie la valeur par défaut lorsqu'il n'y a pas de flag. |
| `refresh(completion:)` | Demande les flags, limité à une fois toutes les 5 minutes tant que les flags stockés sont valides. La completion reçoit `nil` ou une erreur dans `PWFeatureFlagsErrorDomain`, et peut être `nil`. |
| `addUpdateListener(_:)` | Appelle la méthode `featureFlagsDidUpdate()` du listener après chaque actualisation qui a modifié un flag. Le listener est conservé par référence faible. |
| `removeUpdateListener(_:)` | Supprime un listener ajouté avec `addUpdateListener(_:)`. |
| `logImpression(_:)` | Envoie un événement `PW_FeatureFlagImpression` pour la règle et l'état actuels du flag. |