@react-native-firebase/remote-config 26.0.0 → 26.2.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 +12 -0
- package/RNFBRemoteConfig.podspec +2 -1
- package/dist/module/version.js +1 -1
- package/dist/typescript/lib/index.d.ts +1 -1
- package/dist/typescript/lib/version.d.ts +1 -1
- package/ios/RNFBConfig/RNFBConfigHelper.h +89 -0
- package/ios/RNFBConfig/RNFBConfigHelper.m +387 -0
- package/ios/RNFBConfig/RNFBConfigModule.mm +28 -314
- package/lib/version.ts +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.2.0](https://github.com/invertase/react-native-firebase/compare/v26.1.0...v26.2.0) (2026-08-10)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- codegen should be wipe-then-regen ([04bc4e4](https://github.com/invertase/react-native-firebase/commit/04bc4e4cdab9870cb366fd212b2ccb331b0289d6))
|
|
11
|
+
|
|
12
|
+
## [26.1.0](https://github.com/invertase/react-native-firebase/compare/v26.0.0...v26.1.0) (2026-08-03)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **ios:** add SPM dependency resolution support alongside CocoaPods ([#8933](https://github.com/invertase/react-native-firebase/issues/8933)) ([44a7a9a](https://github.com/invertase/react-native-firebase/commit/44a7a9ae7b404f412e9766c0417f1df8fa971a0b))
|
|
17
|
+
|
|
6
18
|
## [26.0.0](https://github.com/invertase/react-native-firebase/compare/v25.1.0...v26.0.0) (2026-07-29)
|
|
7
19
|
|
|
8
20
|
### ⚠ BREAKING CHANGES
|
package/RNFBRemoteConfig.podspec
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'json'
|
|
2
|
+
require_relative '../app/firebase_spm'
|
|
2
3
|
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
3
4
|
appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json')))
|
|
4
5
|
|
|
@@ -46,7 +47,7 @@ Pod::Spec.new do |s|
|
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
# Firebase dependencies
|
|
49
|
-
s
|
|
50
|
+
firebase_dependency(s, firebase_sdk_version, ['FirebaseRemoteConfig'], 'Firebase/RemoteConfig')
|
|
50
51
|
|
|
51
52
|
if defined?($RNFirebaseAsStaticFramework)
|
|
52
53
|
Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
|
package/dist/module/version.js
CHANGED
|
@@ -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.
|
|
6
|
+
export declare const SDK_VERSION = "26.2.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.
|
|
1
|
+
export declare const version = "26.2.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
#import <React/RCTBridgeModule.h>
|
|
20
|
+
|
|
21
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
22
|
+
|
|
23
|
+
/// Thin Objective-C wrapper around FirebaseRemoteConfig.
|
|
24
|
+
///
|
|
25
|
+
/// FirebaseRemoteConfig is a pure-Swift SPM module: its generated ObjC
|
|
26
|
+
/// interface header (FirebaseRemoteConfig-Swift.h) is not reliably
|
|
27
|
+
/// importable from a cross-project CocoaPods target, and `@import
|
|
28
|
+
/// FirebaseRemoteConfig;` (the pattern the Firebase SDK itself documents for
|
|
29
|
+
/// ObjC clients, see SPMSwiftHeaderWorkaround.swift) requires C++ modules to
|
|
30
|
+
/// be enabled when used from an Objective-C++ (.mm) file, which breaks React
|
|
31
|
+
/// Native's own jsi/React modules. Isolating all FirebaseRemoteConfig usage
|
|
32
|
+
/// in this plain Objective-C (.m) file avoids that requirement entirely,
|
|
33
|
+
/// since `@import` only needs `-fmodules` (already enabled) for plain ObjC.
|
|
34
|
+
/// See okf-bundle/ios-spm-native-imports.md.
|
|
35
|
+
@interface RNFBConfigHelper : NSObject
|
|
36
|
+
|
|
37
|
+
+ (void)ensureInitialized:(NSString *)appName
|
|
38
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
39
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
40
|
+
|
|
41
|
+
+ (void)fetch:(NSString *)appName
|
|
42
|
+
expirationDurationSeconds:(double)expirationDurationSeconds
|
|
43
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
44
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
45
|
+
|
|
46
|
+
+ (void)fetchAndActivate:(NSString *)appName
|
|
47
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
48
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
49
|
+
|
|
50
|
+
+ (void)activate:(NSString *)appName
|
|
51
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
52
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
53
|
+
|
|
54
|
+
+ (void)setConfigSettings:(NSString *)appName
|
|
55
|
+
minimumFetchInterval:(double)minimumFetchInterval
|
|
56
|
+
fetchTimeout:(double)fetchTimeout
|
|
57
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
58
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
59
|
+
|
|
60
|
+
+ (void)setDefaults:(NSString *)appName
|
|
61
|
+
defaults:(NSDictionary *)defaults
|
|
62
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
63
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
64
|
+
|
|
65
|
+
+ (void)setDefaultsFromResource:(NSString *)appName
|
|
66
|
+
resourceName:(NSString *)resourceName
|
|
67
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
68
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
69
|
+
|
|
70
|
+
+ (void)reset:(NSString *)appName
|
|
71
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
72
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
73
|
+
|
|
74
|
+
+ (void)onConfigUpdated:(NSString *)appName;
|
|
75
|
+
|
|
76
|
+
+ (void)removeConfigUpdateRegistration:(NSString *)appName;
|
|
77
|
+
|
|
78
|
+
+ (void)removeAllConfigUpdateRegistrations;
|
|
79
|
+
|
|
80
|
+
+ (void)setCustomSignals:(NSString *)appName
|
|
81
|
+
customSignals:(NSDictionary *)customSignals
|
|
82
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
83
|
+
reject:(RCTPromiseRejectBlock)reject;
|
|
84
|
+
|
|
85
|
+
+ (NSDictionary *)getConstantsForAppName:(NSString *)appName;
|
|
86
|
+
|
|
87
|
+
@end
|
|
88
|
+
|
|
89
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,387 @@
|
|
|
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
|
+
#if __has_include(<Firebase/Firebase.h>)
|
|
19
|
+
#import <Firebase/Firebase.h>
|
|
20
|
+
#else
|
|
21
|
+
@import FirebaseCore;
|
|
22
|
+
@import FirebaseRemoteConfig;
|
|
23
|
+
#endif
|
|
24
|
+
#import <React/RCTConvert.h>
|
|
25
|
+
|
|
26
|
+
#import "RNFBApp/RCTConvert+FIRApp.h"
|
|
27
|
+
#import "RNFBApp/RNFBSharedUtils.h"
|
|
28
|
+
#import "RNFBConfigHelper.h"
|
|
29
|
+
|
|
30
|
+
static NSString *const ON_CONFIG_UPDATED_EVENT = @"on_config_updated";
|
|
31
|
+
|
|
32
|
+
static __strong NSMutableDictionary *configUpdateHandlers;
|
|
33
|
+
|
|
34
|
+
static NSString *convertFIRRemoteConfigFetchStatusToNSString(FIRRemoteConfigFetchStatus value) {
|
|
35
|
+
switch (value) {
|
|
36
|
+
case FIRRemoteConfigFetchStatusNoFetchYet:
|
|
37
|
+
return @"no_fetch_yet";
|
|
38
|
+
case FIRRemoteConfigFetchStatusSuccess:
|
|
39
|
+
return @"success";
|
|
40
|
+
case FIRRemoteConfigFetchStatusThrottled:
|
|
41
|
+
return @"throttled";
|
|
42
|
+
case FIRRemoteConfigFetchStatusFailure:
|
|
43
|
+
return @"failure";
|
|
44
|
+
default:
|
|
45
|
+
return @"unknown";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static NSString *convertFIRRemoteConfigFetchStatusToNSStringDescription(
|
|
50
|
+
FIRRemoteConfigFetchStatus value) {
|
|
51
|
+
switch (value) {
|
|
52
|
+
case FIRRemoteConfigFetchStatusThrottled:
|
|
53
|
+
return @"fetch() operation cannot be completed successfully, due to throttling.";
|
|
54
|
+
case FIRRemoteConfigFetchStatusNoFetchYet:
|
|
55
|
+
default:
|
|
56
|
+
return @"fetch() operation cannot be completed successfully.";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static NSString *convertFIRRemoteConfigSourceToNSString(FIRRemoteConfigSource value) {
|
|
61
|
+
switch (value) {
|
|
62
|
+
case FIRRemoteConfigSourceDefault:
|
|
63
|
+
return @"default";
|
|
64
|
+
case FIRRemoteConfigSourceRemote:
|
|
65
|
+
return @"remote";
|
|
66
|
+
case FIRRemoteConfigSourceStatic:
|
|
67
|
+
return @"static";
|
|
68
|
+
default:
|
|
69
|
+
return @"unknown";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static NSString *convertFIRRemoteConfigUpdateErrorToNSString(FIRRemoteConfigUpdateError value) {
|
|
74
|
+
switch (value) {
|
|
75
|
+
case FIRRemoteConfigUpdateErrorStreamError:
|
|
76
|
+
return @"config_update_stream_error";
|
|
77
|
+
case FIRRemoteConfigUpdateErrorMessageInvalid:
|
|
78
|
+
return @"config_update_message_invalid";
|
|
79
|
+
case FIRRemoteConfigUpdateErrorNotFetched:
|
|
80
|
+
return @"config_update_not_fetched";
|
|
81
|
+
case FIRRemoteConfigUpdateErrorUnavailable:
|
|
82
|
+
return @"config_update_unavailable";
|
|
83
|
+
default:
|
|
84
|
+
return @"internal";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static NSDictionary *convertFIRRemoteConfigValueToNSDictionary(FIRRemoteConfigValue *value) {
|
|
89
|
+
return @{
|
|
90
|
+
@"value" : (id)value.stringValue ?: [NSNull null],
|
|
91
|
+
@"source" : convertFIRRemoteConfigSourceToNSString(value.source)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static FIRApp *firebaseAppForName(NSString *appName) {
|
|
96
|
+
return [RCTConvert firAppFromString:appName];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@implementation RNFBConfigHelper
|
|
100
|
+
|
|
101
|
+
+ (NSDictionary *)getConstantsForAppName:(NSString *)appName {
|
|
102
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
103
|
+
return [self getConstantsForApp:firebaseApp];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
+ (NSDictionary *)getConstantsForApp:(FIRApp *)firebaseApp {
|
|
107
|
+
FIRRemoteConfig *remoteConfig = [FIRRemoteConfig remoteConfigWithApp:firebaseApp];
|
|
108
|
+
|
|
109
|
+
NSDate *lastFetchTime = remoteConfig.lastFetchTime;
|
|
110
|
+
NSString *lastFetchStatus =
|
|
111
|
+
convertFIRRemoteConfigFetchStatusToNSString(remoteConfig.lastFetchStatus);
|
|
112
|
+
double minimumFetchInterval =
|
|
113
|
+
[RCTConvert double:@([remoteConfig configSettings].minimumFetchInterval)];
|
|
114
|
+
double fetchTimeout = [RCTConvert double:@([remoteConfig configSettings].fetchTimeout)];
|
|
115
|
+
|
|
116
|
+
NSMutableDictionary *values = [NSMutableDictionary new];
|
|
117
|
+
NSSet *keys = [[FIRRemoteConfig remoteConfigWithApp:firebaseApp] keysWithPrefix:nil];
|
|
118
|
+
for (NSString *key in keys) {
|
|
119
|
+
FIRRemoteConfigValue *value =
|
|
120
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] configValueForKey:key];
|
|
121
|
+
values[key] = convertFIRRemoteConfigValueToNSDictionary(value);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
NSArray *defaultKeys = [remoteConfig allKeysFromSource:FIRRemoteConfigSourceDefault];
|
|
125
|
+
for (NSString *key in defaultKeys) {
|
|
126
|
+
if ([values valueForKey:key] == nil) {
|
|
127
|
+
FIRRemoteConfigValue *value =
|
|
128
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] configValueForKey:key];
|
|
129
|
+
values[key] = convertFIRRemoteConfigValueToNSDictionary(value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return @{
|
|
134
|
+
@"values" : values,
|
|
135
|
+
@"lastFetchStatus" : lastFetchStatus,
|
|
136
|
+
@"lastFetchTime" : @(round([lastFetchTime timeIntervalSince1970] * 1000.0)),
|
|
137
|
+
@"minimumFetchInterval" : @(minimumFetchInterval),
|
|
138
|
+
@"fetchTimeout" : @(fetchTimeout)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
+ (NSDictionary *)resultWithConstants:(id)result firebaseApp:(FIRApp *)firebaseApp {
|
|
143
|
+
NSMutableDictionary *responseDict = [NSMutableDictionary new];
|
|
144
|
+
responseDict[@"result"] = result;
|
|
145
|
+
responseDict[@"constants"] = [self getConstantsForApp:firebaseApp];
|
|
146
|
+
return responseDict;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
+ (NSDictionary *)resultWithVoidConstantsForApp:(FIRApp *)firebaseApp {
|
|
150
|
+
NSMutableDictionary *responseDict = [NSMutableDictionary new];
|
|
151
|
+
responseDict[@"constants"] = [self getConstantsForApp:firebaseApp];
|
|
152
|
+
return responseDict;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
+ (void)ensureInitialized:(NSString *)appName
|
|
156
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
157
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
158
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
159
|
+
FIRRemoteConfigInitializationCompletion completionHandler = ^(NSError *__nullable error) {
|
|
160
|
+
if (error) {
|
|
161
|
+
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
162
|
+
} else {
|
|
163
|
+
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
168
|
+
ensureInitializedWithCompletionHandler:completionHandler];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
+ (void)fetch:(NSString *)appName
|
|
172
|
+
expirationDurationSeconds:(double)expirationDurationSeconds
|
|
173
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
174
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
175
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
176
|
+
FIRRemoteConfigFetchCompletion completionHandler =
|
|
177
|
+
^(FIRRemoteConfigFetchStatus status, NSError *__nullable error) {
|
|
178
|
+
if (error) {
|
|
179
|
+
[RNFBSharedUtils
|
|
180
|
+
rejectPromiseWithUserInfo:reject
|
|
181
|
+
userInfo:[@{
|
|
182
|
+
@"code" : convertFIRRemoteConfigFetchStatusToNSString(status),
|
|
183
|
+
@"message" :
|
|
184
|
+
convertFIRRemoteConfigFetchStatusToNSStringDescription(status)
|
|
185
|
+
} mutableCopy]];
|
|
186
|
+
} else {
|
|
187
|
+
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
if (expirationDurationSeconds == -1) {
|
|
192
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
193
|
+
fetchWithCompletionHandler:completionHandler];
|
|
194
|
+
} else {
|
|
195
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
196
|
+
fetchWithExpirationDuration:expirationDurationSeconds
|
|
197
|
+
completionHandler:completionHandler];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Shared by `activate:` and `fetchAndActivate:` below - resolves with the `changed` BOOL from
|
|
202
|
+
// `-[FIRRemoteConfig activateWithCompletion:]`, treating the SDK's "already activated" error as a
|
|
203
|
+
// non-error `false` result rather than a rejection, since it just means there was nothing new to
|
|
204
|
+
// activate.
|
|
205
|
+
+ (void)rnfb_activateRemoteConfig:(FIRApp *)firebaseApp
|
|
206
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
207
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
208
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] activateWithCompletion:^(
|
|
209
|
+
BOOL changed, NSError *_Nullable error) {
|
|
210
|
+
if (error) {
|
|
211
|
+
if (error.userInfo && error.userInfo[@"ActivationFailureReason"] != nil &&
|
|
212
|
+
[error.userInfo[@"ActivationFailureReason"] containsString:@"already activated"]) {
|
|
213
|
+
resolve([self resultWithConstants:@([RCTConvert BOOL:@(NO)]) firebaseApp:firebaseApp]);
|
|
214
|
+
} else {
|
|
215
|
+
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
resolve([self resultWithConstants:@([RCTConvert BOOL:@(changed)]) firebaseApp:firebaseApp]);
|
|
219
|
+
}
|
|
220
|
+
}];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
+ (void)fetchAndActivate:(NSString *)appName
|
|
224
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
225
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
226
|
+
// NOTE: We deliberately do not use `-[FIRRemoteConfig fetchAndActivateWithCompletionHandler:]`
|
|
227
|
+
// here. Its `FIRRemoteConfigFetchAndActivateStatus` result only reflects whether the fetch
|
|
228
|
+
// succeeded (`SuccessFetchedFromRemote`) vs fell back to previously fetched data
|
|
229
|
+
// (`SuccessUsingPreFetchedData`) - it does NOT reflect whether activation actually changed any
|
|
230
|
+
// config values, so it reports `SuccessFetchedFromRemote` (=> we'd resolve `true`) even when the
|
|
231
|
+
// fetched values are identical to what's already active. See
|
|
232
|
+
// https://github.com/invertase/react-native-firebase/issues/7779
|
|
233
|
+
//
|
|
234
|
+
// Instead we perform the fetch ourselves and hand off to the same activation + resolution logic
|
|
235
|
+
// `activate()` uses, so `fetchAndActivate()` resolves `true` only when activation changed the
|
|
236
|
+
// in-use config values - matching `activate()`'s own semantics as well as the Android
|
|
237
|
+
// implementation.
|
|
238
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
239
|
+
FIRRemoteConfigFetchCompletion fetchCompletion =
|
|
240
|
+
^(FIRRemoteConfigFetchStatus status, NSError *__nullable error) {
|
|
241
|
+
if (error) {
|
|
242
|
+
[RNFBSharedUtils
|
|
243
|
+
rejectPromiseWithUserInfo:reject
|
|
244
|
+
userInfo:[@{
|
|
245
|
+
@"code" : convertFIRRemoteConfigFetchStatusToNSString(status),
|
|
246
|
+
@"message" :
|
|
247
|
+
convertFIRRemoteConfigFetchStatusToNSStringDescription(status)
|
|
248
|
+
} mutableCopy]];
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
[self rnfb_activateRemoteConfig:firebaseApp resolve:resolve reject:reject];
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] fetchWithCompletionHandler:fetchCompletion];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
+ (void)activate:(NSString *)appName
|
|
259
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
260
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
261
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
262
|
+
[self rnfb_activateRemoteConfig:firebaseApp resolve:resolve reject:reject];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
+ (void)setConfigSettings:(NSString *)appName
|
|
266
|
+
minimumFetchInterval:(double)minimumFetchInterval
|
|
267
|
+
fetchTimeout:(double)fetchTimeout
|
|
268
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
269
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
270
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
271
|
+
FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] init];
|
|
272
|
+
remoteConfigSettings.minimumFetchInterval = minimumFetchInterval;
|
|
273
|
+
remoteConfigSettings.fetchTimeout = fetchTimeout;
|
|
274
|
+
|
|
275
|
+
[FIRRemoteConfig remoteConfigWithApp:firebaseApp].configSettings = remoteConfigSettings;
|
|
276
|
+
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
+ (void)setDefaults:(NSString *)appName
|
|
280
|
+
defaults:(NSDictionary *)defaults
|
|
281
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
282
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
283
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
284
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] setDefaults:defaults];
|
|
285
|
+
resolve([self resultWithConstants:[NSNull null] firebaseApp:firebaseApp]);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
+ (void)setDefaultsFromResource:(NSString *)appName
|
|
289
|
+
resourceName:(NSString *)resourceName
|
|
290
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
291
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
292
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
293
|
+
if ([[NSBundle mainBundle] pathForResource:resourceName ofType:@"plist"] != nil) {
|
|
294
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] setDefaultsFromPlistFileName:resourceName];
|
|
295
|
+
resolve([self resultWithConstants:[NSNull null] firebaseApp:firebaseApp]);
|
|
296
|
+
} else {
|
|
297
|
+
[RNFBSharedUtils rejectPromiseWithUserInfo:reject
|
|
298
|
+
userInfo:[@{
|
|
299
|
+
@"code" : @"resource_not_found",
|
|
300
|
+
@"message" : @"The specified resource name was not found."
|
|
301
|
+
} mutableCopy]];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
+ (void)reset:(NSString *)appName
|
|
306
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
307
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
308
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
309
|
+
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
+ (void)onConfigUpdated:(NSString *)appName {
|
|
313
|
+
static dispatch_once_t onceToken;
|
|
314
|
+
dispatch_once(&onceToken, ^{
|
|
315
|
+
configUpdateHandlers = [[NSMutableDictionary alloc] init];
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
319
|
+
if (![configUpdateHandlers valueForKey:firebaseApp.name]) {
|
|
320
|
+
FIRConfigUpdateListenerRegistration *newRegistration =
|
|
321
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
322
|
+
addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nonnull configUpdate,
|
|
323
|
+
NSError *_Nullable error) {
|
|
324
|
+
if (error != nil) {
|
|
325
|
+
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
|
326
|
+
|
|
327
|
+
[userInfo setValue:@"error" forKey:@"resultType"];
|
|
328
|
+
[userInfo setValue:convertFIRRemoteConfigUpdateErrorToNSString(
|
|
329
|
+
(FIRRemoteConfigUpdateError)error.code)
|
|
330
|
+
forKey:@"code"];
|
|
331
|
+
[userInfo setValue:error.localizedDescription forKey:@"message"];
|
|
332
|
+
[userInfo setValue:error.localizedDescription forKey:@"nativeErrorMessage"];
|
|
333
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
334
|
+
name:ON_CONFIG_UPDATED_EVENT
|
|
335
|
+
body:userInfo];
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
NSMutableDictionary *results = [NSMutableDictionary dictionary];
|
|
340
|
+
|
|
341
|
+
[results setValue:@"success" forKey:@"resultType"];
|
|
342
|
+
[results setValue:[configUpdate.updatedKeys allObjects] forKey:@"updatedKeys"];
|
|
343
|
+
|
|
344
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
345
|
+
name:ON_CONFIG_UPDATED_EVENT
|
|
346
|
+
body:results];
|
|
347
|
+
}];
|
|
348
|
+
|
|
349
|
+
configUpdateHandlers[firebaseApp.name] = newRegistration;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
+ (void)removeConfigUpdateRegistration:(NSString *)appName {
|
|
354
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
355
|
+
if ([configUpdateHandlers valueForKey:firebaseApp.name]) {
|
|
356
|
+
[[configUpdateHandlers objectForKey:firebaseApp.name] remove];
|
|
357
|
+
[configUpdateHandlers removeObjectForKey:firebaseApp.name];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
+ (void)removeAllConfigUpdateRegistrations {
|
|
362
|
+
for (NSString *key in [configUpdateHandlers allKeys]) {
|
|
363
|
+
FIRConfigUpdateListenerRegistration *registration = [configUpdateHandlers objectForKey:key];
|
|
364
|
+
[registration remove];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
[configUpdateHandlers removeAllObjects];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
+ (void)setCustomSignals:(NSString *)appName
|
|
371
|
+
customSignals:(NSDictionary *)customSignals
|
|
372
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
373
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
374
|
+
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
375
|
+
NSDictionary *decodedCustomSignals = [RNFBSharedUtils decodeNullSentinels:customSignals];
|
|
376
|
+
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
377
|
+
setCustomSignals:decodedCustomSignals
|
|
378
|
+
withCompletion:^(NSError *_Nullable error) {
|
|
379
|
+
if (error != nil) {
|
|
380
|
+
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
381
|
+
} else {
|
|
382
|
+
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
383
|
+
}
|
|
384
|
+
}];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
@end
|
|
@@ -15,85 +15,11 @@
|
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
#import <Firebase/Firebase.h>
|
|
19
|
-
#import <React/RCTConvert.h>
|
|
20
|
-
|
|
21
|
-
#import "RNFBApp/RCTConvert+FIRApp.h"
|
|
22
|
-
#import "RNFBApp/RNFBSharedUtils.h"
|
|
23
18
|
#import "RNFBConfigModule.h"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
static __strong NSMutableDictionary *configUpdateHandlers;
|
|
19
|
+
#import "RNFBApp/RNFBSharedUtils.h"
|
|
20
|
+
#import "RNFBConfigHelper.h"
|
|
28
21
|
|
|
29
22
|
@implementation RNFBConfigModule
|
|
30
|
-
#pragma mark -
|
|
31
|
-
#pragma mark Converters
|
|
32
|
-
|
|
33
|
-
NSString *convertFIRRemoteConfigFetchStatusToNSString(FIRRemoteConfigFetchStatus value) {
|
|
34
|
-
switch (value) {
|
|
35
|
-
case FIRRemoteConfigFetchStatusNoFetchYet:
|
|
36
|
-
return @"no_fetch_yet";
|
|
37
|
-
case FIRRemoteConfigFetchStatusSuccess:
|
|
38
|
-
return @"success";
|
|
39
|
-
case FIRRemoteConfigFetchStatusThrottled:
|
|
40
|
-
return @"throttled";
|
|
41
|
-
case FIRRemoteConfigFetchStatusFailure:
|
|
42
|
-
return @"failure";
|
|
43
|
-
default:
|
|
44
|
-
return @"unknown";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
NSString *convertFIRRemoteConfigFetchStatusToNSStringDescription(FIRRemoteConfigFetchStatus value) {
|
|
49
|
-
switch (value) {
|
|
50
|
-
case FIRRemoteConfigFetchStatusThrottled:
|
|
51
|
-
return @"fetch() operation cannot be completed successfully, due to throttling.";
|
|
52
|
-
case FIRRemoteConfigFetchStatusNoFetchYet:
|
|
53
|
-
default:
|
|
54
|
-
return @"fetch() operation cannot be completed successfully.";
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
NSString *convertFIRRemoteConfigSourceToNSString(FIRRemoteConfigSource value) {
|
|
59
|
-
switch (value) {
|
|
60
|
-
case FIRRemoteConfigSourceDefault:
|
|
61
|
-
return @"default";
|
|
62
|
-
case FIRRemoteConfigSourceRemote:
|
|
63
|
-
return @"remote";
|
|
64
|
-
case FIRRemoteConfigSourceStatic:
|
|
65
|
-
return @"static";
|
|
66
|
-
default:
|
|
67
|
-
return @"unknown";
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
NSString *convertFIRRemoteConfigUpdateErrorToNSString(FIRRemoteConfigUpdateError value) {
|
|
72
|
-
switch (value) {
|
|
73
|
-
case FIRRemoteConfigUpdateErrorStreamError:
|
|
74
|
-
return @"config_update_stream_error";
|
|
75
|
-
case FIRRemoteConfigUpdateErrorMessageInvalid:
|
|
76
|
-
return @"config_update_message_invalid";
|
|
77
|
-
case FIRRemoteConfigUpdateErrorNotFetched:
|
|
78
|
-
return @"config_update_not_fetched";
|
|
79
|
-
case FIRRemoteConfigUpdateErrorUnavailable:
|
|
80
|
-
return @"config_update_unavailable";
|
|
81
|
-
default:
|
|
82
|
-
return @"internal";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
NSDictionary *convertFIRRemoteConfigValueToNSDictionary(FIRRemoteConfigValue *value) {
|
|
87
|
-
return @{
|
|
88
|
-
@"value" : (id)value.stringValue ?: [NSNull null],
|
|
89
|
-
@"source" : convertFIRRemoteConfigSourceToNSString(value.source)
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
static FIRApp *firebaseAppForName(NSString *appName) {
|
|
94
|
-
return [RCTConvert firAppFromString:appName];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
23
|
#pragma mark -
|
|
98
24
|
#pragma mark Module Setup
|
|
99
25
|
|
|
@@ -103,24 +29,8 @@ RCT_EXPORT_MODULE(NativeRNFBTurboConfig)
|
|
|
103
29
|
return NO;
|
|
104
30
|
}
|
|
105
31
|
|
|
106
|
-
- (instancetype)init {
|
|
107
|
-
self = [super init];
|
|
108
|
-
if (self) {
|
|
109
|
-
static dispatch_once_t onceToken;
|
|
110
|
-
dispatch_once(&onceToken, ^{
|
|
111
|
-
configUpdateHandlers = [[NSMutableDictionary alloc] init];
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
return self;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
32
|
- (void)invalidate {
|
|
118
|
-
|
|
119
|
-
FIRConfigUpdateListenerRegistration *registration = [configUpdateHandlers objectForKey:key];
|
|
120
|
-
[registration remove];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
[configUpdateHandlers removeAllObjects];
|
|
33
|
+
[RNFBConfigHelper removeAllConfigUpdateRegistrations];
|
|
124
34
|
}
|
|
125
35
|
|
|
126
36
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
@@ -131,8 +41,7 @@ RCT_EXPORT_MODULE(NativeRNFBTurboConfig)
|
|
|
131
41
|
- (facebook::react::ModuleConstants<JS::NativeRNFBTurboConfig::Constants::Builder>)
|
|
132
42
|
constantsToExport {
|
|
133
43
|
return [_RCTTypedModuleConstants
|
|
134
|
-
newWithUnsafeDictionary:[
|
|
135
|
-
getConstantsForApp:firebaseAppForName(DEFAULT_APP_DISPLAY_NAME)]];
|
|
44
|
+
newWithUnsafeDictionary:[RNFBConfigHelper getConstantsForAppName:DEFAULT_APP_DISPLAY_NAME]];
|
|
136
45
|
}
|
|
137
46
|
|
|
138
47
|
- (facebook::react::ModuleConstants<JS::NativeRNFBTurboConfig::Constants::Builder>)getConstants {
|
|
@@ -145,276 +54,81 @@ RCT_EXPORT_MODULE(NativeRNFBTurboConfig)
|
|
|
145
54
|
- (void)ensureInitialized:(NSString *)appName
|
|
146
55
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
147
56
|
reject:(RCTPromiseRejectBlock)reject {
|
|
148
|
-
|
|
149
|
-
FIRRemoteConfigInitializationCompletion completionHandler = ^(NSError *__nullable error) {
|
|
150
|
-
if (error) {
|
|
151
|
-
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
152
|
-
} else {
|
|
153
|
-
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
158
|
-
ensureInitializedWithCompletionHandler:completionHandler];
|
|
57
|
+
[RNFBConfigHelper ensureInitialized:appName resolve:resolve reject:reject];
|
|
159
58
|
}
|
|
160
59
|
|
|
161
60
|
- (void)fetch:(NSString *)appName
|
|
162
61
|
expirationDurationSeconds:(double)expirationDurationSeconds
|
|
163
62
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
164
63
|
reject:(RCTPromiseRejectBlock)reject {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
[RNFBSharedUtils
|
|
170
|
-
rejectPromiseWithUserInfo:reject
|
|
171
|
-
userInfo:[@{
|
|
172
|
-
@"code" : convertFIRRemoteConfigFetchStatusToNSString(status),
|
|
173
|
-
@"message" :
|
|
174
|
-
convertFIRRemoteConfigFetchStatusToNSStringDescription(status)
|
|
175
|
-
} mutableCopy]];
|
|
176
|
-
} else {
|
|
177
|
-
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
if (expirationDurationSeconds == -1) {
|
|
182
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
183
|
-
fetchWithCompletionHandler:completionHandler];
|
|
184
|
-
} else {
|
|
185
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
186
|
-
fetchWithExpirationDuration:expirationDurationSeconds
|
|
187
|
-
completionHandler:completionHandler];
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Shared by `activate:` and `fetchAndActivate:` below - resolves with the `changed` BOOL from
|
|
192
|
-
// `-[FIRRemoteConfig activateWithCompletion:]`, treating the SDK's "already activated" error as a
|
|
193
|
-
// non-error `false` result rather than a rejection, since it just means there was nothing new to
|
|
194
|
-
// activate.
|
|
195
|
-
- (void)rnfb_activateRemoteConfig:(FIRApp *)firebaseApp
|
|
196
|
-
resolve:(RCTPromiseResolveBlock)resolve
|
|
197
|
-
reject:(RCTPromiseRejectBlock)reject {
|
|
198
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] activateWithCompletion:^(
|
|
199
|
-
BOOL changed, NSError *_Nullable error) {
|
|
200
|
-
if (error) {
|
|
201
|
-
if (error.userInfo && error.userInfo[@"ActivationFailureReason"] != nil &&
|
|
202
|
-
[error.userInfo[@"ActivationFailureReason"] containsString:@"already activated"]) {
|
|
203
|
-
resolve([self resultWithConstants:@([RCTConvert BOOL:@(NO)]) firebaseApp:firebaseApp]);
|
|
204
|
-
} else {
|
|
205
|
-
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
resolve([self resultWithConstants:@([RCTConvert BOOL:@(changed)]) firebaseApp:firebaseApp]);
|
|
209
|
-
}
|
|
210
|
-
}];
|
|
64
|
+
[RNFBConfigHelper fetch:appName
|
|
65
|
+
expirationDurationSeconds:expirationDurationSeconds
|
|
66
|
+
resolve:resolve
|
|
67
|
+
reject:reject];
|
|
211
68
|
}
|
|
212
69
|
|
|
213
70
|
- (void)fetchAndActivate:(NSString *)appName
|
|
214
71
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
215
72
|
reject:(RCTPromiseRejectBlock)reject {
|
|
216
|
-
|
|
217
|
-
// here. Its `FIRRemoteConfigFetchAndActivateStatus` result only reflects whether the fetch
|
|
218
|
-
// succeeded (`SuccessFetchedFromRemote`) vs fell back to previously fetched data
|
|
219
|
-
// (`SuccessUsingPreFetchedData`) - it does NOT reflect whether activation actually changed any
|
|
220
|
-
// config values, so it reports `SuccessFetchedFromRemote` (=> we'd resolve `true`) even when the
|
|
221
|
-
// fetched values are identical to what's already active. See
|
|
222
|
-
// https://github.com/invertase/react-native-firebase/issues/7779
|
|
223
|
-
//
|
|
224
|
-
// Instead we perform the fetch ourselves and hand off to the same activation + resolution logic
|
|
225
|
-
// `activate()` uses, so `fetchAndActivate()` resolves `true` only when activation changed the
|
|
226
|
-
// in-use config values - matching `activate()`'s own semantics as well as the Android
|
|
227
|
-
// implementation.
|
|
228
|
-
FIRApp *firebaseApp = firebaseAppForName(appName);
|
|
229
|
-
__weak RNFBConfigModule *weakSelf = self;
|
|
230
|
-
FIRRemoteConfigFetchCompletion fetchCompletion =
|
|
231
|
-
^(FIRRemoteConfigFetchStatus status, NSError *__nullable error) {
|
|
232
|
-
RNFBConfigModule *strongSelf = weakSelf;
|
|
233
|
-
if (!strongSelf) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (error) {
|
|
238
|
-
[RNFBSharedUtils
|
|
239
|
-
rejectPromiseWithUserInfo:reject
|
|
240
|
-
userInfo:[@{
|
|
241
|
-
@"code" : convertFIRRemoteConfigFetchStatusToNSString(status),
|
|
242
|
-
@"message" :
|
|
243
|
-
convertFIRRemoteConfigFetchStatusToNSStringDescription(status)
|
|
244
|
-
} mutableCopy]];
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
[strongSelf rnfb_activateRemoteConfig:firebaseApp resolve:resolve reject:reject];
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] fetchWithCompletionHandler:fetchCompletion];
|
|
73
|
+
[RNFBConfigHelper fetchAndActivate:appName resolve:resolve reject:reject];
|
|
252
74
|
}
|
|
253
75
|
|
|
254
76
|
- (void)activate:(NSString *)appName
|
|
255
77
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
256
78
|
reject:(RCTPromiseRejectBlock)reject {
|
|
257
|
-
|
|
258
|
-
[self rnfb_activateRemoteConfig:firebaseApp resolve:resolve reject:reject];
|
|
79
|
+
[RNFBConfigHelper activate:appName resolve:resolve reject:reject];
|
|
259
80
|
}
|
|
260
81
|
|
|
261
82
|
- (void)setConfigSettings:(NSString *)appName
|
|
262
83
|
settings:(JS::NativeRNFBTurboConfig::ConfigSettings &)configSettings
|
|
263
84
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
264
85
|
reject:(RCTPromiseRejectBlock)reject {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
[FIRRemoteConfig remoteConfigWithApp:firebaseApp].configSettings = remoteConfigSettings;
|
|
271
|
-
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
86
|
+
[RNFBConfigHelper setConfigSettings:appName
|
|
87
|
+
minimumFetchInterval:configSettings.minimumFetchInterval()
|
|
88
|
+
fetchTimeout:configSettings.fetchTimeout()
|
|
89
|
+
resolve:resolve
|
|
90
|
+
reject:reject];
|
|
272
91
|
}
|
|
273
92
|
|
|
274
93
|
- (void)setDefaults:(NSString *)appName
|
|
275
94
|
defaults:(NSDictionary *)defaults
|
|
276
95
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
277
96
|
reject:(RCTPromiseRejectBlock)reject {
|
|
278
|
-
|
|
279
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] setDefaults:defaults];
|
|
280
|
-
resolve([self resultWithConstants:[NSNull null] firebaseApp:firebaseApp]);
|
|
97
|
+
[RNFBConfigHelper setDefaults:appName defaults:defaults resolve:resolve reject:reject];
|
|
281
98
|
}
|
|
282
99
|
|
|
283
100
|
- (void)setDefaultsFromResource:(NSString *)appName
|
|
284
101
|
resourceName:(NSString *)resourceName
|
|
285
102
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
286
103
|
reject:(RCTPromiseRejectBlock)reject {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
} else {
|
|
292
|
-
[RNFBSharedUtils rejectPromiseWithUserInfo:reject
|
|
293
|
-
userInfo:[@{
|
|
294
|
-
@"code" : @"resource_not_found",
|
|
295
|
-
@"message" : @"The specified resource name was not found."
|
|
296
|
-
} mutableCopy]];
|
|
297
|
-
}
|
|
104
|
+
[RNFBConfigHelper setDefaultsFromResource:appName
|
|
105
|
+
resourceName:resourceName
|
|
106
|
+
resolve:resolve
|
|
107
|
+
reject:reject];
|
|
298
108
|
}
|
|
299
109
|
|
|
300
110
|
- (void)reset:(NSString *)appName
|
|
301
111
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
302
112
|
reject:(RCTPromiseRejectBlock)reject {
|
|
303
|
-
|
|
304
|
-
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
113
|
+
[RNFBConfigHelper reset:appName resolve:resolve reject:reject];
|
|
305
114
|
}
|
|
306
115
|
|
|
307
116
|
- (void)onConfigUpdated:(NSString *)appName {
|
|
308
|
-
|
|
309
|
-
if (![configUpdateHandlers valueForKey:firebaseApp.name]) {
|
|
310
|
-
FIRConfigUpdateListenerRegistration *newRegistration =
|
|
311
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
|
|
312
|
-
addOnConfigUpdateListener:^(FIRRemoteConfigUpdate *_Nonnull configUpdate,
|
|
313
|
-
NSError *_Nullable error) {
|
|
314
|
-
if (error != nil) {
|
|
315
|
-
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
|
316
|
-
|
|
317
|
-
[userInfo setValue:@"error" forKey:@"resultType"];
|
|
318
|
-
[userInfo setValue:convertFIRRemoteConfigUpdateErrorToNSString(
|
|
319
|
-
(FIRRemoteConfigUpdateError)error.code)
|
|
320
|
-
forKey:@"code"];
|
|
321
|
-
[userInfo setValue:error.localizedDescription forKey:@"message"];
|
|
322
|
-
[userInfo setValue:error.localizedDescription forKey:@"nativeErrorMessage"];
|
|
323
|
-
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
324
|
-
name:ON_CONFIG_UPDATED_EVENT
|
|
325
|
-
body:userInfo];
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
NSMutableDictionary *results = [NSMutableDictionary dictionary];
|
|
330
|
-
|
|
331
|
-
[results setValue:@"success" forKey:@"resultType"];
|
|
332
|
-
[results setValue:[configUpdate.updatedKeys allObjects] forKey:@"updatedKeys"];
|
|
333
|
-
|
|
334
|
-
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
335
|
-
name:ON_CONFIG_UPDATED_EVENT
|
|
336
|
-
body:results];
|
|
337
|
-
}];
|
|
338
|
-
|
|
339
|
-
configUpdateHandlers[firebaseApp.name] = newRegistration;
|
|
340
|
-
}
|
|
117
|
+
[RNFBConfigHelper onConfigUpdated:appName];
|
|
341
118
|
}
|
|
342
119
|
|
|
343
120
|
- (void)removeConfigUpdateRegistration:(NSString *)appName {
|
|
344
|
-
|
|
345
|
-
if ([configUpdateHandlers valueForKey:firebaseApp.name]) {
|
|
346
|
-
[[configUpdateHandlers objectForKey:firebaseApp.name] remove];
|
|
347
|
-
[configUpdateHandlers removeObjectForKey:firebaseApp.name];
|
|
348
|
-
}
|
|
121
|
+
[RNFBConfigHelper removeConfigUpdateRegistration:appName];
|
|
349
122
|
}
|
|
350
123
|
|
|
351
124
|
- (void)setCustomSignals:(NSString *)appName
|
|
352
125
|
customSignals:(NSDictionary *)customSignals
|
|
353
126
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
354
127
|
reject:(RCTPromiseRejectBlock)reject {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
withCompletion:^(NSError *_Nullable error) {
|
|
360
|
-
if (error != nil) {
|
|
361
|
-
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
|
|
362
|
-
} else {
|
|
363
|
-
resolve([self resultWithVoidConstantsForApp:firebaseApp]);
|
|
364
|
-
}
|
|
365
|
-
}];
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
#pragma mark -
|
|
369
|
-
#pragma mark Internal Helper Methods
|
|
370
|
-
|
|
371
|
-
- (NSDictionary *)resultWithConstants:(id)result firebaseApp:(FIRApp *)firebaseApp {
|
|
372
|
-
NSMutableDictionary *responseDict = [NSMutableDictionary new];
|
|
373
|
-
responseDict[@"result"] = result;
|
|
374
|
-
responseDict[@"constants"] = [self getConstantsForApp:firebaseApp];
|
|
375
|
-
return responseDict;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
- (NSDictionary *)resultWithVoidConstantsForApp:(FIRApp *)firebaseApp {
|
|
379
|
-
NSMutableDictionary *responseDict = [NSMutableDictionary new];
|
|
380
|
-
responseDict[@"constants"] = [self getConstantsForApp:firebaseApp];
|
|
381
|
-
return responseDict;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
- (NSDictionary *)getConstantsForApp:(FIRApp *)firebaseApp {
|
|
385
|
-
FIRRemoteConfig *remoteConfig = [FIRRemoteConfig remoteConfigWithApp:firebaseApp];
|
|
386
|
-
|
|
387
|
-
NSDate *lastFetchTime = remoteConfig.lastFetchTime;
|
|
388
|
-
NSString *lastFetchStatus =
|
|
389
|
-
convertFIRRemoteConfigFetchStatusToNSString(remoteConfig.lastFetchStatus);
|
|
390
|
-
double minimumFetchInterval =
|
|
391
|
-
[RCTConvert double:@([remoteConfig configSettings].minimumFetchInterval)];
|
|
392
|
-
double fetchTimeout = [RCTConvert double:@([remoteConfig configSettings].fetchTimeout)];
|
|
393
|
-
|
|
394
|
-
NSMutableDictionary *values = [NSMutableDictionary new];
|
|
395
|
-
NSSet *keys = [[FIRRemoteConfig remoteConfigWithApp:firebaseApp] keysWithPrefix:nil];
|
|
396
|
-
for (NSString *key in keys) {
|
|
397
|
-
FIRRemoteConfigValue *value =
|
|
398
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] configValueForKey:key];
|
|
399
|
-
values[key] = convertFIRRemoteConfigValueToNSDictionary(value);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
NSArray *defaultKeys = [remoteConfig allKeysFromSource:FIRRemoteConfigSourceDefault];
|
|
403
|
-
for (NSString *key in defaultKeys) {
|
|
404
|
-
if ([values valueForKey:key] == nil) {
|
|
405
|
-
FIRRemoteConfigValue *value =
|
|
406
|
-
[[FIRRemoteConfig remoteConfigWithApp:firebaseApp] configValueForKey:key];
|
|
407
|
-
values[key] = convertFIRRemoteConfigValueToNSDictionary(value);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return @{
|
|
412
|
-
@"values" : values,
|
|
413
|
-
@"lastFetchStatus" : lastFetchStatus,
|
|
414
|
-
@"lastFetchTime" : @(round([lastFetchTime timeIntervalSince1970] * 1000.0)),
|
|
415
|
-
@"minimumFetchInterval" : @(minimumFetchInterval),
|
|
416
|
-
@"fetchTimeout" : @(fetchTimeout)
|
|
417
|
-
};
|
|
128
|
+
[RNFBConfigHelper setCustomSignals:appName
|
|
129
|
+
customSignals:customSignals
|
|
130
|
+
resolve:resolve
|
|
131
|
+
reject:reject];
|
|
418
132
|
}
|
|
419
133
|
|
|
420
134
|
@end
|
package/lib/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '26.
|
|
2
|
+
export const version = '26.2.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-firebase/remote-config",
|
|
3
|
-
"version": "26.
|
|
3
|
+
"version": "26.2.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",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"compile": "bob build",
|
|
26
26
|
"prepare": "yarn run build && yarn compile",
|
|
27
27
|
"codegen": "yarn android:codegen && yarn ios:codegen",
|
|
28
|
-
"android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/config/generated",
|
|
29
|
-
"ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated"
|
|
28
|
+
"android:codegen": "rimraf android/src/reactnative/java/io/invertase/firebase/config/generated && npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/config/generated",
|
|
29
|
+
"ios:codegen": "rimraf ios/generated && npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"remote-config"
|
|
43
43
|
],
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@react-native-firebase/analytics": "26.
|
|
46
|
-
"@react-native-firebase/app": "26.
|
|
45
|
+
"@react-native-firebase/analytics": "26.2.0",
|
|
46
|
+
"@react-native-firebase/app": "26.2.0"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"web-streams-polyfill": "^4.2.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@react-native-firebase/app": "26.
|
|
58
|
+
"@react-native-firebase/app": "26.2.0",
|
|
59
59
|
"@types/text-encoding": "^0.0.40",
|
|
60
60
|
"react-native-builder-bob": "^0.41.0",
|
|
61
61
|
"typescript": "^6.0.3"
|
|
@@ -90,5 +90,5 @@
|
|
|
90
90
|
"node_modules/",
|
|
91
91
|
"dist/"
|
|
92
92
|
],
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "b7efa8ca2781b5102975ee5169ee6fc52e9c1588"
|
|
94
94
|
}
|