Skip to content

Commit 46df6d9

Browse files
authored
Merge pull request #853 from qonversion/kamo/dev-1236-sdk-iosandroid-obvyazki-refetch-rc-posle-identify-i-yavnii
feat: invalidateRemoteConfigsCache() + remote config refetch after same-uid identify (DEV-1236)
2 parents d369165 + e68faea commit 46df6d9

9 files changed

Lines changed: 985 additions & 82 deletions

File tree

sample/src/main/java/io/qonversion/sample/RemoteConfigsFragment.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ class RemoteConfigsFragment : Fragment() {
5757
getRemoteConfig(contextKey.ifEmpty { null })
5858
}
5959

60+
binding.buttonInvalidateRemoteConfigsCache.setOnClickListener {
61+
Qonversion.shared.invalidateRemoteConfigsCache()
62+
Toast.makeText(context, getString(R.string.remote_configs_cache_invalidated), Toast.LENGTH_SHORT).show()
63+
}
64+
6065
binding.buttonAttachExperiment.setOnClickListener {
6166
val experimentId = binding.editExperimentId.text.toString()
6267
val groupId = binding.editGroupId.text.toString()

sample/src/main/res/layout/fragment_remote_configs.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@
115115
app:backgroundTint="@color/colorDark"
116116
app:cornerRadius="8dp" />
117117

118+
<com.google.android.material.button.MaterialButton
119+
android:id="@+id/buttonInvalidateRemoteConfigsCache"
120+
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
121+
android:layout_width="match_parent"
122+
android:layout_height="48dp"
123+
android:layout_marginTop="8dp"
124+
android:text="@string/invalidate_remote_configs_cache"
125+
app:cornerRadius="8dp" />
126+
118127
</LinearLayout>
119128
</androidx.cardview.widget.CardView>
120129

sample/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
<string name="single_remote_config">Single Remote Config</string>
8585
<string name="context_key_optional">Context Key (optional)</string>
8686
<string name="get_remote_config">Get Remote Config</string>
87+
<string name="invalidate_remote_configs_cache">Invalidate Remote Configs Cache</string>
88+
<string name="remote_configs_cache_invalidated">Cache invalidated — the next request fetches a fresh evaluation</string>
8789
<string name="experiments">Experiments</string>
8890
<string name="experiment_id">Experiment ID</string>
8991
<string name="group_id">Group ID</string>

sdk/src/main/java/com/qonversion/android/sdk/Qonversion.kt

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,42 @@ interface Qonversion {
222222
*/
223223
fun remoteConfigList(callback: QonversionRemoteConfigListCallback)
224224

225+
/**
226+
* Invalidates the in-memory cache of remote configs so the next
227+
* [remoteConfig] or [remoteConfigList] call fetches a fresh targeting
228+
* evaluation from the server instead of returning the cached copy.
229+
*
230+
* This method performs no network request itself and has no callback —
231+
* it only marks the cached values as stale. A [remoteConfig] load that is
232+
* already in flight when this method is called is re-issued once, so its
233+
* waiting callbacks receive a fresh evaluation rather than the superseded
234+
* one (if the re-issued request fails, the superseded evaluation is
235+
* delivered instead); an in-flight [remoteConfigList] load completes with
236+
* the evaluation it started with, and any subsequent call fetches fresh
237+
* values.
238+
*
239+
* Call it when the targeting inputs changed and you need the change
240+
* reflected immediately, for example:
241+
* - after setting a batch of user properties via [setUserProperty] or
242+
* [setCustomUserProperty] that your remote config targeting depends on;
243+
* - on returning to the foreground in long-living sessions, if the
244+
* targeting could have changed server-side.
245+
*
246+
* You do NOT need to call it after [identify] — the SDK invalidates the
247+
* cache on identity changes automatically. You also do not need it to
248+
* recover from a locally bundled fallback config — fallbacks are never
249+
* cached, so the next call retries the network automatically. The screens
250+
* shown by No-Code products are not affected by this method.
251+
*
252+
* Call it from the same thread you use for the other Qonversion calls
253+
* (typically the main thread). On Android this method is also safe to
254+
* call from any thread.
255+
*
256+
* @see remoteConfig
257+
* @see remoteConfigList
258+
*/
259+
fun invalidateRemoteConfigsCache()
260+
225261
/**
226262
* This function should be used for the test purposes only. Do not forget to delete the usage of this function before the release.
227263
* Use this function to attach the user to the experiment.
@@ -329,15 +365,23 @@ interface Qonversion {
329365
* Sets Qonversion reserved user properties, like email or user id.
330366
* Note that using [QUserPropertyKey.Custom] here will do nothing.
331367
* To set custom user property, use [setCustomUserProperty] method instead.
368+
* If your remote config targeting depends on this property and you need
369+
* the updated evaluation immediately, call [invalidateRemoteConfigsCache]
370+
* after setting the properties.
332371
* @param key defined enum key that will be transformed to string
333372
* @param value property value
373+
* @see invalidateRemoteConfigsCache
334374
*/
335375
fun setUserProperty(key: QUserPropertyKey, value: String)
336376

337377
/**
338-
* Sets custom user property
378+
* Sets custom user property.
379+
* If your remote config targeting depends on this property and you need
380+
* the updated evaluation immediately, call [invalidateRemoteConfigsCache]
381+
* after setting the properties.
339382
* @param key custom user property key
340383
* @param value property value
384+
* @see invalidateRemoteConfigsCache
341385
*/
342386
fun setCustomUserProperty(key: String, value: String)
343387

sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,16 @@ internal class QProductCenterManager internal constructor(
228228
processingPartnersIdentityId = null
229229

230230
if (currentUserId == qonversionUid) {
231+
// The uid did not change, but the identity did — user
232+
// properties and the external identity are now attached, so
233+
// cached configs may no longer reflect the server-side
234+
// targeting evaluation. Drop them (non-destructively) so the
235+
// next remoteConfig() call refetches; pending requests
236+
// re-issued below fetch fresh as well (DEV-1236 B4).
237+
// Invalidate BEFORE handlePendingRequests: the replay must
238+
// miss the cache, or queued completions would be served the
239+
// pre-identify evaluation.
240+
remoteConfigManager.invalidateRemoteConfigsCache()
231241
handlePendingRequests()
232242
fireIdentitySuccess(identityId)
233243
} else {

0 commit comments

Comments
 (0)