Skip to content

Commit 4e83788

Browse files
authored
feat(remote-config): add setCustomSignals(...) method (#1010)
1 parent a33205b commit 4e83788

8 files changed

Lines changed: 172 additions & 1 deletion

File tree

.changeset/eight-jokes-repeat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@capacitor-firebase/remote-config': minor
3+
---
4+
5+
feat: add `setCustomSignals(...)` method

packages/remote-config/README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ The following starter templates are available:
103103

104104
## Usage
105105

106-
The following examples show how to fetch and activate the configuration, read configuration values, configure the fetch behavior, and listen for configuration updates in real time.
106+
The following examples show how to fetch and activate the configuration, read configuration values, configure the fetch behavior, set custom signals, and listen for configuration updates in real time.
107107

108108
### Fetch and activate the configuration
109109

@@ -171,6 +171,23 @@ const setSettings = async () => {
171171
};
172172
```
173173

174+
### Set custom signals
175+
176+
Set custom signals for the app instance that can be used for targeting in Remote Config conditions. Signals with a `null` value will be removed:
177+
178+
```typescript
179+
import { FirebaseRemoteConfig } from '@capacitor-firebase/remote-config';
180+
181+
const setCustomSignals = async () => {
182+
await FirebaseRemoteConfig.setCustomSignals({
183+
customSignals: {
184+
city: 'Berlin',
185+
preferred_event_category: 'concerts',
186+
},
187+
});
188+
};
189+
```
190+
174191
### Listen for configuration updates in real time
175192

176193
Add a listener for the config update event to be notified as soon as parameter values change. Only available on Android and iOS:
@@ -223,6 +240,7 @@ const removeAllListeners = async () => {
223240
* [`getAll()`](#getall)
224241
* [`getInfo()`](#getinfo)
225242
* [`setMinimumFetchInterval(...)`](#setminimumfetchinterval)
243+
* [`setCustomSignals(...)`](#setcustomsignals)
226244
* [`setDefaults(...)`](#setdefaults)
227245
* [`setSettings(...)`](#setsettings)
228246
* [`addConfigUpdateListener(...)`](#addconfigupdatelistener)
@@ -386,6 +404,23 @@ Only available for Web.
386404
--------------------
387405

388406

407+
### setCustomSignals(...)
408+
409+
```typescript
410+
setCustomSignals(options: SetCustomSignalsOptions) => Promise<void>
411+
```
412+
413+
Set custom signals for the app instance that can be used for targeting in Remote Config conditions.
414+
415+
| Param | Type |
416+
| ------------- | --------------------------------------------------------------------------- |
417+
| **`options`** | <code><a href="#setcustomsignalsoptions">SetCustomSignalsOptions</a></code> |
418+
419+
**Since:** 8.4.0
420+
421+
--------------------
422+
423+
389424
### setDefaults(...)
390425

391426
```typescript
@@ -546,6 +581,13 @@ Remove all listeners for this plugin.
546581
| **`minimumFetchIntervalInSeconds`** | <code>number</code> | Define the maximum age in seconds of an entry in the config cache before it is considered stale. During development, it's recommended to set a relatively low minimum fetch interval. | <code>43200</code> | 1.3.0 |
547582

548583

584+
#### SetCustomSignalsOptions
585+
586+
| Prop | Type | Description | Since |
587+
| ------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ----- |
588+
| **`customSignals`** | <code>Record&lt;string, string \| number \| null&gt;</code> | The custom signals to set for the app instance. Signals with a `null` value will be removed. | 8.4.0 |
589+
590+
549591
#### SetDefaultsOptions
550592

551593
| Prop | Type | Description | Since |

packages/remote-config/android/src/main/java/io/capawesome/capacitorjs/plugins/firebase/remoteconfig/FirebaseRemoteConfig.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.google.firebase.remoteconfig.ConfigUpdate;
1010
import com.google.firebase.remoteconfig.ConfigUpdateListener;
1111
import com.google.firebase.remoteconfig.ConfigUpdateListenerRegistration;
12+
import com.google.firebase.remoteconfig.CustomSignals;
1213
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException;
1314
import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo;
1415
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
@@ -20,6 +21,7 @@
2021
import java.util.HashMap;
2122
import java.util.Map;
2223
import java.util.Set;
24+
import org.json.JSONObject;
2325

2426
public class FirebaseRemoteConfig {
2527

@@ -93,6 +95,26 @@ public GetInfoResult getInfo() {
9395
return new GetInfoResult(lastFetchTime, lastFetchStatus);
9496
}
9597

98+
public Task<Void> setCustomSignals(@NonNull Map<String, Object> customSignals) {
99+
CustomSignals.Builder builder = new CustomSignals.Builder();
100+
for (Map.Entry<String, Object> entry : customSignals.entrySet()) {
101+
String key = entry.getKey();
102+
Object value = entry.getValue();
103+
if (value == null || value == JSONObject.NULL) {
104+
builder.put(key, (String) null);
105+
} else if (value instanceof String) {
106+
builder.put(key, (String) value);
107+
} else if (value instanceof Integer || value instanceof Long) {
108+
builder.put(key, ((Number) value).longValue());
109+
} else if (value instanceof Number) {
110+
builder.put(key, ((Number) value).doubleValue());
111+
} else {
112+
throw new IllegalArgumentException("Unsupported value type for key: " + key);
113+
}
114+
}
115+
return getFirebaseRemoteConfigInstance().setCustomSignals(builder.build());
116+
}
117+
96118
public Task<Void> setDefaults(@NonNull Map<String, Object> defaults) {
97119
return getFirebaseRemoteConfigInstance().setDefaultsAsync(defaults);
98120
}

packages/remote-config/android/src/main/java/io/capawesome/capacitorjs/plugins/firebase/remoteconfig/FirebaseRemoteConfigPlugin.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class FirebaseRemoteConfigPlugin extends Plugin {
2121
public static final String TAG = "FirebaseRemoteConfig";
2222
public static final String ERROR_KEY_MISSING = "key must be provided.";
2323
public static final String ERROR_CALLBACK_ID_MISSING = "callbackId must be provided.";
24+
public static final String ERROR_CUSTOM_SIGNALS_MISSING = "customSignals must be provided.";
2425
public static final String ERROR_DEFAULTS_MISSING = "defaults must be provided.";
2526

2627
private static final int DEFAULT_MINIMUM_FETCH_INTERVAL_IN_SECONDS = 43200;
@@ -199,6 +200,37 @@ public void setMinimumFetchInterval(PluginCall call) {
199200
call.reject("Not available on Android.");
200201
}
201202

203+
@PluginMethod
204+
public void setCustomSignals(PluginCall call) {
205+
try {
206+
JSObject customSignals = call.getObject("customSignals");
207+
if (customSignals == null) {
208+
call.reject(ERROR_CUSTOM_SIGNALS_MISSING);
209+
return;
210+
}
211+
212+
Map<String, Object> parsedCustomSignals = new HashMap<>();
213+
Iterator<String> keys = customSignals.keys();
214+
while (keys.hasNext()) {
215+
String key = keys.next();
216+
parsedCustomSignals.put(key, customSignals.get(key));
217+
}
218+
219+
implementation.setCustomSignals(parsedCustomSignals).addOnCompleteListener(t -> {
220+
if (t.isSuccessful()) {
221+
call.resolve();
222+
} else {
223+
Exception exception = t.getException();
224+
String errorMessage = exception != null ? exception.getMessage() : "Failed to set custom signals.";
225+
call.reject(errorMessage);
226+
}
227+
});
228+
} catch (Exception exception) {
229+
Logger.error(TAG, exception.getMessage(), exception);
230+
call.reject(exception.getMessage());
231+
}
232+
}
233+
202234
@PluginMethod
203235
public void setDefaults(PluginCall call) {
204236
try {

packages/remote-config/ios/Plugin/FirebaseRemoteConfig.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,29 @@ import Capacitor
8383
completion(lastFetchTimeMillis, statusInt, nil)
8484
}
8585

86+
@objc public func setCustomSignals(_ customSignals: [String: Any], completion: @escaping (Error?) -> Void) {
87+
var signals = [String: CustomSignalValue?]()
88+
for (key, value) in customSignals {
89+
if let stringValue = value as? String {
90+
signals[key] = .string(stringValue)
91+
} else if let intValue = value as? Int {
92+
signals[key] = .integer(intValue)
93+
} else if let doubleValue = value as? Double {
94+
signals[key] = .double(doubleValue)
95+
} else {
96+
signals.updateValue(nil, forKey: key)
97+
}
98+
}
99+
Task {
100+
do {
101+
try await RemoteConfig.remoteConfig().setCustomSignals(signals)
102+
completion(nil)
103+
} catch {
104+
completion(error)
105+
}
106+
}
107+
}
108+
86109
@objc public func setDefaults(_ defaults: [String: NSObject]) {
87110
RemoteConfig.remoteConfig().setDefaults(defaults)
88111
}

packages/remote-config/ios/Plugin/FirebaseRemoteConfigPlugin.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class FirebaseRemoteConfigPlugin: CAPPlugin, CAPBridgedPlugin {
1919
CAPPluginMethod(name: "getString", returnType: CAPPluginReturnPromise),
2020
CAPPluginMethod(name: "getAll", returnType: CAPPluginReturnPromise),
2121
CAPPluginMethod(name: "setMinimumFetchInterval", returnType: CAPPluginReturnPromise),
22+
CAPPluginMethod(name: "setCustomSignals", returnType: CAPPluginReturnPromise),
2223
CAPPluginMethod(name: "setDefaults", returnType: CAPPluginReturnPromise),
2324
CAPPluginMethod(name: "setSettings", returnType: CAPPluginReturnPromise),
2425
CAPPluginMethod(name: "addConfigUpdateListener", returnType: CAPPluginReturnCallback),
@@ -28,6 +29,7 @@ public class FirebaseRemoteConfigPlugin: CAPPlugin, CAPBridgedPlugin {
2829
public let errorKeyMissing = "key must be provided."
2930
public let errorFetchAndActivatefailed = "fetchAndActivate failed."
3031
public let errorCallbackIdMissing = "callbackId must be provided."
32+
public let errorCustomSignalsMissing = "customSignals must be provided."
3133
public let errorDefaultsMissing = "defaults must be provided."
3234

3335
private let defaultMinimumFetchIntervalInSeconds: Double = 43200
@@ -124,6 +126,22 @@ public class FirebaseRemoteConfigPlugin: CAPPlugin, CAPBridgedPlugin {
124126
call.reject("Not available on iOS.")
125127
}
126128

129+
@objc func setCustomSignals(_ call: CAPPluginCall) {
130+
guard let customSignals = call.getObject("customSignals") else {
131+
call.reject(errorCustomSignalsMissing)
132+
return
133+
}
134+
135+
implementation?.setCustomSignals(customSignals, completion: { error in
136+
if let error = error {
137+
CAPLog.print("[", self.tag, "] ", error)
138+
call.reject(error.localizedDescription)
139+
return
140+
}
141+
call.resolve()
142+
})
143+
}
144+
127145
@objc func setDefaults(_ call: CAPPluginCall) {
128146
guard let defaults = call.getObject("defaults") else {
129147
call.reject(errorDefaultsMissing)

packages/remote-config/src/definitions.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ export interface FirebaseRemoteConfigPlugin {
5858
setMinimumFetchInterval(
5959
options: SetMinimumFetchIntervalOptions,
6060
): Promise<void>;
61+
/**
62+
* Set custom signals for the app instance that can be used for targeting in Remote Config conditions.
63+
*
64+
* @since 8.4.0
65+
*/
66+
setCustomSignals(options: SetCustomSignalsOptions): Promise<void>;
6167
/**
6268
* Sets config defaults for parameter keys and values in the default namespace config.
6369
*
@@ -243,6 +249,20 @@ export interface SetMinimumFetchIntervalOptions {
243249
minimumFetchIntervalInSeconds: number;
244250
}
245251

252+
/**
253+
* @since 8.4.0
254+
*/
255+
export interface SetCustomSignalsOptions {
256+
/**
257+
* The custom signals to set for the app instance.
258+
*
259+
* Signals with a `null` value will be removed.
260+
*
261+
* @since 8.4.0
262+
*/
263+
customSignals: Record<string, string | number | null>;
264+
}
265+
246266
/**
247267
* @since 8.3.0
248268
*/

packages/remote-config/src/web.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getAll,
77
getRemoteConfig,
88
getValue,
9+
setCustomSignals,
910
} from 'firebase/remote-config';
1011
import type { Value } from 'firebase/remote-config';
1112

@@ -20,6 +21,7 @@ import type {
2021
GetOptions,
2122
GetStringResult,
2223
RemoveConfigUpdateListenerOptions,
24+
SetCustomSignalsOptions,
2325
SetMinimumFetchIntervalOptions,
2426
SetDefaultsOptions,
2527
SetSettingsOptions,
@@ -110,6 +112,13 @@ export class FirebaseRemoteConfigWeb
110112
options.minimumFetchIntervalInSeconds * 1000;
111113
}
112114

115+
public async setCustomSignals(
116+
options: SetCustomSignalsOptions,
117+
): Promise<void> {
118+
const remoteConfig = getRemoteConfig();
119+
await setCustomSignals(remoteConfig, options.customSignals);
120+
}
121+
113122
public async setDefaults(options: SetDefaultsOptions): Promise<void> {
114123
const remoteConfig = getRemoteConfig();
115124
remoteConfig.defaultConfig = options.defaults;

0 commit comments

Comments
 (0)