From 134ad203644d8301262d9783800bf1bac4b81b37 Mon Sep 17 00:00:00 2001 From: Jared Lockhart <119884+jaredlockhart@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:19:16 -0500 Subject: [PATCH] docs: update mobile SDK integration guides to match current source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because * `globalUserParticipation` no longer exists in the SDK — it was split into `experimentParticipation` and `rolloutParticipation` * The `recordedContext` NimbusBuilder option for behavioral targeting and Glean recording is undocumented * `recordMalformedConfiguration()` for reporting invalid feature configs is undocumented * `HardcodedNimbusFeatures` testing helper is undocumented This commit * Replaces `globalUserParticipation` in mobile-ui.md with the two separate participation properties and explains their distinct behavior * Adds `recordedContext` section to both Android and iOS integration guides with cross-link to Recording Targeting Context docs * Adds `recordMalformedConfiguration()` section to Android guide * Adds `HardcodedNimbusFeatures` testing section with usage example and key test assertion methods * Updates complete NimbusBuilder examples in both guides to include `recordedContext` and `featureManifest` * Removes deprecated `customTargetingAttributes` from iOS example Fixes #786 Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/platform-guides/android/integration.md | 51 +++++++++++++++++++++ docs/platform-guides/android/mobile-ui.md | 12 +++-- docs/platform-guides/ios/integration.md | 20 ++++++-- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/docs/platform-guides/android/integration.md b/docs/platform-guides/android/integration.md index bcef14402..b91bf4dee 100644 --- a/docs/platform-guides/android/integration.md +++ b/docs/platform-guides/android/integration.md @@ -220,6 +220,55 @@ Adding the `usePreviewCollection` flag allows the builder to configure a `Nimbus }.build(appInfo) ``` +### Connecting to the Recorded Targeting Context + +The `recordedContext` builder option connects the Nimbus SDK to a `RecordedContext` implementation for behavioral targeting and Glean recording. This replaces the older `customTargetingAttributes` approach for providing targeting attributes. + +```kotlin + return NimbusBuilder(context).apply { + // … + recordedContext = RecordedNimbusContext(isFirstRun = isAppFirstRun) + // … + }.build(appInfo) +``` + +See [Recording Targeting Context](/advanced/recording-targeting-context) for details on implementing the `RecordedContext` trait. + +### Reporting malformed feature configuration + +If your app detects that a feature configuration from an experiment is invalid or malformed, you can report it as telemetry using `recordMalformedConfiguration`: + +```kotlin +FxNimbus.features.myFeature.recordMalformedConfiguration(partId = "invalid-field") +``` + +This sends a `malformedConfiguration` Glean event identifying the feature and the specific part that was invalid. + +## Unit and UI testing with `HardcodedNimbusFeatures` + +The `HardcodedNimbusFeatures` class lets you inject feature configurations directly for unit and UI testing, without a running Nimbus SDK or network connection: + +```kotlin +val hardcodedNimbus = HardcodedNimbusFeatures(testContext, + "my-feature" to JSONObject("""{"enabled": true, "title": "Hello"}""") +) +hardcodedNimbus.connectWith(FxNimbus) + +// Access feature values as normal — they'll use the hardcoded config +val config = FxNimbus.features.myFeature.value() + +// Test assertions +assertTrue(hardcodedNimbus.isExposed("my-feature")) +assertEquals(1, hardcodedNimbus.getExposureCount("my-feature")) +assertFalse(hardcodedNimbus.isMalformed("my-feature")) +``` + +Key test methods: +- `isExposed(featureId)` — whether `recordExposureEvent` was called +- `getExposureCount(featureId)` — number of exposure events recorded +- `isMalformed(featureId)` — whether `recordMalformedConfiguration` was called +- `hasFeature(featureId)` — whether the feature was provided to the constructor + ## A complete `NimbusBuilder` example ```kotlin @@ -232,6 +281,8 @@ Adding the `usePreviewCollection` flag allows the builder to configure a `Nimbus usePreviewCollection = context.settings().nimbusUsePreview isFirstRun = isAppFirstRun sharedPreferences = context.settings().preferences + recordedContext = RecordedNimbusContext(isFirstRun = isAppFirstRun) + featureManifest = FxNimbus // Optional callbacks. onCreateCallback = { nimbus -> // called when nimbus is set up diff --git a/docs/platform-guides/android/mobile-ui.md b/docs/platform-guides/android/mobile-ui.md index f5ce07269..2e76804d0 100644 --- a/docs/platform-guides/android/mobile-ui.md +++ b/docs/platform-guides/android/mobile-ui.md @@ -10,18 +10,24 @@ Required user interface components for apps integrating with the Nimbus SDK. Currently Nimbus provides no user-interface components of its own, though provides API to connect to existing settings screens. -## Global Opt-Out/Opt-In for Experiments +## Opt-Out/Opt-In Controls The settings page should include a `Studies` toggle, which allows users to opt-in or opt-out of experiments. The example from Firefox for iOS is shown: -Toggling the `Studies` flag should set the `Nimbus` value for `globalUserParticipation`: +Experiment participation and rollout participation are controlled separately: ```kotlin -nimbus.globalUserParticipation = flag +// Controls opt-in/out for experiments (not rollouts) +nimbus.experimentParticipation = flag + +// Controls opt-in/out for rollouts (not experiments) +nimbus.rolloutParticipation = flag ``` +When set to `false`, the user will be opted out of all active enrollments of that type and will not be enrolled in new ones. Toggling the `Studies` flag should set `experimentParticipation`. + ## Resetting Telemetry Identifiers During experiment enrollment, telemetry is generated which can connect the user to the experiment enrollment. diff --git a/docs/platform-guides/ios/integration.md b/docs/platform-guides/ios/integration.md index b650142c1..6e563e81a 100644 --- a/docs/platform-guides/ios/integration.md +++ b/docs/platform-guides/ios/integration.md @@ -184,6 +184,20 @@ To connect the `NimbusInterface` object to the command line, we need to feed the .build(appInfo: appInfo) ``` +### Connecting to the Recorded Targeting Context + +The `recordedContext` builder option connects the Nimbus SDK to a `RecordedContext` implementation for behavioral targeting and Glean recording. This replaces the older `customTargetingAttributes` approach for providing targeting attributes. + +```swift + return NimbusBuilder(dbPath: dbPath) + // … + .with(recordedContext: RecordedNimbusContext(isFirstRun: isFirstRun)) + // … + .build(appInfo: appSettings) +``` + +See [Recording Targeting Context](/advanced/recording-targeting-context) for details on implementing the `RecordedContext` protocol. + ## A complete `NimbusBuilder` example ```swift @@ -203,10 +217,7 @@ public static var nimbus: NimbusInterface = { // thinks it is. let appSettings = NimbusAppSettings( appName: "example-app", - channel: "release", - customTargetingAttributes: [ - "is_first_run": isFirstRun, - ] + channel: "release" ) let errorReporter: NimbusErrorReporter = { err in @@ -229,6 +240,7 @@ public static var nimbus: NimbusInterface = { .with(errorReporter: errorReporter) .with(initialExperiments: Bundle.main.url(forResource: "initial_experiments", withExtension: "json")) .isFirstRun(isFirstRun) + .with(recordedContext: RecordedNimbusContext(isFirstRun: isFirstRun)) .with(bundles: bundles) .with(userDefaults: UserDefaults.standard) .with(featureManifest: AppConfig.shared)