@react-native-firebase/remote-config 26.3.3 → 26.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [26.4.0](https://github.com/invertase/react-native-firebase/compare/v26.3.3...v26.4.0) (2026-09-05)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **remote-config:** use RNFBHandleMap for config update handlers ([f142bdb](https://github.com/invertase/react-native-firebase/commit/f142bdb1d9ec9318c5587a6f70e6cd6da28e9797))
11
+
6
12
  ## [26.3.3](https://github.com/invertase/react-native-firebase/compare/v26.3.2...v26.3.3) (2026-09-01)
7
13
 
8
14
  ### Bug Fixes
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
31
31
  s.tvos.deployment_target = firebase_tvos_target
32
32
  s.source_files = 'ios/**/*.{h,m,mm,cpp}'
33
33
  s.private_header_files = "ios/**/*.h"
34
- s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*'
34
+ s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*', 'ios/*UnitTests/**'
35
35
 
36
36
  # Must be set before install_modules_dependencies so RN can append use_frameworks
37
37
  # HEADER_SEARCH_PATHS (React-debug etc.). Assigning after overwrites those paths
@@ -93,6 +93,8 @@ dependencies {
93
93
  api appProject
94
94
  implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}")
95
95
  implementation "com.google.firebase:firebase-config"
96
+
97
+ testImplementation "junit:junit:4.13.2"
96
98
  }
97
99
 
98
100
  ReactNative.shared.applyPackageVersion()
@@ -0,0 +1,26 @@
1
+ package io.invertase.firebase.config;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ /**
21
+ * Detach surface stored in {@link RNFBRemoteConfigListenerRegistry}. Invoked after {@code get}/
22
+ * {@code take}/{@code takeAll}, never under the HandleMap lock.
23
+ */
24
+ interface ConfigUpdateListenerHandle {
25
+ void remove();
26
+ }
@@ -0,0 +1,76 @@
1
+ package io.invertase.firebase.config;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import io.invertase.firebase.common.RNFBHandleCollisionException;
21
+ import io.invertase.firebase.common.RNFBHandleMap;
22
+ import java.util.List;
23
+
24
+ /**
25
+ * Remote Config update-listener map. Unique {@link #put} / {@link #putOrDiscard}; callers {@link
26
+ * #take} or {@link #takeAllAndRemove} then {@code remove()} outside the HandleMap lock.
27
+ * Skip-if-registered is {@code get(appName) != null}.
28
+ */
29
+ final class RNFBRemoteConfigListenerRegistry {
30
+ private final RNFBHandleMap<String, ConfigUpdateListenerHandle> map = new RNFBHandleMap<>();
31
+
32
+ void put(String appName, ConfigUpdateListenerHandle handle) throws RNFBHandleCollisionException {
33
+ map.put(appName, handle);
34
+ }
35
+
36
+ /**
37
+ * Unique put. On collision, {@code remove()} the incoming handle and leave the existing mapping.
38
+ *
39
+ * @return true if stored
40
+ */
41
+ boolean putOrDiscard(String appName, ConfigUpdateListenerHandle handle) {
42
+ try {
43
+ map.put(appName, handle);
44
+ return true;
45
+ } catch (RNFBHandleCollisionException collision) {
46
+ if (handle != null) {
47
+ handle.remove();
48
+ }
49
+ return false;
50
+ }
51
+ }
52
+
53
+ ConfigUpdateListenerHandle get(String appName) {
54
+ return map.get(appName);
55
+ }
56
+
57
+ ConfigUpdateListenerHandle take(String appName) {
58
+ return map.take(appName);
59
+ }
60
+
61
+ void takeAndRemove(String appName) {
62
+ ConfigUpdateListenerHandle handle = map.take(appName);
63
+ if (handle != null) {
64
+ handle.remove();
65
+ }
66
+ }
67
+
68
+ void takeAllAndRemove() {
69
+ List<ConfigUpdateListenerHandle> remaining = map.takeAll();
70
+ for (ConfigUpdateListenerHandle handle : remaining) {
71
+ if (handle != null) {
72
+ handle.remove();
73
+ }
74
+ }
75
+ }
76
+ }
@@ -37,7 +37,6 @@ import io.invertase.firebase.common.ReactNativeFirebaseEvent;
37
37
  import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
38
38
  import java.util.ArrayList;
39
39
  import java.util.HashMap;
40
- import java.util.Iterator;
41
40
  import java.util.List;
42
41
  import java.util.Map;
43
42
  import java.util.Set;
@@ -48,8 +47,8 @@ public class NativeRNFBTurboConfig extends NativeRNFBTurboConfigSpec {
48
47
  private static final String SERVICE_NAME = "Config";
49
48
  private final UniversalFirebaseConfigModule module;
50
49
 
51
- private static final HashMap<String, ConfigUpdateListenerRegistration>
52
- mConfigUpdateRegistrations = new HashMap<>();
50
+ private static final RNFBRemoteConfigListenerRegistry configUpdateListeners =
51
+ new RNFBRemoteConfigListenerRegistry();
53
52
 
54
53
  public NativeRNFBTurboConfig(ReactApplicationContext reactContext) {
55
54
  super(reactContext);
@@ -60,15 +59,7 @@ public class NativeRNFBTurboConfig extends NativeRNFBTurboConfigSpec {
60
59
  public void invalidate() {
61
60
  super.invalidate();
62
61
 
63
- Iterator<Map.Entry<String, ConfigUpdateListenerRegistration>> configRegistrationsIterator =
64
- mConfigUpdateRegistrations.entrySet().iterator();
65
-
66
- while (configRegistrationsIterator.hasNext()) {
67
- Map.Entry<String, ConfigUpdateListenerRegistration> pair = configRegistrationsIterator.next();
68
- ConfigUpdateListenerRegistration mConfigRegistration = pair.getValue();
69
- mConfigRegistration.remove();
70
- configRegistrationsIterator.remove();
71
- }
62
+ configUpdateListeners.takeAllAndRemove();
72
63
 
73
64
  module.onTearDown();
74
65
  }
@@ -198,79 +189,76 @@ public class NativeRNFBTurboConfig extends NativeRNFBTurboConfigSpec {
198
189
 
199
190
  @Override
200
191
  public void onConfigUpdated(String appName) {
201
- if (mConfigUpdateRegistrations.get(appName) == null) {
202
- ConfigUpdateListenerRegistration registration =
203
- FirebaseRemoteConfig.getInstance(FirebaseApp.getInstance(appName))
204
- .addOnConfigUpdateListener(
205
- new ConfigUpdateListener() {
206
- @Override
207
- public void onUpdate(@NotNull ConfigUpdate configUpdate) {
208
- ReactNativeFirebaseEventEmitter emitter =
209
- ReactNativeFirebaseEventEmitter.getSharedInstance();
210
-
211
- Set<String> updatedKeys = configUpdate.getUpdatedKeys();
212
- List<String> updatedKeysList = new ArrayList<>(updatedKeys);
213
-
214
- Map<String, Object> results = new HashMap<>();
215
- results.put("appName", appName);
216
- results.put("resultType", "success");
217
- results.put("updatedKeys", updatedKeysList);
218
- ReactNativeFirebaseEvent event =
219
- new ReactNativeFirebaseEvent(
220
- "on_config_updated", Arguments.makeNativeMap(results), appName);
221
- emitter.sendEvent(event);
222
- }
192
+ if (configUpdateListeners.get(appName) != null) {
193
+ return;
194
+ }
223
195
 
224
- @Override
225
- public void onError(@NotNull FirebaseRemoteConfigException error) {
226
- ReactNativeFirebaseEventEmitter emitter =
227
- ReactNativeFirebaseEventEmitter.getSharedInstance();
228
-
229
- WritableMap userInfoMap = Arguments.createMap();
230
- userInfoMap.putString("resultType", "error");
231
- userInfoMap.putString("appName", appName);
232
-
233
- FirebaseRemoteConfigException.Code code = error.getCode();
234
- switch (code) {
235
- case CONFIG_UPDATE_STREAM_ERROR:
236
- userInfoMap.putString("code", "config_update_stream_error");
237
- break;
238
- case CONFIG_UPDATE_MESSAGE_INVALID:
239
- userInfoMap.putString("code", "config_update_message_invalid");
240
- break;
241
- case CONFIG_UPDATE_NOT_FETCHED:
242
- userInfoMap.putString("code", "config_update_not_fetched");
243
- break;
244
- case CONFIG_UPDATE_UNAVAILABLE:
245
- userInfoMap.putString("code", "config_update_unavailable");
246
- break;
247
- case UNKNOWN:
248
- userInfoMap.putString("code", "unknown");
249
- break;
250
- default:
251
- userInfoMap.putString("code", "internal");
252
- }
253
-
254
- userInfoMap.putString("message", error.getMessage());
255
- userInfoMap.putString("nativeErrorMessage", error.getMessage());
256
- ReactNativeFirebaseEvent event =
257
- new ReactNativeFirebaseEvent("on_config_updated", userInfoMap, appName);
258
- emitter.sendEvent(event);
196
+ ConfigUpdateListenerRegistration registration =
197
+ FirebaseRemoteConfig.getInstance(FirebaseApp.getInstance(appName))
198
+ .addOnConfigUpdateListener(
199
+ new ConfigUpdateListener() {
200
+ @Override
201
+ public void onUpdate(@NotNull ConfigUpdate configUpdate) {
202
+ ReactNativeFirebaseEventEmitter emitter =
203
+ ReactNativeFirebaseEventEmitter.getSharedInstance();
204
+
205
+ Set<String> updatedKeys = configUpdate.getUpdatedKeys();
206
+ List<String> updatedKeysList = new ArrayList<>(updatedKeys);
207
+
208
+ Map<String, Object> results = new HashMap<>();
209
+ results.put("appName", appName);
210
+ results.put("resultType", "success");
211
+ results.put("updatedKeys", updatedKeysList);
212
+ ReactNativeFirebaseEvent event =
213
+ new ReactNativeFirebaseEvent(
214
+ "on_config_updated", Arguments.makeNativeMap(results), appName);
215
+ emitter.sendEvent(event);
216
+ }
217
+
218
+ @Override
219
+ public void onError(@NotNull FirebaseRemoteConfigException error) {
220
+ ReactNativeFirebaseEventEmitter emitter =
221
+ ReactNativeFirebaseEventEmitter.getSharedInstance();
222
+
223
+ WritableMap userInfoMap = Arguments.createMap();
224
+ userInfoMap.putString("resultType", "error");
225
+ userInfoMap.putString("appName", appName);
226
+
227
+ FirebaseRemoteConfigException.Code code = error.getCode();
228
+ switch (code) {
229
+ case CONFIG_UPDATE_STREAM_ERROR:
230
+ userInfoMap.putString("code", "config_update_stream_error");
231
+ break;
232
+ case CONFIG_UPDATE_MESSAGE_INVALID:
233
+ userInfoMap.putString("code", "config_update_message_invalid");
234
+ break;
235
+ case CONFIG_UPDATE_NOT_FETCHED:
236
+ userInfoMap.putString("code", "config_update_not_fetched");
237
+ break;
238
+ case CONFIG_UPDATE_UNAVAILABLE:
239
+ userInfoMap.putString("code", "config_update_unavailable");
240
+ break;
241
+ case UNKNOWN:
242
+ userInfoMap.putString("code", "unknown");
243
+ break;
244
+ default:
245
+ userInfoMap.putString("code", "internal");
259
246
  }
260
- });
261
247
 
262
- mConfigUpdateRegistrations.put(appName, registration);
263
- }
248
+ userInfoMap.putString("message", error.getMessage());
249
+ userInfoMap.putString("nativeErrorMessage", error.getMessage());
250
+ ReactNativeFirebaseEvent event =
251
+ new ReactNativeFirebaseEvent("on_config_updated", userInfoMap, appName);
252
+ emitter.sendEvent(event);
253
+ }
254
+ });
255
+
256
+ configUpdateListeners.putOrDiscard(appName, registration::remove);
264
257
  }
265
258
 
266
259
  @Override
267
260
  public void removeConfigUpdateRegistration(String appName) {
268
- ConfigUpdateListenerRegistration mConfigRegistration = mConfigUpdateRegistrations.get(appName);
269
-
270
- if (mConfigRegistration != null) {
271
- mConfigRegistration.remove();
272
- mConfigUpdateRegistrations.remove(appName);
273
- }
261
+ configUpdateListeners.takeAndRemove(appName);
274
262
  }
275
263
 
276
264
  @Override
@@ -0,0 +1,171 @@
1
+ package io.invertase.firebase.config;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import static org.junit.Assert.assertEquals;
21
+ import static org.junit.Assert.assertFalse;
22
+ import static org.junit.Assert.assertNull;
23
+ import static org.junit.Assert.assertSame;
24
+ import static org.junit.Assert.assertTrue;
25
+ import static org.junit.Assert.fail;
26
+
27
+ import io.invertase.firebase.common.RNFBHandleCollisionException;
28
+ import org.junit.Test;
29
+
30
+ /**
31
+ * JVM coverage for {@link RNFBRemoteConfigListenerRegistry}. Does not instantiate {@code
32
+ * NativeRNFBTurboConfig} (React Native / Firebase) — D12.
33
+ */
34
+ public class RNFBRemoteConfigListenerRegistryTest {
35
+
36
+ private static final class FakeHandle implements ConfigUpdateListenerHandle {
37
+ int removeCount;
38
+
39
+ @Override
40
+ public void remove() {
41
+ removeCount++;
42
+ }
43
+ }
44
+
45
+ @Test
46
+ public void putGetTake_happyPath() throws Exception {
47
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
48
+ FakeHandle handle = new FakeHandle();
49
+ registry.put("app", handle);
50
+ assertSame(handle, registry.get("app"));
51
+ assertSame(handle, registry.take("app"));
52
+ assertNull(registry.get("app"));
53
+ assertEquals(0, handle.removeCount);
54
+ }
55
+
56
+ @Test
57
+ public void put_occupiedId_throwsCollision() throws Exception {
58
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
59
+ FakeHandle first = new FakeHandle();
60
+ registry.put("app", first);
61
+ try {
62
+ registry.put("app", new FakeHandle());
63
+ fail("expected RNFBHandleCollisionException");
64
+ } catch (RNFBHandleCollisionException e) {
65
+ assertTrue(e.getMessage().contains("app"));
66
+ assertSame(first, registry.get("app"));
67
+ }
68
+ }
69
+
70
+ @Test
71
+ public void get_whenFree_isNull() {
72
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
73
+ assertNull(registry.get("app"));
74
+ }
75
+
76
+ @Test
77
+ public void get_whenOccupied_returnsHandle() throws Exception {
78
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
79
+ FakeHandle first = new FakeHandle();
80
+ registry.put("app", first);
81
+ assertSame(first, registry.get("app"));
82
+ }
83
+
84
+ @Test
85
+ public void putOrDiscard_collision_removesIncoming() throws Exception {
86
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
87
+ FakeHandle first = new FakeHandle();
88
+ FakeHandle duplicate = new FakeHandle();
89
+ registry.put("app", first);
90
+ assertFalse(registry.putOrDiscard("app", duplicate));
91
+ assertEquals(1, duplicate.removeCount);
92
+ assertEquals(0, first.removeCount);
93
+ assertSame(first, registry.get("app"));
94
+ }
95
+
96
+ @Test
97
+ public void putOrDiscard_storesWhenFree() {
98
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
99
+ FakeHandle handle = new FakeHandle();
100
+ assertTrue(registry.putOrDiscard("app", handle));
101
+ assertSame(handle, registry.get("app"));
102
+ assertEquals(0, handle.removeCount);
103
+ }
104
+
105
+ @Test
106
+ public void putOrDiscard_collision_nullIncoming_isNoOp() throws Exception {
107
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
108
+ FakeHandle first = new FakeHandle();
109
+ registry.put("app", first);
110
+ assertFalse(registry.putOrDiscard("app", null));
111
+ assertSame(first, registry.get("app"));
112
+ }
113
+
114
+ @Test
115
+ public void takeAndRemove_removesAfterTake() throws Exception {
116
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
117
+ FakeHandle handle = new FakeHandle();
118
+ registry.put("app", handle);
119
+ registry.takeAndRemove("app");
120
+ assertEquals(1, handle.removeCount);
121
+ assertNull(registry.get("app"));
122
+ }
123
+
124
+ @Test
125
+ public void takeAndRemove_missingKey_isNoOp() {
126
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
127
+ registry.takeAndRemove("missing");
128
+ assertNull(registry.get("missing"));
129
+ }
130
+
131
+ @Test
132
+ public void takeAllAndRemove_removesSnapshotAndLeavesEmpty() throws Exception {
133
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
134
+ FakeHandle a = new FakeHandle();
135
+ FakeHandle b = new FakeHandle();
136
+ registry.put("a", a);
137
+ registry.put("b", b);
138
+ registry.takeAllAndRemove();
139
+ assertEquals(1, a.removeCount);
140
+ assertEquals(1, b.removeCount);
141
+ assertNull(registry.get("a"));
142
+ assertNull(registry.get("b"));
143
+ }
144
+
145
+ @Test
146
+ public void takeAllAndRemove_empty_isNoOp() {
147
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
148
+ registry.takeAllAndRemove();
149
+ assertNull(registry.get("app"));
150
+ }
151
+
152
+ @Test
153
+ public void takeAllAndRemove_nullHandle_isNoOp() throws Exception {
154
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
155
+ registry.put("app", null);
156
+ registry.takeAllAndRemove();
157
+ assertNull(registry.get("app"));
158
+ }
159
+
160
+ @Test
161
+ public void put_afterTake_allowsReuse() throws Exception {
162
+ RNFBRemoteConfigListenerRegistry registry = new RNFBRemoteConfigListenerRegistry();
163
+ FakeHandle first = new FakeHandle();
164
+ FakeHandle second = new FakeHandle();
165
+ registry.put("app", first);
166
+ assertSame(first, registry.take("app"));
167
+ registry.put("app", second);
168
+ assertSame(second, registry.get("app"));
169
+ assertEquals(0, first.removeCount);
170
+ }
171
+ }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
3
  // Generated by genversion.
4
- export const version = '26.3.3';
4
+ export const version = '26.4.0';
5
5
  //# sourceMappingURL=version.js.map
@@ -3,7 +3,7 @@ import { LastFetchStatus, ValueSource } from './statics';
3
3
  import type { ConfigUpdateObserver, CustomSignals, LogLevel, RemoteConfig, RemoteConfigOptions, Unsubscribe, Value } from './types/remote-config';
4
4
  import './types/internal';
5
5
  export { LastFetchStatus, ValueSource };
6
- export declare const SDK_VERSION = "26.3.3";
6
+ export declare const SDK_VERSION = "26.4.0";
7
7
  /**
8
8
  * Returns a RemoteConfig instance for the given app.
9
9
  * @param app - FirebaseApp. Optional.
@@ -1,2 +1,2 @@
1
- export declare const version = "26.3.3";
1
+ export declare const version = "26.4.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -26,10 +26,11 @@
26
26
  #import "RNFBApp/RCTConvert+FIRApp.h"
27
27
  #import "RNFBApp/RNFBSharedUtils.h"
28
28
  #import "RNFBConfigHelper.h"
29
+ #import "RNFBRemoteConfigListenerRegistry.h"
29
30
 
30
31
  static NSString *const ON_CONFIG_UPDATED_EVENT = @"on_config_updated";
31
32
 
32
- static __strong NSMutableDictionary *configUpdateHandlers;
33
+ static __strong RNFBRemoteConfigListenerRegistry *configUpdateHandlers;
33
34
 
34
35
  static NSString *convertFIRRemoteConfigFetchStatusToNSString(FIRRemoteConfigFetchStatus value) {
35
36
  switch (value) {
@@ -98,6 +99,13 @@ static FIRApp *firebaseAppForName(NSString *appName) {
98
99
 
99
100
  @implementation RNFBConfigHelper
100
101
 
102
+ + (void)initializeConfigUpdateHandlersOnce {
103
+ static dispatch_once_t onceToken;
104
+ dispatch_once(&onceToken, ^{
105
+ configUpdateHandlers = [[RNFBRemoteConfigListenerRegistry alloc] init];
106
+ });
107
+ }
108
+
101
109
  + (NSDictionary *)getConstantsForAppName:(NSString *)appName {
102
110
  FIRApp *firebaseApp = firebaseAppForName(appName);
103
111
  return [self getConstantsForApp:firebaseApp];
@@ -311,61 +319,54 @@ static FIRApp *firebaseAppForName(NSString *appName) {
311
319
  }
312
320
 
313
321
  + (void)onConfigUpdated:(NSString *)appName {
314
- static dispatch_once_t onceToken;
315
- dispatch_once(&onceToken, ^{
316
- configUpdateHandlers = [[NSMutableDictionary alloc] init];
317
- });
322
+ [self initializeConfigUpdateHandlersOnce];
318
323
 
319
324
  FIRApp *firebaseApp = firebaseAppForName(appName);
320
- if (![configUpdateHandlers valueForKey:firebaseApp.name]) {
321
- FIRConfigUpdateListenerRegistration *newRegistration =
322
- [[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
323
- addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nonnull configUpdate,
324
- NSError *_Nullable error) {
325
- if (error != nil) {
326
- NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
327
-
328
- [userInfo setValue:@"error" forKey:@"resultType"];
329
- [userInfo setValue:convertFIRRemoteConfigUpdateErrorToNSString(
330
- (FIRRemoteConfigUpdateError)error.code)
331
- forKey:@"code"];
332
- [userInfo setValue:error.localizedDescription forKey:@"message"];
333
- [userInfo setValue:error.localizedDescription forKey:@"nativeErrorMessage"];
334
- [RNFBSharedUtils sendJSEventForApp:firebaseApp
335
- name:ON_CONFIG_UPDATED_EVENT
336
- body:userInfo];
337
- return;
338
- }
339
-
340
- NSMutableDictionary *results = [NSMutableDictionary dictionary];
341
-
342
- [results setValue:@"success" forKey:@"resultType"];
343
- [results setValue:[configUpdate.updatedKeys allObjects] forKey:@"updatedKeys"];
325
+ if ([configUpdateHandlers get:firebaseApp.name] != nil) {
326
+ return;
327
+ }
344
328
 
329
+ FIRConfigUpdateListenerRegistration *newRegistration =
330
+ [[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
331
+ addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nonnull configUpdate,
332
+ NSError *_Nullable error) {
333
+ if (error != nil) {
334
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
335
+
336
+ [userInfo setValue:@"error" forKey:@"resultType"];
337
+ [userInfo setValue:convertFIRRemoteConfigUpdateErrorToNSString(
338
+ (FIRRemoteConfigUpdateError)error.code)
339
+ forKey:@"code"];
340
+ [userInfo setValue:error.localizedDescription forKey:@"message"];
341
+ [userInfo setValue:error.localizedDescription forKey:@"nativeErrorMessage"];
345
342
  [RNFBSharedUtils sendJSEventForApp:firebaseApp
346
343
  name:ON_CONFIG_UPDATED_EVENT
347
- body:results];
348
- }];
344
+ body:userInfo];
345
+ return;
346
+ }
349
347
 
350
- configUpdateHandlers[firebaseApp.name] = newRegistration;
351
- }
348
+ NSMutableDictionary *results = [NSMutableDictionary dictionary];
349
+
350
+ [results setValue:@"success" forKey:@"resultType"];
351
+ [results setValue:[configUpdate.updatedKeys allObjects] forKey:@"updatedKeys"];
352
+
353
+ [RNFBSharedUtils sendJSEventForApp:firebaseApp
354
+ name:ON_CONFIG_UPDATED_EVENT
355
+ body:results];
356
+ }];
357
+
358
+ [configUpdateHandlers putOrDiscard:firebaseApp.name value:newRegistration];
352
359
  }
353
360
 
354
361
  + (void)removeConfigUpdateRegistration:(NSString *)appName {
362
+ [self initializeConfigUpdateHandlersOnce];
355
363
  FIRApp *firebaseApp = firebaseAppForName(appName);
356
- if ([configUpdateHandlers valueForKey:firebaseApp.name]) {
357
- [[configUpdateHandlers objectForKey:firebaseApp.name] remove];
358
- [configUpdateHandlers removeObjectForKey:firebaseApp.name];
359
- }
364
+ [configUpdateHandlers takeAndRemove:firebaseApp.name];
360
365
  }
361
366
 
362
367
  + (void)removeAllConfigUpdateRegistrations {
363
- for (NSString *key in [configUpdateHandlers allKeys]) {
364
- FIRConfigUpdateListenerRegistration *registration = [configUpdateHandlers objectForKey:key];
365
- [registration remove];
366
- }
367
-
368
- [configUpdateHandlers removeAllObjects];
368
+ [self initializeConfigUpdateHandlersOnce];
369
+ [configUpdateHandlers removeAll];
369
370
  }
370
371
 
371
372
  + (void)setCustomSignals:(NSString *)appName
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+
20
+ NS_ASSUME_NONNULL_BEGIN
21
+
22
+ /**
23
+ * Remote Config update-listener map. Unique `put` / `putOrDiscard`; callers `take` or `removeAll`
24
+ * then `remove` outside the HandleMap lock. Skip-if-registered is `get != nil`. Stored values are
25
+ * expected to respond to `remove`.
26
+ */
27
+ @interface RNFBRemoteConfigListenerRegistry : NSObject
28
+
29
+ - (BOOL)put:(id)key value:(id)value error:(NSError *_Nullable *_Nullable)error;
30
+ /// Unique put. On collision, `remove`s the incoming value and leaves the existing mapping.
31
+ - (BOOL)putOrDiscard:(id)key value:(id)value;
32
+ - (nullable id)get:(id)key;
33
+ - (nullable id)take:(id)key;
34
+ - (void)takeAndRemove:(id)key;
35
+ - (void)removeAll;
36
+
37
+ @end
38
+
39
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import "RNFBRemoteConfigListenerRegistry.h"
19
+
20
+ #if __has_include("RNFBHandleMap.h")
21
+ #import "RNFBHandleMap.h"
22
+ #else
23
+ #import "RNFBApp/RNFBHandleMap.h"
24
+ #endif
25
+
26
+ @protocol RNFBRemoteConfigRemovable <NSObject>
27
+ - (void)remove;
28
+ @end
29
+
30
+ @interface RNFBRemoteConfigListenerRegistry ()
31
+ @property(nonatomic, strong) RNFBHandleMap *map;
32
+ @end
33
+
34
+ @implementation RNFBRemoteConfigListenerRegistry
35
+
36
+ - (instancetype)init {
37
+ self = [super init];
38
+ if (self) {
39
+ _map = [[RNFBHandleMap alloc] init];
40
+ }
41
+ return self;
42
+ }
43
+
44
+ - (void)rnfb_removeHandle:(id)handle {
45
+ if (handle && [handle respondsToSelector:@selector(remove)]) {
46
+ [(id<RNFBRemoteConfigRemovable>)handle remove];
47
+ }
48
+ }
49
+
50
+ - (BOOL)put:(id)key value:(id)value error:(NSError **)error {
51
+ return [self.map put:key value:value error:error];
52
+ }
53
+
54
+ - (BOOL)putOrDiscard:(id)key value:(id)value {
55
+ NSError *error = nil;
56
+ if ([self.map put:key value:value error:&error]) {
57
+ return YES;
58
+ }
59
+ [self rnfb_removeHandle:value];
60
+ return NO;
61
+ }
62
+
63
+ - (id)get:(id)key {
64
+ return [self.map get:key];
65
+ }
66
+
67
+ - (id)take:(id)key {
68
+ return [self.map take:key];
69
+ }
70
+
71
+ - (void)takeAndRemove:(id)key {
72
+ id handle = [self.map take:key];
73
+ [self rnfb_removeHandle:handle];
74
+ }
75
+
76
+ - (void)removeAll {
77
+ NSArray *handlers = [self.map takeAll];
78
+ for (id handler in handlers) {
79
+ [self rnfb_removeHandle:handler];
80
+ }
81
+ }
82
+
83
+ @end
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <XCTest/XCTest.h>
19
+
20
+ #import "RNFBHandleMap.h"
21
+ #import "RNFBRemoteConfigListenerRegistry.h"
22
+
23
+ @interface FakeRemoteConfigListenerHandle : NSObject
24
+ @property(nonatomic, assign) NSInteger removeCount;
25
+ - (void)remove;
26
+ @end
27
+
28
+ @implementation FakeRemoteConfigListenerHandle
29
+ - (void)remove {
30
+ self.removeCount += 1;
31
+ }
32
+ @end
33
+
34
+ @interface RNFBRemoteConfigListenerRegistryTests : XCTestCase
35
+ @property(nonatomic, strong) RNFBRemoteConfigListenerRegistry *registry;
36
+ @end
37
+
38
+ @implementation RNFBRemoteConfigListenerRegistryTests
39
+
40
+ - (void)setUp {
41
+ [super setUp];
42
+ self.registry = [[RNFBRemoteConfigListenerRegistry alloc] init];
43
+ }
44
+
45
+ - (void)testPutGetTake_happyPath {
46
+ FakeRemoteConfigListenerHandle *handle = [[FakeRemoteConfigListenerHandle alloc] init];
47
+ NSError *error = nil;
48
+ XCTAssertTrue([self.registry put:@"app" value:handle error:&error]);
49
+ XCTAssertNil(error);
50
+ XCTAssertEqual(handle, [self.registry get:@"app"]);
51
+ XCTAssertEqual(handle, [self.registry take:@"app"]);
52
+ XCTAssertNil([self.registry get:@"app"]);
53
+ XCTAssertEqual(handle.removeCount, 0);
54
+ }
55
+
56
+ - (void)testPut_occupiedId_returnsCollision {
57
+ FakeRemoteConfigListenerHandle *first = [[FakeRemoteConfigListenerHandle alloc] init];
58
+ XCTAssertTrue([self.registry put:@"app" value:first error:nil]);
59
+
60
+ NSError *error = nil;
61
+ XCTAssertFalse([self.registry put:@"app"
62
+ value:[[FakeRemoteConfigListenerHandle alloc] init]
63
+ error:&error]);
64
+ XCTAssertNotNil(error);
65
+ XCTAssertEqualObjects(error.domain, RNFBHandleMapErrorDomain);
66
+ XCTAssertEqual(error.code, RNFBHandleMapErrorCollision);
67
+ XCTAssertEqual(first, [self.registry get:@"app"]);
68
+ }
69
+
70
+ - (void)testPut_occupiedId_nilErrorOut_returnsNo {
71
+ FakeRemoteConfigListenerHandle *first = [[FakeRemoteConfigListenerHandle alloc] init];
72
+ XCTAssertTrue([self.registry put:@"app" value:first error:nil]);
73
+ XCTAssertFalse([self.registry put:@"app"
74
+ value:[[FakeRemoteConfigListenerHandle alloc] init]
75
+ error:nil]);
76
+ XCTAssertEqual(first, [self.registry get:@"app"]);
77
+ }
78
+
79
+ - (void)testGet_whenFree_isNil {
80
+ XCTAssertNil([self.registry get:@"app"]);
81
+ }
82
+
83
+ - (void)testGet_whenOccupied_returnsHandle {
84
+ FakeRemoteConfigListenerHandle *first = [[FakeRemoteConfigListenerHandle alloc] init];
85
+ XCTAssertTrue([self.registry put:@"app" value:first error:nil]);
86
+ XCTAssertEqual(first, [self.registry get:@"app"]);
87
+ }
88
+
89
+ - (void)testPutOrDiscard_collision_removesIncoming {
90
+ FakeRemoteConfigListenerHandle *first = [[FakeRemoteConfigListenerHandle alloc] init];
91
+ FakeRemoteConfigListenerHandle *duplicate = [[FakeRemoteConfigListenerHandle alloc] init];
92
+ XCTAssertTrue([self.registry put:@"app" value:first error:nil]);
93
+ XCTAssertFalse([self.registry putOrDiscard:@"app" value:duplicate]);
94
+ XCTAssertEqual(duplicate.removeCount, 1);
95
+ XCTAssertEqual(first.removeCount, 0);
96
+ XCTAssertEqual(first, [self.registry get:@"app"]);
97
+ }
98
+
99
+ - (void)testPutOrDiscard_storesWhenFree {
100
+ FakeRemoteConfigListenerHandle *handle = [[FakeRemoteConfigListenerHandle alloc] init];
101
+ XCTAssertTrue([self.registry putOrDiscard:@"app" value:handle]);
102
+ XCTAssertEqual(handle, [self.registry get:@"app"]);
103
+ XCTAssertEqual(handle.removeCount, 0);
104
+ }
105
+
106
+ - (void)testTakeAndRemove_removesAfterTake {
107
+ FakeRemoteConfigListenerHandle *handle = [[FakeRemoteConfigListenerHandle alloc] init];
108
+ XCTAssertTrue([self.registry put:@"app" value:handle error:nil]);
109
+ [self.registry takeAndRemove:@"app"];
110
+ XCTAssertEqual(handle.removeCount, 1);
111
+ XCTAssertNil([self.registry get:@"app"]);
112
+ }
113
+
114
+ - (void)testTakeAndRemove_missingKey_isNoOp {
115
+ [self.registry takeAndRemove:@"missing"];
116
+ }
117
+
118
+ - (void)testRemoveAll_removesSnapshotAndLeavesEmpty {
119
+ FakeRemoteConfigListenerHandle *a = [[FakeRemoteConfigListenerHandle alloc] init];
120
+ FakeRemoteConfigListenerHandle *b = [[FakeRemoteConfigListenerHandle alloc] init];
121
+ XCTAssertTrue([self.registry put:@"a" value:a error:nil]);
122
+ XCTAssertTrue([self.registry put:@"b" value:b error:nil]);
123
+ [self.registry removeAll];
124
+ XCTAssertEqual(a.removeCount, 1);
125
+ XCTAssertEqual(b.removeCount, 1);
126
+ XCTAssertNil([self.registry get:@"a"]);
127
+ XCTAssertNil([self.registry get:@"b"]);
128
+ }
129
+
130
+ - (void)testPut_afterTake_allowsReuse {
131
+ FakeRemoteConfigListenerHandle *first = [[FakeRemoteConfigListenerHandle alloc] init];
132
+ FakeRemoteConfigListenerHandle *second = [[FakeRemoteConfigListenerHandle alloc] init];
133
+ XCTAssertTrue([self.registry put:@"app" value:first error:nil]);
134
+ XCTAssertEqual(first, [self.registry take:@"app"]);
135
+ XCTAssertTrue([self.registry put:@"app" value:second error:nil]);
136
+ XCTAssertEqual(second, [self.registry get:@"app"]);
137
+ XCTAssertEqual(first.removeCount, 0);
138
+ }
139
+
140
+ - (void)testRemoveAll_objectWithoutRemove_doesNotCrash {
141
+ NSObject *plain = [[NSObject alloc] init];
142
+ XCTAssertTrue([self.registry put:@"plain" value:plain error:nil]);
143
+ [self.registry removeAll];
144
+ XCTAssertNil([self.registry get:@"plain"]);
145
+ }
146
+
147
+ - (void)testTakeAndRemove_objectWithoutRemove_doesNotCrash {
148
+ NSObject *plain = [[NSObject alloc] init];
149
+ XCTAssertTrue([self.registry put:@"plain" value:plain error:nil]);
150
+ [self.registry takeAndRemove:@"plain"];
151
+ XCTAssertNil([self.registry get:@"plain"]);
152
+ }
153
+
154
+ @end
@@ -0,0 +1,251 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 56;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ A9000000000000000000000A /* RNFBHandleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000008 /* RNFBHandleMap.m */; };
11
+ A9000000000000000000000B /* RNFBRemoteConfigListenerRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000018 /* RNFBRemoteConfigListenerRegistry.m */; };
12
+ A9000000000000000000000C /* RNFBRemoteConfigListenerRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A90000000000000000000009 /* RNFBRemoteConfigListenerRegistryTests.m */; };
13
+ A90000000000000000000015 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A90000000000000000000014 /* XCTest.framework */; };
14
+ /* End PBXBuildFile section */
15
+
16
+ /* Begin PBXFileReference section */
17
+ A90000000000000000000003 /* RNFBRemoteConfigUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNFBRemoteConfigUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
18
+ A90000000000000000000007 /* RNFBHandleMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBHandleMap.h; path = ../../../app/ios/RNFBApp/RNFBHandleMap.h; sourceTree = SOURCE_ROOT; };
19
+ A90000000000000000000008 /* RNFBHandleMap.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBHandleMap.m; path = ../../../app/ios/RNFBApp/RNFBHandleMap.m; sourceTree = SOURCE_ROOT; };
20
+ A90000000000000000000009 /* RNFBRemoteConfigListenerRegistryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBRemoteConfigListenerRegistryTests.m; sourceTree = "<group>"; };
21
+ A90000000000000000000016 /* RNFBRemoteConfigListenerRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBRemoteConfigListenerRegistry.h; path = ../RNFBConfig/RNFBRemoteConfigListenerRegistry.h; sourceTree = SOURCE_ROOT; };
22
+ A90000000000000000000018 /* RNFBRemoteConfigListenerRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBRemoteConfigListenerRegistry.m; path = ../RNFBConfig/RNFBRemoteConfigListenerRegistry.m; sourceTree = SOURCE_ROOT; };
23
+ A90000000000000000000014 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
24
+ /* End PBXFileReference section */
25
+
26
+ /* Begin PBXFrameworksBuildPhase section */
27
+ A9000000000000000000000D /* Frameworks */ = {
28
+ isa = PBXFrameworksBuildPhase;
29
+ buildActionMask = 2147483647;
30
+ files = (
31
+ A90000000000000000000015 /* XCTest.framework in Frameworks */,
32
+ );
33
+ runOnlyForDeploymentPostprocessing = 0;
34
+ };
35
+ /* End PBXFrameworksBuildPhase section */
36
+
37
+ /* Begin PBXGroup section */
38
+ A90000000000000000000004 = {
39
+ isa = PBXGroup;
40
+ children = (
41
+ A90000000000000000000006 /* Sources */,
42
+ A90000000000000000000005 /* Products */,
43
+ );
44
+ sourceTree = "<group>";
45
+ };
46
+ A90000000000000000000005 /* Products */ = {
47
+ isa = PBXGroup;
48
+ children = (
49
+ A90000000000000000000003 /* RNFBRemoteConfigUnitTests.xctest */,
50
+ );
51
+ name = Products;
52
+ sourceTree = "<group>";
53
+ };
54
+ A90000000000000000000006 /* Sources */ = {
55
+ isa = PBXGroup;
56
+ children = (
57
+ A90000000000000000000007 /* RNFBHandleMap.h */,
58
+ A90000000000000000000008 /* RNFBHandleMap.m */,
59
+ A90000000000000000000016 /* RNFBRemoteConfigListenerRegistry.h */,
60
+ A90000000000000000000018 /* RNFBRemoteConfigListenerRegistry.m */,
61
+ A90000000000000000000009 /* RNFBRemoteConfigListenerRegistryTests.m */,
62
+ );
63
+ name = Sources;
64
+ sourceTree = "<group>";
65
+ };
66
+ /* End PBXGroup section */
67
+
68
+ /* Begin PBXNativeTarget section */
69
+ A90000000000000000000002 /* RNFBRemoteConfigUnitTests */ = {
70
+ isa = PBXNativeTarget;
71
+ buildConfigurationList = A90000000000000000000013 /* Build configuration list for PBXNativeTarget "RNFBRemoteConfigUnitTests" */;
72
+ buildPhases = (
73
+ A9000000000000000000000E /* Sources */,
74
+ A9000000000000000000000D /* Frameworks */,
75
+ );
76
+ buildRules = (
77
+ );
78
+ dependencies = (
79
+ );
80
+ name = RNFBRemoteConfigUnitTests;
81
+ productName = RNFBRemoteConfigUnitTests;
82
+ productReference = A90000000000000000000003 /* RNFBRemoteConfigUnitTests.xctest */;
83
+ productType = "com.apple.product-type.bundle.unit-test";
84
+ };
85
+ /* End PBXNativeTarget section */
86
+
87
+ /* Begin PBXProject section */
88
+ A90000000000000000000001 /* Project object */ = {
89
+ isa = PBXProject;
90
+ attributes = {
91
+ BuildIndependentTargetsInParallel = 1;
92
+ LastUpgradeCheck = 2600;
93
+ ORGANIZATIONNAME = Invertase;
94
+ TargetAttributes = {
95
+ A90000000000000000000002 = {
96
+ CreatedOnToolsVersion = 26.0;
97
+ };
98
+ };
99
+ };
100
+ buildConfigurationList = A90000000000000000000012 /* Build configuration list for PBXProject "RNFBRemoteConfigUnitTests" */;
101
+ compatibilityVersion = "Xcode 14.0";
102
+ developmentRegion = en;
103
+ hasScannedForEncodings = 0;
104
+ knownRegions = (
105
+ en,
106
+ Base,
107
+ );
108
+ mainGroup = A90000000000000000000004;
109
+ productRefGroup = A90000000000000000000005 /* Products */;
110
+ projectDirPath = "";
111
+ projectRoot = "";
112
+ targets = (
113
+ A90000000000000000000002 /* RNFBRemoteConfigUnitTests */,
114
+ );
115
+ };
116
+ /* End PBXProject section */
117
+
118
+ /* Begin PBXSourcesBuildPhase section */
119
+ A9000000000000000000000E /* Sources */ = {
120
+ isa = PBXSourcesBuildPhase;
121
+ buildActionMask = 2147483647;
122
+ files = (
123
+ A9000000000000000000000A /* RNFBHandleMap.m in Sources */,
124
+ A9000000000000000000000B /* RNFBRemoteConfigListenerRegistry.m in Sources */,
125
+ A9000000000000000000000C /* RNFBRemoteConfigListenerRegistryTests.m in Sources */,
126
+ );
127
+ runOnlyForDeploymentPostprocessing = 0;
128
+ };
129
+ /* End PBXSourcesBuildPhase section */
130
+
131
+ /* Begin XCBuildConfiguration section */
132
+ A9000000000000000000001A /* Debug */ = {
133
+ isa = XCBuildConfiguration;
134
+ buildSettings = {
135
+ ALWAYS_SEARCH_USER_PATHS = NO;
136
+ CLANG_ENABLE_MODULES = YES;
137
+ CLANG_ENABLE_OBJC_ARC = YES;
138
+ COPY_PHASE_STRIP = NO;
139
+ DEBUG_INFORMATION_FORMAT = dwarf;
140
+ ENABLE_TESTABILITY = YES;
141
+ GCC_C_LANGUAGE_STANDARD = gnu17;
142
+ GCC_DYNAMIC_NO_PIC = NO;
143
+ GCC_OPTIMIZATION_LEVEL = 0;
144
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
145
+ ONLY_ACTIVE_ARCH = YES;
146
+ SDKROOT = macosx;
147
+ SUPPORTED_PLATFORMS = macosx;
148
+ };
149
+ name = Debug;
150
+ };
151
+ A9000000000000000000001B /* Release */ = {
152
+ isa = XCBuildConfiguration;
153
+ buildSettings = {
154
+ ALWAYS_SEARCH_USER_PATHS = NO;
155
+ CLANG_ENABLE_MODULES = YES;
156
+ CLANG_ENABLE_OBJC_ARC = YES;
157
+ COPY_PHASE_STRIP = YES;
158
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
159
+ GCC_C_LANGUAGE_STANDARD = gnu17;
160
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
161
+ SDKROOT = macosx;
162
+ SUPPORTED_PLATFORMS = macosx;
163
+ };
164
+ name = Release;
165
+ };
166
+ A90000000000000000000010 /* Debug */ = {
167
+ isa = XCBuildConfiguration;
168
+ buildSettings = {
169
+ CLANG_ENABLE_CODE_COVERAGE = YES;
170
+ CODE_SIGNING_ALLOWED = NO;
171
+ CODE_SIGNING_REQUIRED = NO;
172
+ CODE_SIGN_IDENTITY = "-";
173
+ COMBINE_HIDPI_IMAGES = YES;
174
+ GENERATE_INFOPLIST_FILE = YES;
175
+ HEADER_SEARCH_PATHS = (
176
+ "$(SRCROOT)/../../../app/ios",
177
+ "$(SRCROOT)/../../../app/ios/RNFBApp",
178
+ "$(SRCROOT)/../RNFBConfig",
179
+ );
180
+ LD_RUNPATH_SEARCH_PATHS = (
181
+ "$(inherited)",
182
+ "@executable_path/../Frameworks",
183
+ "@loader_path/../Frameworks",
184
+ );
185
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
186
+ OTHER_CFLAGS = (
187
+ "-fprofile-instr-generate",
188
+ "-fcoverage-mapping",
189
+ );
190
+ OTHER_LDFLAGS = (
191
+ "-fprofile-instr-generate",
192
+ );
193
+ PRODUCT_BUNDLE_IDENTIFIER = io.invertase.firebase.RNFBRemoteConfigUnitTests;
194
+ PRODUCT_NAME = "$(TARGET_NAME)";
195
+ SDKROOT = macosx;
196
+ SUPPORTED_PLATFORMS = macosx;
197
+ };
198
+ name = Debug;
199
+ };
200
+ A90000000000000000000011 /* Release */ = {
201
+ isa = XCBuildConfiguration;
202
+ buildSettings = {
203
+ CLANG_ENABLE_CODE_COVERAGE = YES;
204
+ CODE_SIGNING_ALLOWED = NO;
205
+ CODE_SIGNING_REQUIRED = NO;
206
+ CODE_SIGN_IDENTITY = "-";
207
+ COMBINE_HIDPI_IMAGES = YES;
208
+ GENERATE_INFOPLIST_FILE = YES;
209
+ HEADER_SEARCH_PATHS = (
210
+ "$(SRCROOT)/../../../app/ios",
211
+ "$(SRCROOT)/../../../app/ios/RNFBApp",
212
+ "$(SRCROOT)/../RNFBConfig",
213
+ );
214
+ LD_RUNPATH_SEARCH_PATHS = (
215
+ "$(inherited)",
216
+ "@executable_path/../Frameworks",
217
+ "@loader_path/../Frameworks",
218
+ );
219
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
220
+ PRODUCT_BUNDLE_IDENTIFIER = io.invertase.firebase.RNFBRemoteConfigUnitTests;
221
+ PRODUCT_NAME = "$(TARGET_NAME)";
222
+ SDKROOT = macosx;
223
+ SUPPORTED_PLATFORMS = macosx;
224
+ };
225
+ name = Release;
226
+ };
227
+ /* End XCBuildConfiguration section */
228
+
229
+ /* Begin XCConfigurationList section */
230
+ A90000000000000000000012 /* Build configuration list for PBXProject "RNFBRemoteConfigUnitTests" */ = {
231
+ isa = XCConfigurationList;
232
+ buildConfigurations = (
233
+ A9000000000000000000001A /* Debug */,
234
+ A9000000000000000000001B /* Release */,
235
+ );
236
+ defaultConfigurationIsVisible = 0;
237
+ defaultConfigurationName = Debug;
238
+ };
239
+ A90000000000000000000013 /* Build configuration list for PBXNativeTarget "RNFBRemoteConfigUnitTests" */ = {
240
+ isa = XCConfigurationList;
241
+ buildConfigurations = (
242
+ A90000000000000000000010 /* Debug */,
243
+ A90000000000000000000011 /* Release */,
244
+ );
245
+ defaultConfigurationIsVisible = 0;
246
+ defaultConfigurationName = Debug;
247
+ };
248
+ /* End XCConfigurationList section */
249
+ };
250
+ rootObject = A90000000000000000000001 /* Project object */;
251
+ }
@@ -0,0 +1,69 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ LastUpgradeVersion = "2600"
4
+ version = "1.7">
5
+ <BuildAction
6
+ parallelizeBuildables = "YES"
7
+ buildImplicitDependencies = "YES">
8
+ <BuildActionEntries>
9
+ <BuildActionEntry
10
+ buildForTesting = "YES"
11
+ buildForRunning = "YES"
12
+ buildForProfiling = "NO"
13
+ buildForArchiving = "NO"
14
+ buildForAnalyzing = "YES">
15
+ <BuildableReference
16
+ BuildableIdentifier = "primary"
17
+ BlueprintIdentifier = "A90000000000000000000002"
18
+ BuildableName = "RNFBRemoteConfigUnitTests.xctest"
19
+ BlueprintName = "RNFBRemoteConfigUnitTests"
20
+ ReferencedContainer = "container:RNFBRemoteConfigUnitTests.xcodeproj">
21
+ </BuildableReference>
22
+ </BuildActionEntry>
23
+ </BuildActionEntries>
24
+ </BuildAction>
25
+ <TestAction
26
+ buildConfiguration = "Debug"
27
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+ shouldUseLaunchSchemeArgsEnv = "YES"
30
+ codeCoverageEnabled = "YES">
31
+ <Testables>
32
+ <TestableReference
33
+ skipped = "NO">
34
+ <BuildableReference
35
+ BuildableIdentifier = "primary"
36
+ BlueprintIdentifier = "A90000000000000000000002"
37
+ BuildableName = "RNFBRemoteConfigUnitTests.xctest"
38
+ BlueprintName = "RNFBRemoteConfigUnitTests"
39
+ ReferencedContainer = "container:RNFBRemoteConfigUnitTests.xcodeproj">
40
+ </BuildableReference>
41
+ </TestableReference>
42
+ </Testables>
43
+ </TestAction>
44
+ <LaunchAction
45
+ buildConfiguration = "Debug"
46
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48
+ launchStyle = "0"
49
+ useCustomWorkingDirectory = "NO"
50
+ ignoresPersistentStateOnLaunch = "NO"
51
+ debugDocumentVersioning = "YES"
52
+ debugServiceExtension = "internal"
53
+ allowLocationSimulation = "YES">
54
+ </LaunchAction>
55
+ <ProfileAction
56
+ buildConfiguration = "Release"
57
+ shouldUseLaunchSchemeArgsEnv = "YES"
58
+ savedToolIdentifier = ""
59
+ useCustomWorkingDirectory = "NO"
60
+ debugDocumentVersioning = "YES">
61
+ </ProfileAction>
62
+ <AnalyzeAction
63
+ buildConfiguration = "Debug">
64
+ </AnalyzeAction>
65
+ <ArchiveAction
66
+ buildConfiguration = "Release"
67
+ revealArchiveInOrganizer = "YES">
68
+ </ArchiveAction>
69
+ </Scheme>
package/lib/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '26.3.3';
2
+ export const version = '26.4.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/remote-config",
3
- "version": "26.3.3",
3
+ "version": "26.4.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - React Native Firebase provides native integration with Remote Config, allowing you to change the appearance and/or functionality of your app without requiring an app update.",
6
6
  "main": "./dist/module/index.js",
