@@ -213,8 +213,9 @@ @interface InternalCallBackHandler: NSObject
213213 *
214214 * @param transactionID is the transaction ID to use for the fetch
215215 * @param channel is the FlutterMethodChannel to use any callback to Flutter or nil if not required
216+ * @param configEpoch is the configuration epoch that the fetch was made within
216217 */
217- - (nullable instancetype )initWithTransactionID : (NSString *)transactionID channel : (FlutterMethodChannel *)channel ;
218+ - (nullable instancetype )initWithTransactionID : (NSString *)transactionID channel : (FlutterMethodChannel *)channel configEpoch : ( int ) configEpoch ;
218219
219220/* *
220221 * Provides string mappings for the token fetch status with strings that are compatible with the common dart layer. This
@@ -245,6 +246,9 @@ - (NSDictionary *)getResult;
245246// FlutterMethodChannel to use for any callback to Flutter or nil if no callback is needed
246247@property FlutterMethodChannel *channel;
247248
249+ // configuration epoch that the fetch was made within
250+ @property int configEpoch;
251+
248252// Dispatch group to indicate when the fetch is complete
249253@property dispatch_group_t group;
250254
@@ -258,12 +262,13 @@ - (NSDictionary *)getResult;
258262@implementation InternalCallBackHandler
259263
260264// see interface for documentation
261- - (nullable instancetype )initWithTransactionID : (NSString *)transactionID channel : (FlutterMethodChannel *)channel
265+ - (nullable instancetype )initWithTransactionID : (NSString *)transactionID channel : (FlutterMethodChannel *)channel configEpoch : ( int ) configEpoch
262266{
263267 self = [super init ];
264268 if (self) {
265269 _transactionID = transactionID;
266270 _channel = channel;
271+ _configEpoch = configEpoch;
267272 _group = dispatch_group_create ();
268273 _results = [NSMutableDictionary dictionary ];
269274 dispatch_group_enter (_group);
@@ -330,6 +335,7 @@ - (void)postWithTokenFetchResult:(ApproovTokenFetchResult *_Nonnull)tokenFetchRe
330335 _results[@" MeasurementConfig" ] = tokenFetchResult.measurementConfig ;
331336 if (tokenFetchResult.loggableToken != nil )
332337 _results[@" LoggableToken" ] = tokenFetchResult.loggableToken ;
338+ _results[@" ConfigEpoch" ] = [NSNumber numberWithInt: _configEpoch];
333339
334340 // leave the dispatch group to indicate that the results are available
335341 dispatch_group_leave (_group);
@@ -367,6 +373,11 @@ @interface ApproovHttpClientPlugin()
367373// Provides any prior initial comment supplied, or empty string if none was provided
368374@property NSString *initializedComment;
369375
376+ // Counter for the configuration epoch that is incremented whenever the configuration is fetched. This keeps
377+ // track of dynamic configuration changes and the state is held in the platform layer as we want this to work
378+ // across multiple different isolates which have independent Dart level state.
379+ @property int configEpoch;
380+
370381// Active set of callback handlers to the Approov SDK - accessess to this must be protected as it could be
371382// accessed from multiple threads
372383@property NSMutableDictionary <NSString*, InternalCallBackHandler*> *activeCallBackHandlers;
@@ -398,6 +409,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
398409 [registrar addMethodCallDelegate: instance channel: fgChannel];
399410 instance.bgChannel = bgChannel;
400411 [registrar addMethodCallDelegate: instance channel: bgChannel];
412+ instance.configEpoch = 0 ;
401413 instance.activeCallBackHandlers = [NSMutableDictionary dictionary ];
402414 instance.activeCertFetches = [NSMutableDictionary dictionary ];
403415}
@@ -445,7 +457,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
445457 result (nil );
446458 }
447459 } else if ([@" fetchConfig" isEqualToString: call.method]) {
460+ _configEpoch++;
448461 result ([Approov fetchConfig ]);
462+ } else if ([@" getConfigEpoch" isEqualToString: call.method]) {
463+ result ([NSNumber numberWithInt: _configEpoch]);
449464 } else if ([@" getDeviceID" isEqualToString: call.method]) {
450465 result ([Approov getDeviceID ]);
451466 } else if ([@" getPins" isEqualToString: call.method]) {
@@ -504,7 +519,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
504519 NSString *transactionID = call.arguments [@" transactionID" ];
505520 BOOL performCallBack = [call.arguments[@" performCallBack" ] isEqualToString: @" YES" ];
506521 InternalCallBackHandler *callBackHandler = [[InternalCallBackHandler alloc ] initWithTransactionID: transactionID
507- channel: (performCallBack ? _fgChannel : nil )];
522+ channel: (performCallBack ? _fgChannel : nil ) configEpoch: _configEpoch ];
508523 [Approov fetchApproovToken: ^(ApproovTokenFetchResult *tokenFetchResult) {
509524 [callBackHandler postWithTokenFetchResult: tokenFetchResult];
510525 } :call.arguments[@" url" ]];
@@ -521,7 +536,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
521536 newDef = call.arguments [@" newDef" ];
522537 BOOL performCallBack = [call.arguments[@" performCallBack" ] isEqualToString: @" YES" ];
523538 InternalCallBackHandler *callBackHandler = [[InternalCallBackHandler alloc ] initWithTransactionID: transactionID
524- channel: (performCallBack ? _fgChannel : nil )];
539+ channel: (performCallBack ? _fgChannel : nil ) configEpoch: _configEpoch ];
525540 [Approov fetchSecureString: ^(ApproovTokenFetchResult *tokenFetchResult) {
526541 [callBackHandler postWithTokenFetchResult: tokenFetchResult];
527542 } :call.arguments[@" key" ] :newDef];
@@ -535,7 +550,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
535550 NSString *transactionID = call.arguments [@" transactionID" ];
536551 BOOL performCallBack = [call.arguments[@" performCallBack" ] isEqualToString: @" YES" ];
537552 InternalCallBackHandler *callBackHandler = [[InternalCallBackHandler alloc ] initWithTransactionID: transactionID
538- channel: (performCallBack ? _fgChannel : nil )];
553+ channel: (performCallBack ? _fgChannel : nil ) configEpoch: _configEpoch ];
539554 [Approov fetchCustomJWT: ^(ApproovTokenFetchResult *tokenFetchResult) {
540555 [callBackHandler postWithTokenFetchResult: tokenFetchResult];
541556 } :call.arguments[@" payload" ]];
0 commit comments