Skip to content

feat(remote-config): add RemoteConfigManager#7067

Open
rickvdl wants to merge 15 commits into
mainfrom
rickvdl/remote-config-manager-config-cache
Open

feat(remote-config): add RemoteConfigManager#7067
rickvdl wants to merge 15 commits into
mainfrom
rickvdl/remote-config-manager-config-cache

Conversation

@rickvdl

@rickvdl rickvdl commented Jun 22, 2026

Copy link
Copy Markdown
Member

Part of a stack of PRs, builds on #7076 and should be aligned with the Android equivalent in RevenueCat/purchases-android#3612.

Description

  • Introduces the RemoteConfigManager, which is responsible for refreshing the latest config using the RemoteConfigAPI.
  • Will use the persistence layer for storing the latest PersistedRemoteConfiguration
  • This data will be included with subsequent requests to the remote config API, allowing the backend to return just the diff of what to sync

Downloading / storing the topics payloads itself will be done in a follow up PR.


Note

Medium Risk
Introduces a new remote-config refresh and disk persistence path that will affect SDK configuration once wired, but failures preserve cached state and the manager is not yet integrated into the main SDK flow.

Overview
Adds RemoteConfigManager to orchestrate remote config refresh: it reads PersistedRemoteConfiguration from disk, builds a RemoteConfigRequest (domain, manifest, prefetched blobs), calls the API once at a time, and on success decodes the container config and writes updated manifest, active topics, prefetch blobs, and merged topic blob refs (pruning inactive topics).

RemoteConfigAPI is abstracted behind RemoteConfigAPIType for testability. Parse and network failures log via new RemoteConfigStrings cases and leave the existing cache unchanged; 204/no content also skips writes.

Unit tests cover first vs subsequent requests, in-flight deduplication, persistence/merge behavior, and error paths. SDK lifecycle wiring and blob download are explicitly deferred.

Reviewed by Cursor Bugbot for commit 59f7d0a. Bugbot is set up for automated code reviews on this repo. Configure here.

@emerge-tools

emerge-tools Bot commented Jun 22, 2026

Copy link
Copy Markdown

4 builds increased size