@@ -28,6 +28,7 @@
28
28
  "android:codegen": "node ../../scripts/codegen-package.mjs remote-config android",
29
29
  "ios:codegen": "node ../../scripts/codegen-package.mjs remote-config ios"
30
30
  },
31
+ "homepage": "https://rnfirebase.io",
31
32
  "repository": {
32
33
  "type": "git",
33
34
  "url": "https://github.com/invertase/react-native-firebase",
@@ -43,8 +44,8 @@
43
44
  "remote-config"
44
45
  ],
45
46
  "peerDependencies": {
46
- "@react-native-firebase/analytics": "26.3.3",
47
- "@react-native-firebase/app": "26.3.3"
47
+ "@react-native-firebase/analytics": "26.4.0",
48
+ "@react-native-firebase/app": "26.4.0"
48
49
  },
49
50
  "publishConfig": {
50
51
  "access": "public",
@@ -56,7 +57,7 @@
56
57
  "web-streams-polyfill": "^4.2.0"
57
58
  },
58
59
  "devDependencies": {
59
- "@react-native-firebase/app": "26.3.3",
60
+ "@react-native-firebase/app": "26.4.0",
60
61
  "@types/text-encoding": "^0.0.40",
61
62
  "react-native-builder-bob": "^0.41.0",
62
63
  "typescript": "^6.0.3"
@@ -91,5 +92,5 @@
91
92
  "node_modules/",
92
93
  "dist/"
93
94
  ],
94
- "gitHead": "04b90008385bf69be74f3a333d0dfea43ba32e64"
95
+ "gitHead": "06701af5fdc19bae9f379567eadb29dfe81953c0"
95
96
  }