diff --git a/docs/readme.md b/docs/readme.md index b4955cc8b..d26714fcc 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -113,6 +113,7 @@ Release Notes - Changes - Messaging: Added new Registration methods using Installation Ids. Deprecated old Token based methods. + - Remote Config: Add support for setting Custom Signals. ### 13.15.0 - Changes diff --git a/remote_config/src/FirebaseRemoteConfig.cs b/remote_config/src/FirebaseRemoteConfig.cs index d70d18161..7ffc5165c 100644 --- a/remote_config/src/FirebaseRemoteConfig.cs +++ b/remote_config/src/FirebaseRemoteConfig.cs @@ -252,6 +252,36 @@ public Task SetDefaultsAsync(IDictionary defaults) { RemoteConfigUtil.ConvertDictionaryToMap(defaults)); } + /// @brief Sets the custom signals values based on the input dictionary. + /// + /// @note This upserts the custom signals, i.e., inserts a new signal if none exists + /// or updates the signal if it does. + /// + /// @param customSignals IDictionary of string keys to object values, representing the + /// set of custom signals to apply. Supported value types are string, long (and integer types), + /// double (and float types), or null to remove a signal. + /// If the same key is specified multiple times, the value associated with the last + /// duplicate key is applied. + /// + /// @return A Task which can be used to determine when the operation is + /// complete. + public Task SetCustomSignalsAsync(IDictionary customSignals) { + ThrowIfNull(); + if (customSignals == null) { + throw new System.ArgumentNullException(nameof(customSignals)); + } + using StringList signalKeys = new StringList(); + using VariantList signalValues = new VariantList(); + foreach (KeyValuePair pair in customSignals) { + if (pair.Key == null) { + throw new System.ArgumentException("Key cannot be null", nameof(customSignals)); + } + signalKeys.Add(pair.Key); + signalValues.Add(Variant.FromObject(pair.Value)); + } + return remoteConfigInternal.SetCustomSignalsInternalAsync(signalKeys, signalValues); + } + /// @brief Asynchronously changes the settings for this Remote Config /// instance. /// diff --git a/remote_config/src/swig/remote_config.i b/remote_config/src/swig/remote_config.i index 4d1880e09..a6a433250 100644 --- a/remote_config/src/swig/remote_config.i +++ b/remote_config/src/swig/remote_config.i @@ -37,6 +37,7 @@ #include #include "app/src/callback.h" #include "app/src/cpp_instance_manager.h" +#include "app/src/log.h" #include "remote_config/src/include/firebase/remote_config.h" namespace firebase { @@ -135,6 +136,7 @@ void SetConfigUpdateCallback(RemoteConfig* rc, firebase::remote_config::ConfigUp %ignore firebase::remote_config::RemoteConfig::GetInstance; %ignore firebase::remote_config::RemoteConfig::SetDefaults; +%ignore firebase::remote_config::RemoteConfig::SetCustomSignals; // Ignore the various Get, as GetValue is used instead. %ignore firebase::remote_config::RemoteConfig::GetBoolean; %ignore firebase::remote_config::RemoteConfig::GetLong; @@ -280,6 +282,22 @@ void SetConfigUpdateCallback(firebase::remote_config::RemoteConfig* rc, delete[] default_array; return future_result; } + + Future SetCustomSignalsInternal( + std::vector keys, + std::vector values) { + if (keys.size() != values.size()) { + firebase::LogError( + "SetCustomSignalsInternal given different list sizes (%zu, %zu)", + keys.size(), values.size()); + return firebase::Future(); + } + std::map custom_signals; + for (size_t i = 0; i < keys.size(); ++i) { + custom_signals[keys[i]] = values[i]; + } + return self->SetCustomSignals(custom_signals); + } } // 314: Ignore warnings about the internal namespace being renamed to diff --git a/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandler.cs b/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandler.cs index 2fec7aa95..3675a2ba1 100644 --- a/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandler.cs +++ b/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandler.cs @@ -192,7 +192,23 @@ void FetchComplete(Task fetchTask) { } } - + public Task SetCustomSignalsAsync() { + DebugLog("Setting custom signals..."); + var customSignals = new System.Collections.Generic.Dictionary { + { "item_id", "sword_123" }, + { "player_level", 42 }, + { "item_rating", 4.5 } + }; + return Firebase.RemoteConfig.FirebaseRemoteConfig.DefaultInstance + .SetCustomSignalsAsync(customSignals) + .ContinueWithOnMainThread(task => { + if (task.IsFaulted) { + DebugLog("Failed to set custom signals: " + task.Exception); + } else { + DebugLog("Custom signals set successfully!"); + } + }); + } // Output text to the debug log text field, as well as the console. public void DebugLog(string s) { @@ -234,6 +250,9 @@ void GUIDisplayControls() { if (GUILayout.Button("Display All Keys")) { DisplayAllKeys(); } + if (GUILayout.Button("Set Custom Signals")) { + SetCustomSignalsAsync(); + } if (GUILayout.Button("Fetch Remote Data")) { FetchDataAsync(); } diff --git a/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandlerAutomated.cs b/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandlerAutomated.cs index 48da93be4..9f4653e89 100644 --- a/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandlerAutomated.cs +++ b/remote_config/testapp/Assets/Firebase/Sample/RemoteConfig/UIHandlerAutomated.cs @@ -23,6 +23,7 @@ protected override void Start() { TestAddAndRemoveConfigUpdateListener, #endif // !(UNITY_IOS || UNITY_TVOS || UNITY_ANDROID) || UNITY_EDITOR TestFetchData, + TestSetCustomSignals, }; testRunner = AutomatedTestRunner.CreateTestRunner( testsToRun: tests, @@ -160,5 +161,30 @@ Task TestFetchData() { FirebaseRemoteConfig.DefaultInstance.GetValue("config_test_bool").BooleanValue); }); } + + async Task TestSetCustomSignals() { + var signals = new System.Collections.Generic.Dictionary { + { "test_string", "alpha" }, + { "test_int", 42 }, + { "test_double", 3.14 } + }; + await FirebaseRemoteConfig.DefaultInstance.SetCustomSignalsAsync(signals); + + // After setting the Custom Signal, fetch to get the signal data + await FirebaseRemoteConfig.DefaultInstance.FetchAsync(TimeSpan.Zero); + await FirebaseRemoteConfig.DefaultInstance.ActivateAsync(); + + // Because of caching, this isn't the most reliable test, so just print out the value. + DebugLog("Check custom value: " + + FirebaseRemoteConfig.DefaultInstance.GetValue("config_test_with_custom_signal").StringValue); + + // Set the custom signals back to null, to clear them out. + var signals2 = new System.Collections.Generic.Dictionary { + { "test_string", null }, + { "test_int", null }, + { "test_double", null } + }; + await FirebaseRemoteConfig.DefaultInstance.SetCustomSignalsAsync(signals2); + } } }