diff --git a/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/FirebaseRemoteConfigPlugin.java b/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/FirebaseRemoteConfigPlugin.java index a0d38488b1bf..30a0de0e6cd4 100644 --- a/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/FirebaseRemoteConfigPlugin.java +++ b/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/FirebaseRemoteConfigPlugin.java @@ -14,6 +14,7 @@ import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException; import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException; import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue; import io.flutter.Log; @@ -188,6 +189,18 @@ public void onMethodCall(MethodCall call, @NonNull final MethodChannel.Result re } else if (exception instanceof FirebaseRemoteConfigClientException) { details.put("code", "internal"); details.put("message", "internal remote config fetch error"); + } else if (exception instanceof FirebaseRemoteConfigServerException) { + details.put("code", "remote-config-server-error"); + details.put("message", exception.getMessage()); + + Throwable cause = exception.getCause(); + if (cause != null) { + String causeMessage = cause.getMessage(); + if (causeMessage != null && causeMessage.contains("Forbidden")) { + // Specific error code for 403 status code to indicate the request was forbidden. + details.put("code", "forbidden"); + } + } } else { details.put("code", "unknown"); details.put("message", "unknown remote config error"); diff --git a/packages/firebase_remote_config/firebase_remote_config/ios/Classes/FLTFirebaseRemoteConfigUtils.m b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/FLTFirebaseRemoteConfigUtils.m index a69b3de5429e..982761c279af 100644 --- a/packages/firebase_remote_config/firebase_remote_config/ios/Classes/FLTFirebaseRemoteConfigUtils.m +++ b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/FLTFirebaseRemoteConfigUtils.m @@ -11,8 +11,18 @@ + (NSDictionary *)ErrorCodeAndMessageFromNSError:(NSError *)error { NSMutableDictionary *codeAndMessage = [[NSMutableDictionary alloc] init]; switch (error.code) { case FIRRemoteConfigErrorInternalError: - [codeAndMessage setValue:@"internal" forKey:@"code"]; - [codeAndMessage setValue:error.userInfo[NSLocalizedDescriptionKey] forKey:@"message"]; + if ([error.userInfo[NSLocalizedDescriptionKey] containsString:@"403"]) { + // See PR for details: https://github.com/firebase/flutterfire/pull/9629 + [codeAndMessage setValue:@"forbidden" forKey:@"code"]; + NSString *updateMessage = + [NSString stringWithFormat:@"%@%@", error.userInfo[NSLocalizedDescriptionKey], + @". You may have to enable the Remote Config API on Google " + @"Cloud Platform for your Firebase project."]; + [codeAndMessage setValue:updateMessage forKey:@"message"]; + } else { + [codeAndMessage setValue:@"internal" forKey:@"code"]; + [codeAndMessage setValue:error.userInfo[NSLocalizedDescriptionKey] forKey:@"message"]; + } break; case FIRRemoteConfigErrorThrottled: [codeAndMessage setValue:@"throttled" forKey:@"code"]; diff --git a/packages/firebase_remote_config/firebase_remote_config/lib/src/firebase_remote_config.dart b/packages/firebase_remote_config/firebase_remote_config/lib/src/firebase_remote_config.dart index 7f41e29a817c..3388c3d9a1d1 100644 --- a/packages/firebase_remote_config/firebase_remote_config/lib/src/firebase_remote_config.dart +++ b/packages/firebase_remote_config/firebase_remote_config/lib/src/firebase_remote_config.dart @@ -83,6 +83,9 @@ class FirebaseRemoteConfig extends FirebasePluginPlatform with ChangeNotifier { /// Performs a fetch and activate operation, as a convenience. /// /// Returns [bool] in the same way that is done for [activate]. + /// A [FirebaseException] maybe thrown with the following error code: + /// - **forbidden**: + /// - Thrown if the Google Cloud Platform Firebase Remote Config API is disabled Future fetchAndActivate() async { bool configChanged = await _delegate.fetchAndActivate(); notifyListeners(); diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/platform_interface/platform_interface_firebase_remote_config.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/platform_interface/platform_interface_firebase_remote_config.dart index 0d4aebfb7a7b..167154c8383c 100644 --- a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/platform_interface/platform_interface_firebase_remote_config.dart +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/platform_interface/platform_interface_firebase_remote_config.dart @@ -122,6 +122,9 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { /// Performs a fetch and activate operation, as a convenience. /// /// Returns [bool] in the same way that is done for [activate]. + /// A [FirebaseException] maybe thrown with the following error code: + /// - **forbidden**: + /// - Thrown if the Google Cloud Platform Firebase Remote Config API is disabled Future fetchAndActivate() { throw UnimplementedError('fetchAndActivate() is not implemented'); }