Name Version Download Change Install Change Approval
RevenueCat
com.revenuecat.PaywallsTester
1.0 (1) 18.9 MB ⬆️ 46.0 kB (0.24%) 68.5 MB ⬆️ 170.4 kB (0.25%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.local-source
1.0 (1) 4.4 MB ⬆️ 6.1 kB (0.14%) 13.2 MB ⬆️ 19.5 kB (0.15%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.cocoapods
1.0 (1) 6.6 MB ⬆️ 13.4 kB (0.2%) 28.9 MB ⬆️ 40.3 kB (0.14%) ⏳ Needs approval
BinarySizeTest
com.revenuecat.binary-size-test.spm
1.0 (1) 4.5 MB ⬆️ 5.1 kB (0.11%) 11.5 MB ⬆️ 19.7 kB (0.17%) N/A

RevenueCat 1.0 (1)
com.revenuecat.PaywallsTester

⚖️ Compare build
⏱️ Analyze build performance

Total install size change: ⬆️ 170.4 kB (0.25%)
Total download size change: ⬆️ 46.0 kB (0.24%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 50.3 kB
DYLD.Exports ⬆️ 4.1 kB
Code Signature ⬆️ 3.8 kB
📝 RCWebPurchaseRedemption.init ⬆️ 2.9 kB
RCWebPurchaseRedemption.Objc Metadata ⬇️ -2.9 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.local-source

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 19.5 kB (0.15%)
Total download size change: ⬆️ 6.1 kB (0.14%)

Largest size changes

Item Install Size Change
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 7.9 kB
📝 RevenueCat.RCContainer.ElementParser.checksumString(in) ⬆️ 1.5 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
DYLD.String Table ⬆️ 1.3 kB
📝 RevenueCat.RCContainer.ElementParser.base64URLString(in) ⬆️ 1.2 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.cocoapods

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 40.3 kB (0.14%)
Total download size change: ⬆️ 13.4 kB (0.2%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 11.4 kB
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 7.9 kB
📝 RevenueCat.RCContainer.ElementParser.checksumString(in) ⬆️ 1.5 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
📝 RevenueCat.RCContainer.ElementParser.base64URLString(in) ⬆️ 1.2 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.spm

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 19.7 kB (0.17%)
Total download size change: ⬆️ 5.1 kB (0.11%)

Largest size changes

Item Install Size Change
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 7.9 kB
📝 RevenueCat.RCContainer.ElementParser.checksumString(in) ⬆️ 1.5 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
📝 RevenueCat.RCContainer.ElementParser.base64URLString(in) ⬆️ 1.2 kB
🗑 RevenueCat.RCContainer.Parser.base64URLString(in) ⬇️ -1.2 kB
View Treemap

Image of diff


🛸 Powered by Emerge Tools

Comment trigger: Size diff threshold of 100.00kB exceeded

@rickvdl rickvdl changed the title feat(remote-config): add manager config cache feat(remote-config): add RemoteConfigManager + manifest cache Jun 22, 2026
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch 2 times, most recently from 3df4088 to 1f95120 Compare June 22, 2026 15:09
@rickvdl

rickvdl commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

@RCGitBot please test

Comment thread Sources/Networking/RemoteConfigDiskCache.swift Outdated
@rickvdl

rickvdl commented Jun 23, 2026

Copy link
Copy Markdown
Member Author

@RCGitBot please test run-test-ios-15-and-14

@github-actions

Copy link
Copy Markdown

🚀 Triggered run-test-ios-15-and-14Pipeline #39787

@rickvdl

rickvdl commented Jun 23, 2026

Copy link
Copy Markdown
Member Author

@rickvdl rickvdl marked this pull request as ready for review June 23, 2026 13:50
@rickvdl rickvdl requested a review from a team as a code owner June 23, 2026 13:50
Comment thread Sources/Networking/RemoteConfigManager.swift
Comment thread Sources/Networking/RemoteConfigManager.swift
Comment thread Sources/Networking/RemoteConfigManager.swift
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from 989bde7 to 96e80a7 Compare June 23, 2026 14:09
Comment thread Sources/Networking/RemoteConfigDiskCache.swift

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small differences with Android, but in general, I do think it all makes sense! And as we discussed, we can iterate in follow-ups If needed.

Comment thread Sources/Networking/RemoteConfigManager.swift
Comment thread Sources/Networking/RemoteConfigManager.swift
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from 96e80a7 to d313b32 Compare June 23, 2026 14:23
@rickvdl rickvdl changed the title feat(remote-config): add RemoteConfigManager + manifest cache feat(remote-config): add RemoteConfigManager + manifest storage Jun 24, 2026
@rickvdl rickvdl changed the title feat(remote-config): add RemoteConfigManager + manifest storage feat(remote-config): add RemoteConfigManager + manifest persistence Jun 24, 2026
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from d676892 to 55b2419 Compare June 24, 2026 10:06
@rickvdl rickvdl changed the title feat(remote-config): add RemoteConfigManager + manifest persistence feat(remote-config): add RemoteConfigManager Jun 24, 2026
@rickvdl rickvdl changed the base branch from rickvdl/remote-config-rc-container-signing to rickvdl/remote-config-manifest-cache June 24, 2026 10:06
@rickvdl rickvdl marked this pull request as draft June 24, 2026 10:07
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manifest-cache branch 3 times, most recently from caff100 to 25ac068 Compare June 25, 2026 14:46
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from 572b0f3 to 12f8722 Compare June 25, 2026 14:53
@RevenueCat-Danger-Bot

RevenueCat-Danger-Bot commented Jun 25, 2026

Copy link
Copy Markdown

❌ CI Job Failed — run-test-ios-26

View Build

@rickvdl rickvdl changed the base branch from rickvdl/remote-config-manifest-cache to main June 25, 2026 15:09
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from 12f8722 to e37560b Compare June 25, 2026 15:10
@rickvdl rickvdl changed the base branch from main to rickvdl/remote-config-manifest-cache June 25, 2026 15:14
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from e37560b to f7ef32f Compare June 25, 2026 15:14
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manifest-cache branch from 25ac068 to 97e93b7 Compare June 25, 2026 15:16
@rickvdl rickvdl force-pushed the rickvdl/remote-config-manager-config-cache branch from f7ef32f to e8b227e Compare June 25, 2026 15:27
case let .success(.container(container, _)):
self.persist(container: container, previous: persisted)
case .success(.noContent):
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

204 refresh skips lastRefreshAt

Medium Severity

A successful noContent (204) refresh leaves disk cache unchanged and never updates lastRefreshAt, even though the server confirmed the config is current. Only container responses set lastRefreshAt in persist, so successful syncs that return no body look stale to any logic keyed off last refresh time.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e8b227e. Configure here.

Base automatically changed from rickvdl/remote-config-manifest-cache to main June 25, 2026 15:50
…-manager-config-cache

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
#	Sources/Logging/Strings/RemoteConfigStrings.swift
@RevenueCat-Danger-Bot

Copy link
Copy Markdown

❌ CI Job Failed — lint

View Build

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 59f7d0a. Configure here.

case let .success(.container(container, _)):
self.persist(container: container, previous: persisted)
case .success(.noContent):
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Success cases mismatch fetch result

High Severity

The refresh completion handler pattern-matches Result success as .container and .noContent, but RemoteConfigFetchResult is still a struct with an optional container produced by GetRemoteConfigOperation. This commit does not align those shapes, so wiring the manager to the real API will not handle 204 vs container responses correctly without further changes.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 59f7d0a. Configure here.

) -> [String: [String]] {
return previous
.merging(response.topics.topicBlobRefs) { _, changed in changed }
.filter { topic, _ in response.activeTopics.contains(topic) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Topics lacks topicBlobRefs member

High Severity

mergedTopicBlobRefs reads response.topics.topicBlobRefs, but RemoteConfiguration.Topics only exposes entries and this commit does not add topicBlobRefs. The merge and persistence path therefore depend on an API that is not present alongside the manager.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 59f7d0a. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants