@react-native-firebase/app-check 26.3.3 → 26.4.1

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,16 @@
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.1](https://github.com/invertase/react-native-firebase/compare/v26.4.0...v26.4.1) (2026-10-23)
7
+
8
+ **Note:** Version bump only for package @react-native-firebase/app-check
9
+
10
+ ## [26.4.0](https://github.com/invertase/react-native-firebase/compare/v26.3.3...v26.4.0) (2026-09-05)
11
+
12
+ ### Bug Fixes
13
+
14
+ - **app-check:** use RNFBHandleMap for app-check listeners ([b77e645](https://github.com/invertase/react-native-firebase/commit/b77e645cc2b251a6c46314106a2aa9a88b5b808b))
15
+
6
16
  ## [26.3.3](https://github.com/invertase/react-native-firebase/compare/v26.3.2...v26.3.3) (2026-09-01)
7
17
 
8
18
  ### Reverts
@@ -103,6 +103,8 @@ dependencies {
103
103
  implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion('firebase', 'bom')}")
104
104
  implementation 'com.google.firebase:firebase-appcheck-playintegrity'
105
105
  implementation "com.google.firebase:firebase-appcheck-debug"
106
+
107
+ testImplementation "junit:junit:4.13.2"
106
108
  }
107
109
 
108
110
  ReactNative.shared.applyPackageVersion()
@@ -0,0 +1,26 @@
1
+ package io.invertase.firebase.appcheck;
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 RNFBAppCheckListenerRegistry}. Invoked after {@code get}/{@code
22
+ * take}/{@code takeAll}, never under the HandleMap lock.
23
+ */
24
+ interface AppCheckListenerHandle {
25
+ void remove();
26
+ }
@@ -36,9 +36,6 @@ import io.invertase.firebase.common.ReactNativeFirebaseJSON;
36
36
  import io.invertase.firebase.common.ReactNativeFirebaseMeta;
37
37
  import io.invertase.firebase.common.ReactNativeFirebasePreferences;
38
38
  import io.invertase.firebase.common.TaskExecutorService;
39
- import java.util.HashMap;
40
- import java.util.Iterator;
41
- import java.util.Map;
42
39
  import java.util.concurrent.ExecutorService;
43
40
 
44
41
  public class NativeRNFBTurboAppCheck extends NativeRNFBTurboAppCheckSpec {
@@ -46,8 +43,8 @@ public class NativeRNFBTurboAppCheck extends NativeRNFBTurboAppCheckSpec {
46
43
  private static final String LOGTAG = "RNFBAppCheck";
47
44
  private static final String KEY_APPCHECK_TOKEN_REFRESH_ENABLED = "app_check_token_auto_refresh";
48
45
 
49
- private static HashMap<String, FirebaseAppCheck.AppCheckListener> mAppCheckListeners =
50
- new HashMap<>();
46
+ private static final RNFBAppCheckListenerRegistry appCheckListeners =
47
+ new RNFBAppCheckListenerRegistry();
51
48
 
52
49
  private final TaskExecutorService executorService;
53
50
  private final ReactNativeFirebaseAppCheckProviderFactory providerFactory =
@@ -116,18 +113,7 @@ public class NativeRNFBTurboAppCheck extends NativeRNFBTurboAppCheckSpec {
116
113
  super.invalidate();
117
114
  Log.d(TAG, "instance-destroyed");
118
115
 
119
- Iterator appCheckListenerIterator = mAppCheckListeners.entrySet().iterator();
120
-
121
- while (appCheckListenerIterator.hasNext()) {
122
- Map.Entry pair = (Map.Entry) appCheckListenerIterator.next();
123
- String appName = (String) pair.getKey();
124
- FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
125
- FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
126
- FirebaseAppCheck.AppCheckListener mAppCheckListener =
127
- (FirebaseAppCheck.AppCheckListener) pair.getValue();
128
- firebaseAppCheck.removeAppCheckListener(mAppCheckListener);
129
- appCheckListenerIterator.remove();
130
- }
116
+ appCheckListeners.takeAllAndRemove();
131
117
 
132
118
  executorService.shutdown();
133
119
  }
@@ -256,38 +242,32 @@ public class NativeRNFBTurboAppCheck extends NativeRNFBTurboAppCheckSpec {
256
242
  FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
257
243
  FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
258
244
 
259
- if (mAppCheckListeners.get(appName) == null) {
260
- FirebaseAppCheck.AppCheckListener newAppCheckListener =
261
- appCheckToken -> {
262
- WritableMap eventBody = Arguments.createMap();
263
- eventBody.putString("appName", appName);
264
- eventBody.putString("token", appCheckToken.getToken());
265
- eventBody.putDouble("expireTimeMillis", appCheckToken.getExpireTimeMillis());
266
-
267
- ReactNativeFirebaseEventEmitter emitter =
268
- ReactNativeFirebaseEventEmitter.getSharedInstance();
269
- ReactNativeFirebaseEvent event =
270
- new ReactNativeFirebaseEvent("appCheck_token_changed", eventBody, appName);
271
- emitter.sendEvent(event);
272
- };
273
-
274
- firebaseAppCheck.addAppCheckListener(newAppCheckListener);
275
- mAppCheckListeners.put(appName, newAppCheckListener);
245
+ if (appCheckListeners.get(appName) != null) {
246
+ return;
276
247
  }
248
+
249
+ FirebaseAppCheck.AppCheckListener newAppCheckListener =
250
+ appCheckToken -> {
251
+ WritableMap eventBody = Arguments.createMap();
252
+ eventBody.putString("appName", appName);
253
+ eventBody.putString("token", appCheckToken.getToken());
254
+ eventBody.putDouble("expireTimeMillis", appCheckToken.getExpireTimeMillis());
255
+
256
+ ReactNativeFirebaseEventEmitter emitter =
257
+ ReactNativeFirebaseEventEmitter.getSharedInstance();
258
+ ReactNativeFirebaseEvent event =
259
+ new ReactNativeFirebaseEvent("appCheck_token_changed", eventBody, appName);
260
+ emitter.sendEvent(event);
261
+ };
262
+
263
+ firebaseAppCheck.addAppCheckListener(newAppCheckListener);
264
+ appCheckListeners.putOrDiscard(
265
+ appName, () -> firebaseAppCheck.removeAppCheckListener(newAppCheckListener));
277
266
  }
278
267
 
279
268
  @Override
280
269
  public void removeAppCheckListener(String appName) {
281
270
  Log.d(TAG, "removeAppCheckListener " + appName);
282
-
283
- FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
284
- FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
285
-
286
- FirebaseAppCheck.AppCheckListener mAppCheckListener = mAppCheckListeners.get(appName);
287
-
288
- if (mAppCheckListener != null) {
289
- firebaseAppCheck.removeAppCheckListener(mAppCheckListener);
290
- mAppCheckListeners.remove(appName);
291
- }
271
+ appCheckListeners.takeAndRemove(appName);
292
272
  }
293
273
  }
@@ -0,0 +1,76 @@
1
+ package io.invertase.firebase.appcheck;
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
+ * App Check token listener map. Unique {@link #put} / {@link #putOrDiscard}; callers {@link #take}
26
+ * or {@link #takeAllAndRemove} then {@code remove()} outside the HandleMap lock. Skip-if-registered
27
+ * is {@code get(appName) != null}.
28
+ */
29
+ final class RNFBAppCheckListenerRegistry {
30
+ private final RNFBHandleMap<String, AppCheckListenerHandle> map = new RNFBHandleMap<>();
31
+
32
+ void put(String appName, AppCheckListenerHandle 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, AppCheckListenerHandle 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
+ AppCheckListenerHandle get(String appName) {
54
+ return map.get(appName);
55
+ }
56
+
57
+ AppCheckListenerHandle take(String appName) {
58
+ return map.take(appName);
59
+ }
60
+
61
+ void takeAndRemove(String appName) {
62
+ AppCheckListenerHandle handle = map.take(appName);
63
+ if (handle != null) {
64
+ handle.remove();
65
+ }
66
+ }
67
+
68
+ void takeAllAndRemove() {
69
+ List<AppCheckListenerHandle> remaining = map.takeAll();
70
+ for (AppCheckListenerHandle handle : remaining) {
71
+ if (handle != null) {
72
+ handle.remove();
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,171 @@
1
+ package io.invertase.firebase.appcheck;
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 RNFBAppCheckListenerRegistry}. Does not instantiate {@code
32
+ * NativeRNFBTurboAppCheck} (React Native / Firebase) — D12.
33
+ */
34
+ public class RNFBAppCheckListenerRegistryTest {
35
+
36
+ private static final class FakeHandle implements AppCheckListenerHandle {
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
73
+ assertNull(registry.get("app"));
74
+ }
75
+
76
+ @Test
77
+ public void get_whenOccupied_returnsHandle() throws Exception {
78
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
127
+ registry.takeAndRemove("missing");
128
+ assertNull(registry.get("missing"));
129
+ }
130
+
131
+ @Test
132
+ public void takeAllAndRemove_removesSnapshotAndLeavesEmpty() throws Exception {
133
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
148
+ registry.takeAllAndRemove();
149
+ assertNull(registry.get("app"));
150
+ }
151
+
152
+ @Test
153
+ public void takeAllAndRemove_nullHandle_isNoOp() throws Exception {
154
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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
+ RNFBAppCheckListenerRegistry registry = new RNFBAppCheckListenerRegistry();
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.1';
5
5
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  import type { FirebaseApp } from '@react-native-firebase/app';
2
2
  import './types/internal';
3
3
  import type { AppCheck, AppCheckOptions, AppCheckTokenResult, PartialObserver, Unsubscribe } from './types/appcheck';
4
- export declare const SDK_VERSION = "26.3.3";
4
+ export declare const SDK_VERSION = "26.4.1";
5
5
  export { CustomProvider, ReactNativeFirebaseAppCheckProvider } from './providers';
6
6
  /**
7
7
  * Initializes App Check for the given Firebase app.
@@ -1,2 +1,2 @@
1
- export declare const version = "26.3.3";
1
+ export declare const version = "26.4.1";
2
2
  //# sourceMappingURL=version.d.ts.map
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.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/app-check",
3
- "version": "26.3.3",
3
+ "version": "26.4.1",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - App Check",
6
6
  "main": "./dist/module/index.js",
@@ -30,6 +30,7 @@
30
30
  "android:codegen": "node ../../scripts/codegen-package.mjs app-check android",
31
31
  "ios:codegen": "node ../../scripts/codegen-package.mjs app-check ios"
32
32
  },
33
+ "homepage": "https://rnfirebase.io",
33
34
  "repository": {
34
35
  "type": "git",
35
36
  "url": "https://github.com/invertase/react-native-firebase",
@@ -44,11 +45,11 @@
44
45
  "appCheck"
45
46
  ],
46
47
  "peerDependencies": {
47
- "@react-native-firebase/app": "26.3.3",
48
+ "@react-native-firebase/app": "26.4.1",
48
49
  "expo": ">=47.0.0"
49
50
  },
50
51
  "devDependencies": {
51
- "@react-native-firebase/app": "26.3.3",
52
+ "@react-native-firebase/app": "26.4.1",
52
53
  "expo": "^55.0.18",
53
54
  "react-native-builder-bob": "^0.41.0",
54
55
  "typescript": "^6.0.3"
@@ -100,5 +101,5 @@
100
101
  "node_modules/",
101
102
  "dist/"
102
103
  ],
103
- "gitHead": "04b90008385bf69be74f3a333d0dfea43ba32e64"
104
+ "gitHead": "a3efad5f425135a5d2e66857ffae84ebaa02a7ba"
104
105
  }