diff --git a/.vscode/settings.json b/.vscode/settings.json index 192e749674be..0fe6bfd08e49 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,15 @@ { "dart.runPubGetOnPubspecChanges": "always", -} + "C_Cpp.errorSquiggles": "disabled", + "files.associations": { + "chrono": "cpp", + "functional": "cpp", + "optional": "cpp", + "system_error": "cpp", + "type_traits": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xtr1common": "cpp", + "vector": "cpp" + }, +} \ No newline at end of file diff --git a/packages/firebase_core/firebase_core/pubspec.yaml b/packages/firebase_core/firebase_core/pubspec.yaml index 58e9696f4c47..1515f77f57a5 100644 --- a/packages/firebase_core/firebase_core/pubspec.yaml +++ b/packages/firebase_core/firebase_core/pubspec.yaml @@ -40,6 +40,7 @@ flutter: windows: pluginClass: FirebaseCorePluginCApi + firebase: google_services_gradle_plugin_version: '4.3.10' crashlytics_gradle_plugin_version: '2.8.1' diff --git a/packages/firebase_core/firebase_core/windows/CMakeLists.txt b/packages/firebase_core/firebase_core/windows/CMakeLists.txt index bd50de39c3b5..773ec6781e52 100644 --- a/packages/firebase_core/firebase_core/windows/CMakeLists.txt +++ b/packages/firebase_core/firebase_core/windows/CMakeLists.txt @@ -4,7 +4,7 @@ # customers of the plugin. cmake_minimum_required(VERSION 3.14) -set(FIREBASE_SDK_VERSION "10.5.0") +set(FIREBASE_SDK_VERSION "11.0.1") if (EXISTS $ENV{FIREBASE_CPP_SDK_DIR}/include/firebase/version.h) file(READ "$ENV{FIREBASE_CPP_SDK_DIR}/include/firebase/version.h" existing_version) @@ -90,7 +90,7 @@ set(MSVC_RUNTIME_MODE MD) add_subdirectory(${FIREBASE_CPP_SDK_DIR} bin/ EXCLUDE_FROM_ALL) target_include_directories(${PLUGIN_NAME} INTERFACE "${FIREBASE_CPP_SDK_DIR}/include") -set(firebase_libs firebase_auth firebase_database firebase_app) +set(firebase_libs firebase_auth firebase_database firebase_app firebase_remote_config) foreach(firebase_lib IN ITEMS ${firebase_libs}) get_target_property(firebase_lib_path ${firebase_lib} IMPORTED_LOCATION) string(REPLACE "Debug" "Release" firebase_lib_release_path ${firebase_lib_path}) @@ -99,8 +99,9 @@ foreach(firebase_lib IN ITEMS ${firebase_libs}) IMPORTED_LOCATION_RELEASE "${firebase_lib_release_path}" ) endforeach() +set(ADDITIONAL_LIBS advapi32 ws2_32 crypt32 rpcrt4 ole32) -target_link_libraries(${PLUGIN_NAME} PRIVATE "${firebase_libs}") +target_link_libraries(${PLUGIN_NAME} PRIVATE "${firebase_libs}" "${ADDITIONAL_LIBS}") target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp index 7e778c1a803f..16a4f2d1801a 100644 --- a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp +++ b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp @@ -1,13 +1,15 @@ // Copyright 2023, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. - +#define _CRT_SECURE_NO_WARNINGS #include "firebase_core_plugin.h" // This must be included before many other Windows headers. #include #include "firebase/app.h" +#include "firebase/log.h" +#include "firebase/remote_config.h" #include "messages.g.h" // For getPlatformVersion; remove unless needed for your plugin implementation. @@ -18,12 +20,14 @@ #include #include +#include #include #include #include #include #include using ::firebase::App; +using ::firebase::remote_config::RemoteConfig; namespace firebase_core_windows { @@ -38,7 +42,10 @@ void FirebaseCorePlugin::RegisterWithRegistrar( registrar->AddPlugin(std::move(plugin)); } -FirebaseCorePlugin::FirebaseCorePlugin() {} +FirebaseCorePlugin::FirebaseCorePlugin() { + firebase::SetLogLevel(firebase::kLogLevelVerbose); + std::cout << "[C++] FirebaseCorePlugin::FirebaseCorePlugin" << std::endl; +} FirebaseCorePlugin::~FirebaseCorePlugin() = default; @@ -87,17 +94,29 @@ PigeonInitializeResponse AppToPigeonInitializeResponse(const App &app) { PigeonInitializeResponse response = PigeonInitializeResponse(); response.set_name(app.name()); response.set_options(optionsFromFIROptions(app.options())); + + // response.set_plugin_constants(registrar.); return response; } +void *FirebaseCorePlugin::GetFirebaseApp(std::string appName) { + return App::GetInstance(appName.c_str()); +} + +void *FirebaseCorePlugin::GetFirebaseRemoteConfig(std::string appName) { + App *app = App::GetInstance(appName.c_str()); + RemoteConfig *rc = RemoteConfig::GetInstance(app); + return rc; +} + void FirebaseCorePlugin::InitializeApp( const std::string &app_name, const PigeonFirebaseOptions &initialize_app_request, std::function reply)> result) { // Create an app - App *app; - app = App::Create(PigeonFirebaseOptionsToAppOptions(initialize_app_request), - app_name.c_str()); + App *app = + App::Create(PigeonFirebaseOptionsToAppOptions(initialize_app_request), + app_name.c_str()); // Send back the result to Flutter result(AppToPigeonInitializeResponse(*app)); @@ -105,16 +124,20 @@ void FirebaseCorePlugin::InitializeApp( void FirebaseCorePlugin::InitializeCore( std::function reply)> result) { - // TODO: Missing function to get the list of currently initialized apps std::vector initializedApps; + std::vector all_apps = App::GetApps(); + for (const App *app : all_apps) { + initializedApps.push_back(AppToPigeonInitializeResponse(*app)); + } + flutter::EncodableList encodableList; // Insert the contents of the vector into the EncodableList - // for (const auto &item : initializedApps) { - // encodableList.push_back(flutter::EncodableValue(item)); - //} - result(flutter::EncodableList()); + for (const auto &item : initializedApps) { + encodableList.push_back(flutter::CustomEncodableValue(item)); + } + result(encodableList); } void FirebaseCorePlugin::OptionsFromResource( diff --git a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h index a1f43ad21491..cf24b865779a 100644 --- a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h +++ b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h @@ -21,6 +21,8 @@ class FirebaseCorePlugin : public flutter::Plugin, public FirebaseAppHostApi { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); + static void *GetFirebaseApp(std::string appName); + static void *GetFirebaseRemoteConfig(std::string appName); FirebaseCorePlugin(); diff --git a/packages/firebase_core/firebase_core/windows/firebase_core_plugin_c_api.cpp b/packages/firebase_core/firebase_core/windows/firebase_core_plugin_c_api.cpp index fa14aed47bd9..4c52ed4e696d 100644 --- a/packages/firebase_core/firebase_core/windows/firebase_core_plugin_c_api.cpp +++ b/packages/firebase_core/firebase_core/windows/firebase_core_plugin_c_api.cpp @@ -14,3 +14,11 @@ void FirebaseCorePluginCApiRegisterWithRegistrar( flutter::PluginRegistrarManager::GetInstance() ->GetRegistrar(registrar)); } + +FLUTTER_PLUGIN_EXPORT void* GetFirebaseApp(std::string appName) { + return firebase_core_windows::FirebaseCorePlugin::GetFirebaseApp(appName); +} + +FLUTTER_PLUGIN_EXPORT void* GetFirebaseRemoteConfig(std::string appName) { + return firebase_core_windows::FirebaseCorePlugin::GetFirebaseApp(appName); +} diff --git a/packages/firebase_core/firebase_core/windows/include/firebase_core/firebase_core_plugin_c_api.h b/packages/firebase_core/firebase_core/windows/include/firebase_core/firebase_core_plugin_c_api.h index 3f0d51a62c38..61fffe72cf22 100644 --- a/packages/firebase_core/firebase_core/windows/include/firebase_core/firebase_core_plugin_c_api.h +++ b/packages/firebase_core/firebase_core/windows/include/firebase_core/firebase_core_plugin_c_api.h @@ -9,21 +9,21 @@ #include +#include +#include +#include + #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) #else #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) #endif -#if defined(__cplusplus) -extern "C" { -#endif - FLUTTER_PLUGIN_EXPORT void FirebaseCorePluginCApiRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); -#if defined(__cplusplus) -} // extern "C" -#endif +FLUTTER_PLUGIN_EXPORT void* GetFirebaseApp(std::string appName); + +FLUTTER_PLUGIN_EXPORT void* GetFirebaseRemoteConfig(std::string appName); #endif // FLUTTER_PLUGIN_FIREBASE_CORE_PLUGIN_C_API_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/GeneratedAndroidFirebaseRemoteConfig.java b/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/GeneratedAndroidFirebaseRemoteConfig.java new file mode 100644 index 000000000000..447a2f21b0bc --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/GeneratedAndroidFirebaseRemoteConfig.java @@ -0,0 +1,719 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +package io.flutter.plugins.firebase.remoteconfig; + +import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MessageCodec; +import io.flutter.plugin.common.StandardMessageCodec; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Generated class from Pigeon. */ +@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) +public class GeneratedAndroidFirebaseRemoteConfig { + + /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ + public static class FlutterError extends RuntimeException { + + /** The error code. */ + public final String code; + + /** The error details. Must be a datatype supported by the api codec. */ + public final Object details; + + public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details) + { + super(message); + this.code = code; + this.details = details; + } + } + + @NonNull + protected static ArrayList wrapError(@NonNull Throwable exception) { + ArrayList errorList = new ArrayList(3); + if (exception instanceof FlutterError) { + FlutterError error = (FlutterError) exception; + errorList.add(error.code); + errorList.add(error.getMessage()); + errorList.add(error.details); + } else { + errorList.add(exception.toString()); + errorList.add(exception.getClass().getSimpleName()); + errorList.add( + "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception)); + } + return errorList; + } + + /** ValueSource defines the possible sources of a config parameter value. */ + public enum PigeonValueSource { + /** The value was defined by a static constant. */ + VALUE_STATIC(0), + /** The value was defined by default config. */ + VALUE_DEFAULT(1), + /** The value was defined by fetched config. */ + VALUE_REMOTE(2); + + final int index; + + private PigeonValueSource(final int index) { + this.index = index; + } + } + + public enum PigeonRemoteConfigFetchStatus { + /** Indicates instance has not yet attempted a fetch. */ + NO_FETCH_YET(0), + /** Indicates the last fetch attempt succeeded. */ + SUCCESS(1), + /** Indicates the last fetch attempt failed. */ + FAILURE(2), + /** Indicates the last fetch attempt was rate-limited. */ + THROTTLE(3); + + final int index; + + private PigeonRemoteConfigFetchStatus(final int index) { + this.index = index; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class PigeonRemoteConfigSettings { + private @NonNull Long fetchTimeout; + + public @NonNull Long getFetchTimeout() { + return fetchTimeout; + } + + public void setFetchTimeout(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"fetchTimeout\" is null."); + } + this.fetchTimeout = setterArg; + } + + private @NonNull Long minimumFetchInterval; + + public @NonNull Long getMinimumFetchInterval() { + return minimumFetchInterval; + } + + public void setMinimumFetchInterval(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"minimumFetchInterval\" is null."); + } + this.minimumFetchInterval = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PigeonRemoteConfigSettings() {} + + public static final class Builder { + + private @Nullable Long fetchTimeout; + + public @NonNull Builder setFetchTimeout(@NonNull Long setterArg) { + this.fetchTimeout = setterArg; + return this; + } + + private @Nullable Long minimumFetchInterval; + + public @NonNull Builder setMinimumFetchInterval(@NonNull Long setterArg) { + this.minimumFetchInterval = setterArg; + return this; + } + + public @NonNull PigeonRemoteConfigSettings build() { + PigeonRemoteConfigSettings pigeonReturn = new PigeonRemoteConfigSettings(); + pigeonReturn.setFetchTimeout(fetchTimeout); + pigeonReturn.setMinimumFetchInterval(minimumFetchInterval); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(2); + toListResult.add(fetchTimeout); + toListResult.add(minimumFetchInterval); + return toListResult; + } + + static @NonNull PigeonRemoteConfigSettings fromList(@NonNull ArrayList list) { + PigeonRemoteConfigSettings pigeonResult = new PigeonRemoteConfigSettings(); + Object fetchTimeout = list.get(0); + pigeonResult.setFetchTimeout((fetchTimeout == null) ? null : ((fetchTimeout instanceof Integer) ? (Integer) fetchTimeout : (Long) fetchTimeout)); + Object minimumFetchInterval = list.get(1); + pigeonResult.setMinimumFetchInterval((minimumFetchInterval == null) ? null : ((minimumFetchInterval instanceof Integer) ? (Integer) minimumFetchInterval : (Long) minimumFetchInterval)); + return pigeonResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class PigeonRemoteConfigValue { + private @Nullable List value; + + public @Nullable List getValue() { + return value; + } + + public void setValue(@Nullable List setterArg) { + this.value = setterArg; + } + + /** Indicates at which source this value came from. */ + private @NonNull PigeonValueSource source; + + public @NonNull PigeonValueSource getSource() { + return source; + } + + public void setSource(@NonNull PigeonValueSource setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"source\" is null."); + } + this.source = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PigeonRemoteConfigValue() {} + + public static final class Builder { + + private @Nullable List value; + + public @NonNull Builder setValue(@Nullable List setterArg) { + this.value = setterArg; + return this; + } + + private @Nullable PigeonValueSource source; + + public @NonNull Builder setSource(@NonNull PigeonValueSource setterArg) { + this.source = setterArg; + return this; + } + + public @NonNull PigeonRemoteConfigValue build() { + PigeonRemoteConfigValue pigeonReturn = new PigeonRemoteConfigValue(); + pigeonReturn.setValue(value); + pigeonReturn.setSource(source); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(2); + toListResult.add(value); + toListResult.add(source == null ? null : source.index); + return toListResult; + } + + static @NonNull PigeonRemoteConfigValue fromList(@NonNull ArrayList list) { + PigeonRemoteConfigValue pigeonResult = new PigeonRemoteConfigValue(); + Object value = list.get(0); + pigeonResult.setValue((List) value); + Object source = list.get(1); + pigeonResult.setSource(source == null ? null : PigeonValueSource.values()[(int) source]); + return pigeonResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class PigeonFirebaseApp { + private @NonNull String appName; + + public @NonNull String getAppName() { + return appName; + } + + public void setAppName(@NonNull String setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"appName\" is null."); + } + this.appName = setterArg; + } + + private @Nullable String tenantId; + + public @Nullable String getTenantId() { + return tenantId; + } + + public void setTenantId(@Nullable String setterArg) { + this.tenantId = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PigeonFirebaseApp() {} + + public static final class Builder { + + private @Nullable String appName; + + public @NonNull Builder setAppName(@NonNull String setterArg) { + this.appName = setterArg; + return this; + } + + private @Nullable String tenantId; + + public @NonNull Builder setTenantId(@Nullable String setterArg) { + this.tenantId = setterArg; + return this; + } + + public @NonNull PigeonFirebaseApp build() { + PigeonFirebaseApp pigeonReturn = new PigeonFirebaseApp(); + pigeonReturn.setAppName(appName); + pigeonReturn.setTenantId(tenantId); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(2); + toListResult.add(appName); + toListResult.add(tenantId); + return toListResult; + } + + static @NonNull PigeonFirebaseApp fromList(@NonNull ArrayList list) { + PigeonFirebaseApp pigeonResult = new PigeonFirebaseApp(); + Object appName = list.get(0); + pigeonResult.setAppName((String) appName); + Object tenantId = list.get(1); + pigeonResult.setTenantId((String) tenantId); + return pigeonResult; + } + } + + public interface Result { + @SuppressWarnings("UnknownNullness") + void success(T result); + + void error(@NonNull Throwable error); + } + + private static class FirebaseRemoteConfigHostApiCodec extends StandardMessageCodec { + public static final FirebaseRemoteConfigHostApiCodec INSTANCE = new FirebaseRemoteConfigHostApiCodec(); + + private FirebaseRemoteConfigHostApiCodec() {} + + @Override + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return PigeonFirebaseApp.fromList((ArrayList) readValue(buffer)); + case (byte) 129: + return PigeonRemoteConfigSettings.fromList((ArrayList) readValue(buffer)); + case (byte) 130: + return PigeonRemoteConfigValue.fromList((ArrayList) readValue(buffer)); + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { + if (value instanceof PigeonFirebaseApp) { + stream.write(128); + writeValue(stream, ((PigeonFirebaseApp) value).toList()); + } else if (value instanceof PigeonRemoteConfigSettings) { + stream.write(129); + writeValue(stream, ((PigeonRemoteConfigSettings) value).toList()); + } else if (value instanceof PigeonRemoteConfigValue) { + stream.write(130); + writeValue(stream, ((PigeonRemoteConfigValue) value).toList()); + } else { + super.writeValue(stream, value); + } + } + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface FirebaseRemoteConfigHostApi { + + void activate(@NonNull PigeonFirebaseApp app, @NonNull Result result); + + void ensureInitialized(@NonNull PigeonFirebaseApp app, @NonNull Result result); + + void fetch(@NonNull PigeonFirebaseApp app, @NonNull Result result); + + void fetchAndActivate(@NonNull PigeonFirebaseApp app, @NonNull Result result); + + @NonNull + Map getAll(@NonNull PigeonFirebaseApp app); + + @NonNull + Boolean getBool(@NonNull PigeonFirebaseApp app, @NonNull String key); + + @NonNull + Long getInt(@NonNull PigeonFirebaseApp app, @NonNull String key); + + @NonNull + Double getDouble(@NonNull PigeonFirebaseApp app, @NonNull String key); + + @NonNull + String getString(@NonNull PigeonFirebaseApp app, @NonNull String key); + + @NonNull + PigeonRemoteConfigValue getValue(@NonNull PigeonFirebaseApp app, @NonNull String key); + + void setConfigSettings(@NonNull PigeonFirebaseApp app, @NonNull PigeonRemoteConfigSettings remoteConfigSettings, @NonNull Result result); + + void setDefaults(@NonNull PigeonFirebaseApp app, @NonNull Map defaultParameters, @NonNull Result result); + + /** The codec used by FirebaseRemoteConfigHostApi. */ + static @NonNull MessageCodec getCodec() { + return FirebaseRemoteConfigHostApiCodec.INSTANCE; + } + /**Sets up an instance of `FirebaseRemoteConfigHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable FirebaseRemoteConfigHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + Result resultCallback = + new Result() { + public void success(Boolean result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.activate(appArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + Result resultCallback = + new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.ensureInitialized(appArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + Result resultCallback = + new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.fetch(appArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + Result resultCallback = + new Result() { + public void success(Boolean result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.fetchAndActivate(appArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + try { + Map output = api.getAll(appArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + String keyArg = (String) args.get(1); + try { + Boolean output = api.getBool(appArg, keyArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + String keyArg = (String) args.get(1); + try { + Long output = api.getInt(appArg, keyArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + String keyArg = (String) args.get(1); + try { + Double output = api.getDouble(appArg, keyArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + String keyArg = (String) args.get(1); + try { + String output = api.getString(appArg, keyArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + String keyArg = (String) args.get(1); + try { + PigeonRemoteConfigValue output = api.getValue(appArg, keyArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + PigeonRemoteConfigSettings remoteConfigSettingsArg = (PigeonRemoteConfigSettings) args.get(1); + Result resultCallback = + new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.setConfigSettings(appArg, remoteConfigSettingsArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PigeonFirebaseApp appArg = (PigeonFirebaseApp) args.get(0); + Map defaultParametersArg = (Map) args.get(1); + Result resultCallback = + new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.setDefaults(appArg, defaultParametersArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/.gitignore b/packages/firebase_remote_config/firebase_remote_config/example/.gitignore new file mode 100644 index 000000000000..24476c5d1eb5 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/firebase_remote_config/firebase_remote_config/example/lib/firebase_options.dart b/packages/firebase_remote_config/firebase_remote_config/example/lib/firebase_options.dart index af4b4130e962..d924f779faad 100644 --- a/packages/firebase_remote_config/firebase_remote_config/example/lib/firebase_options.dart +++ b/packages/firebase_remote_config/firebase_remote_config/example/lib/firebase_options.dart @@ -31,10 +31,11 @@ class DefaultFirebaseOptions { case TargetPlatform.macOS: return macos; case TargetPlatform.windows: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for windows - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); + return android; + // throw UnsupportedError( + // 'DefaultFirebaseOptions have not been configured for windows - ' + // 'you can reconfigure this by running the FlutterFire CLI again.', + // ); case TargetPlatform.linux: throw UnsupportedError( 'DefaultFirebaseOptions have not been configured for linux - ' diff --git a/packages/firebase_remote_config/firebase_remote_config/example/test/widget_test.dart b/packages/firebase_remote_config/firebase_remote_config/example/test/widget_test.dart new file mode 100644 index 000000000000..092d222f7e16 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/.gitignore b/packages/firebase_remote_config/firebase_remote_config/example/windows/.gitignore new file mode 100644 index 000000000000..d492d0d98c8f --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/CMakeLists.txt b/packages/firebase_remote_config/firebase_remote_config/example/windows/CMakeLists.txt new file mode 100644 index 000000000000..b63432b834a7 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(firebaes_remote_config_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "firebase_remote_config_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/CMakeLists.txt b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000000..930d2071a324 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.cc b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000000..2de46391571e --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,17 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseRemoteConfigPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseRemoteConfigPluginCApi")); +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.h b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000000..dc139d85a931 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugins.cmake b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000000..a78d7e70f4ae --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + firebase_core + firebase_remote_config +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/CMakeLists.txt b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/CMakeLists.txt new file mode 100644 index 000000000000..394917c053a0 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/Runner.rc b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/Runner.rc new file mode 100644 index 000000000000..423a96f5504a --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "io.flutter.plugins.firebase.remoteconfig" "\0" + VALUE "FileDescription", "example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 io.flutter.plugins.firebase.remoteconfig. All rights reserved." "\0" + VALUE "OriginalFilename", "example.exe" "\0" + VALUE "ProductName", "example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.cpp b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.cpp new file mode 100644 index 000000000000..46c3e636f1e8 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. Ensure a frame is pending to ensure the window is shown. + // This no-ops if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.h b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.h new file mode 100644 index 000000000000..6da0652f05f2 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/main.cpp b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/main.cpp new file mode 100644 index 000000000000..a61bf80d31fb --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resource.h b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resource.h new file mode 100644 index 000000000000..66a65d1e4a79 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resources/app_icon.ico b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000000..c04e20caf637 Binary files /dev/null and b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/resources/app_icon.ico differ diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/runner.exe.manifest b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/runner.exe.manifest new file mode 100644 index 000000000000..a42ea7687cb6 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.cpp b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.cpp new file mode 100644 index 000000000000..f5bf9fa0f536 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.h b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.h new file mode 100644 index 000000000000..3879d5475579 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.cpp b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.cpp new file mode 100644 index 000000000000..041a38554745 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.h b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.h new file mode 100644 index 000000000000..c86632d8a6b9 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/example/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.h b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.h new file mode 100644 index 000000000000..ad79bad9f8db --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.h @@ -0,0 +1,95 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import + +@protocol FlutterBinaryMessenger; +@protocol FlutterMessageCodec; +@class FlutterError; +@class FlutterStandardTypedData; + +NS_ASSUME_NONNULL_BEGIN + +/// ValueSource defines the possible sources of a config parameter value. +typedef NS_ENUM(NSUInteger, PigeonValueSource) { + /// The value was defined by a static constant. + PigeonValueSourceValueStatic = 0, + /// The value was defined by default config. + PigeonValueSourceValueDefault = 1, + /// The value was defined by fetched config. + PigeonValueSourceValueRemote = 2, +}; + +typedef NS_ENUM(NSUInteger, PigeonRemoteConfigFetchStatus) { + /// Indicates instance has not yet attempted a fetch. + PigeonRemoteConfigFetchStatusNoFetchYet = 0, + /// Indicates the last fetch attempt succeeded. + PigeonRemoteConfigFetchStatusSuccess = 1, + /// Indicates the last fetch attempt failed. + PigeonRemoteConfigFetchStatusFailure = 2, + /// Indicates the last fetch attempt was rate-limited. + PigeonRemoteConfigFetchStatusThrottle = 3, +}; + +@class PigeonRemoteConfigSettings; +@class PigeonRemoteConfigValue; +@class PigeonFirebaseApp; + +@interface PigeonRemoteConfigSettings : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithFetchTimeout:(NSNumber *)fetchTimeout + minimumFetchInterval:(NSNumber *)minimumFetchInterval; +@property(nonatomic, strong) NSNumber * fetchTimeout; +@property(nonatomic, strong) NSNumber * minimumFetchInterval; +@end + +@interface PigeonRemoteConfigValue : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithValue:(nullable NSArray *)value + source:(PigeonValueSource)source; +@property(nonatomic, strong, nullable) NSArray * value; +/// Indicates at which source this value came from. +@property(nonatomic, assign) PigeonValueSource source; +@end + +@interface PigeonFirebaseApp : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAppName:(NSString *)appName + tenantId:(nullable NSString *)tenantId; +@property(nonatomic, copy) NSString * appName; +@property(nonatomic, copy, nullable) NSString * tenantId; +@end + +/// The codec used by FirebaseRemoteConfigHostApi. +NSObject *FirebaseRemoteConfigHostApiGetCodec(void); + +@protocol FirebaseRemoteConfigHostApi +- (void)activateApp:(PigeonFirebaseApp *)app completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; +- (void)ensureInitializedApp:(PigeonFirebaseApp *)app completion:(void (^)(FlutterError *_Nullable))completion; +- (void)fetchApp:(PigeonFirebaseApp *)app completion:(void (^)(FlutterError *_Nullable))completion; +- (void)fetchAndActivateApp:(PigeonFirebaseApp *)app completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; +/// @return `nil` only when `error != nil`. +- (nullable NSDictionary *)getAllApp:(PigeonFirebaseApp *)app error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)getBoolApp:(PigeonFirebaseApp *)app key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)getIntApp:(PigeonFirebaseApp *)app key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)getDoubleApp:(PigeonFirebaseApp *)app key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSString *)getStringApp:(PigeonFirebaseApp *)app key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable PigeonRemoteConfigValue *)getValueApp:(PigeonFirebaseApp *)app key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error; +- (void)setConfigSettingsApp:(PigeonFirebaseApp *)app remoteConfigSettings:(PigeonRemoteConfigSettings *)remoteConfigSettings completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setDefaultsApp:(PigeonFirebaseApp *)app defaultParameters:(NSDictionary *)defaultParameters completion:(void (^)(FlutterError *_Nullable))completion; +@end + +extern void FirebaseRemoteConfigHostApiSetup(id binaryMessenger, NSObject *_Nullable api); + +NS_ASSUME_NONNULL_END diff --git a/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.m b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.m new file mode 100644 index 000000000000..e2817ce711e3 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/ios/Classes/messages.g.m @@ -0,0 +1,416 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import "messages.g.h" +#import + +#if !__has_feature(objc_arc) +#error File requires ARC to be enabled. +#endif + +static NSArray *wrapResult(id result, FlutterError *error) { + if (error) { + return @[ + error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] + ]; + } + return @[ result ?: [NSNull null] ]; +} +static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { + id result = array[key]; + return (result == [NSNull null]) ? nil : result; +} + +@interface PigeonRemoteConfigSettings () ++ (PigeonRemoteConfigSettings *)fromList:(NSArray *)list; ++ (nullable PigeonRemoteConfigSettings *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface PigeonRemoteConfigValue () ++ (PigeonRemoteConfigValue *)fromList:(NSArray *)list; ++ (nullable PigeonRemoteConfigValue *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface PigeonFirebaseApp () ++ (PigeonFirebaseApp *)fromList:(NSArray *)list; ++ (nullable PigeonFirebaseApp *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@implementation PigeonRemoteConfigSettings ++ (instancetype)makeWithFetchTimeout:(NSNumber *)fetchTimeout + minimumFetchInterval:(NSNumber *)minimumFetchInterval { + PigeonRemoteConfigSettings* pigeonResult = [[PigeonRemoteConfigSettings alloc] init]; + pigeonResult.fetchTimeout = fetchTimeout; + pigeonResult.minimumFetchInterval = minimumFetchInterval; + return pigeonResult; +} ++ (PigeonRemoteConfigSettings *)fromList:(NSArray *)list { + PigeonRemoteConfigSettings *pigeonResult = [[PigeonRemoteConfigSettings alloc] init]; + pigeonResult.fetchTimeout = GetNullableObjectAtIndex(list, 0); + NSAssert(pigeonResult.fetchTimeout != nil, @""); + pigeonResult.minimumFetchInterval = GetNullableObjectAtIndex(list, 1); + NSAssert(pigeonResult.minimumFetchInterval != nil, @""); + return pigeonResult; +} ++ (nullable PigeonRemoteConfigSettings *)nullableFromList:(NSArray *)list { + return (list) ? [PigeonRemoteConfigSettings fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + (self.fetchTimeout ?: [NSNull null]), + (self.minimumFetchInterval ?: [NSNull null]), + ]; +} +@end + +@implementation PigeonRemoteConfigValue ++ (instancetype)makeWithValue:(nullable NSArray *)value + source:(PigeonValueSource)source { + PigeonRemoteConfigValue* pigeonResult = [[PigeonRemoteConfigValue alloc] init]; + pigeonResult.value = value; + pigeonResult.source = source; + return pigeonResult; +} ++ (PigeonRemoteConfigValue *)fromList:(NSArray *)list { + PigeonRemoteConfigValue *pigeonResult = [[PigeonRemoteConfigValue alloc] init]; + pigeonResult.value = GetNullableObjectAtIndex(list, 0); + pigeonResult.source = [GetNullableObjectAtIndex(list, 1) integerValue]; + return pigeonResult; +} ++ (nullable PigeonRemoteConfigValue *)nullableFromList:(NSArray *)list { + return (list) ? [PigeonRemoteConfigValue fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + (self.value ?: [NSNull null]), + @(self.source), + ]; +} +@end + +@implementation PigeonFirebaseApp ++ (instancetype)makeWithAppName:(NSString *)appName + tenantId:(nullable NSString *)tenantId { + PigeonFirebaseApp* pigeonResult = [[PigeonFirebaseApp alloc] init]; + pigeonResult.appName = appName; + pigeonResult.tenantId = tenantId; + return pigeonResult; +} ++ (PigeonFirebaseApp *)fromList:(NSArray *)list { + PigeonFirebaseApp *pigeonResult = [[PigeonFirebaseApp alloc] init]; + pigeonResult.appName = GetNullableObjectAtIndex(list, 0); + NSAssert(pigeonResult.appName != nil, @""); + pigeonResult.tenantId = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable PigeonFirebaseApp *)nullableFromList:(NSArray *)list { + return (list) ? [PigeonFirebaseApp fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + (self.appName ?: [NSNull null]), + (self.tenantId ?: [NSNull null]), + ]; +} +@end + +@interface FirebaseRemoteConfigHostApiCodecReader : FlutterStandardReader +@end +@implementation FirebaseRemoteConfigHostApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [PigeonFirebaseApp fromList:[self readValue]]; + case 129: + return [PigeonRemoteConfigSettings fromList:[self readValue]]; + case 130: + return [PigeonRemoteConfigValue fromList:[self readValue]]; + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FirebaseRemoteConfigHostApiCodecWriter : FlutterStandardWriter +@end +@implementation FirebaseRemoteConfigHostApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[PigeonFirebaseApp class]]) { + [self writeByte:128]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[PigeonRemoteConfigSettings class]]) { + [self writeByte:129]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[PigeonRemoteConfigValue class]]) { + [self writeByte:130]; + [self writeValue:[value toList]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FirebaseRemoteConfigHostApiCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FirebaseRemoteConfigHostApiCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FirebaseRemoteConfigHostApiCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FirebaseRemoteConfigHostApiCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FirebaseRemoteConfigHostApiGetCodec(void) { + static FlutterStandardMessageCodec *sSharedObject = nil; + static dispatch_once_t sPred = 0; + dispatch_once(&sPred, ^{ + FirebaseRemoteConfigHostApiCodecReaderWriter *readerWriter = [[FirebaseRemoteConfigHostApiCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} + +void FirebaseRemoteConfigHostApiSetup(id binaryMessenger, NSObject *api) { + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(activateApp:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(activateApp:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + [api activateApp:arg_app completion:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(ensureInitializedApp:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(ensureInitializedApp:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + [api ensureInitializedApp:arg_app completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(fetchApp:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(fetchApp:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + [api fetchApp:arg_app completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(fetchAndActivateApp:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(fetchAndActivateApp:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + [api fetchAndActivateApp:arg_app completion:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getAllApp:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getAllApp:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSDictionary *output = [api getAllApp:arg_app error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getBoolApp:key:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getBoolApp:key:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSString *arg_key = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSNumber *output = [api getBoolApp:arg_app key:arg_key error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getIntApp:key:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getIntApp:key:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSString *arg_key = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSNumber *output = [api getIntApp:arg_app key:arg_key error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getDoubleApp:key:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getDoubleApp:key:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSString *arg_key = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSNumber *output = [api getDoubleApp:arg_app key:arg_key error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getStringApp:key:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getStringApp:key:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSString *arg_key = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSString *output = [api getStringApp:arg_app key:arg_key error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getValueApp:key:error:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(getValueApp:key:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSString *arg_key = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + PigeonRemoteConfigValue *output = [api getValueApp:arg_app key:arg_key error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setConfigSettingsApp:remoteConfigSettings:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(setConfigSettingsApp:remoteConfigSettings:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + PigeonRemoteConfigSettings *arg_remoteConfigSettings = GetNullableObjectAtIndex(args, 1); + [api setConfigSettingsApp:arg_app remoteConfigSettings:arg_remoteConfigSettings completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults" + binaryMessenger:binaryMessenger + codec:FirebaseRemoteConfigHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setDefaultsApp:defaultParameters:completion:)], @"FirebaseRemoteConfigHostApi api (%@) doesn't respond to @selector(setDefaultsApp:defaultParameters:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + PigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); + NSDictionary *arg_defaultParameters = GetNullableObjectAtIndex(args, 1); + [api setDefaultsApp:arg_app defaultParameters:arg_defaultParameters completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} diff --git a/packages/firebase_remote_config/firebase_remote_config/lib/firebase_remote_config.dart b/packages/firebase_remote_config/firebase_remote_config/lib/firebase_remote_config.dart index fbef39b99cec..4d80e5dd2e71 100644 --- a/packages/firebase_remote_config/firebase_remote_config/lib/firebase_remote_config.dart +++ b/packages/firebase_remote_config/firebase_remote_config/lib/firebase_remote_config.dart @@ -5,6 +5,7 @@ library firebase_remote_config; import 'dart:async'; +import 'dart:developer'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart' 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 10daf4ab5f6f..be78e1a2e9e0 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 @@ -51,12 +51,12 @@ class FirebaseRemoteConfig extends FirebasePluginPlatform { /// Returns the status of the last fetch attempt. RemoteConfigFetchStatus get lastFetchStatus { - return _delegate.lastFetchStatus; + return _delegate.getFetchStatus(); } /// Returns the [RemoteConfigSettings] of the current instance. RemoteConfigSettings get settings { - return _delegate.settings; + return _delegate.getSettings(); } /// Makes the last fetched config available to getters. @@ -86,13 +86,14 @@ class FirebaseRemoteConfig extends FirebasePluginPlatform { /// - **forbidden**: /// - Thrown if the Google Cloud Platform Firebase Remote Config API is disabled Future fetchAndActivate() async { + log('remote_config_dart fetchAndActivate'); bool configChanged = await _delegate.fetchAndActivate(); return configChanged; } /// Returns a Map of all Remote Config parameters. Map getAll() { - return _delegate.getAll(); + return _delegate.getAllConverted(); } /// Gets the value for a given key as a bool. @@ -125,7 +126,7 @@ class FirebaseRemoteConfig extends FirebasePluginPlatform { /// Gets the [RemoteConfigValue] for a given key. RemoteConfigValue getValue(String key) { - return _delegate.getValue(key); + return _delegate.getValueConverted(key); } /// Sets the [RemoteConfigSettings] for the current instance. @@ -137,7 +138,7 @@ class FirebaseRemoteConfig extends FirebasePluginPlatform { if (remoteConfigSettings.fetchTimeout.inSeconds == 0) { remoteConfigSettings.fetchTimeout = const Duration(seconds: 60); } - return _delegate.setConfigSettings(remoteConfigSettings); + return _delegate.setConfigSettingsConverted(remoteConfigSettings); } /// Sets the default parameter values for the current instance. diff --git a/packages/firebase_remote_config/firebase_remote_config/pubspec.yaml b/packages/firebase_remote_config/firebase_remote_config/pubspec.yaml index f22d9df4d67d..7bd8ff13cdb9 100644 --- a/packages/firebase_remote_config/firebase_remote_config/pubspec.yaml +++ b/packages/firebase_remote_config/firebase_remote_config/pubspec.yaml @@ -40,3 +40,5 @@ flutter: pluginClass: FLTFirebaseRemoteConfigPlugin web: default_package: firebase_remote_config_web + windows: + pluginClass: FirebaseRemoteConfigPluginCApi diff --git a/packages/firebase_remote_config/firebase_remote_config/test/firebase_remote_config_test.dart b/packages/firebase_remote_config/firebase_remote_config/test/firebase_remote_config_test.dart index c01592ad5f02..2dd193af7503 100644 --- a/packages/firebase_remote_config/firebase_remote_config/test/firebase_remote_config_test.dart +++ b/packages/firebase_remote_config/firebase_remote_config/test/firebase_remote_config_test.dart @@ -19,11 +19,11 @@ void main() { late FirebaseRemoteConfig remoteConfig; late DateTime mockLastFetchTime; - late RemoteConfigFetchStatus mockLastFetchStatus; - late RemoteConfigSettings mockRemoteConfigSettings; - late Map mockParameters; + late PigeonRemoteConfigFetchStatus mockLastFetchStatus; + late PigeonRemoteConfigSettings mockRemoteConfigSettings; + late Map mockParameters; late Map mockDefaultParameters; - late RemoteConfigValue mockRemoteConfigValue; + late PigeonRemoteConfigValue mockRemoteConfigValue; group('FirebaseRemoteConfig', () { FirebaseRemoteConfigPlatform.instance = mockRemoteConfigPlatform; @@ -33,16 +33,16 @@ void main() { remoteConfig = FirebaseRemoteConfig.instance; mockLastFetchTime = DateTime(2020); - mockLastFetchStatus = RemoteConfigFetchStatus.noFetchYet; - mockRemoteConfigSettings = RemoteConfigSettings( - fetchTimeout: const Duration(seconds: 10), - minimumFetchInterval: const Duration(hours: 1), + mockLastFetchStatus = PigeonRemoteConfigFetchStatus.noFetchYet; + mockRemoteConfigSettings = PigeonRemoteConfigSettings( + fetchTimeout: 10, + minimumFetchInterval: 3600, ); - mockParameters = {}; + mockParameters = {}; mockDefaultParameters = {}; - mockRemoteConfigValue = RemoteConfigValue( - [], - ValueSource.valueStatic, + mockRemoteConfigValue = PigeonRemoteConfigValue( + value: [], + source: PigeonValueSource.valueStatic, ); when( @@ -137,9 +137,14 @@ void main() { fetchTimeout: const Duration(seconds: 8), minimumFetchInterval: Duration.zero, ); + final pigeonRemoteConfigSettings = PigeonRemoteConfigSettings( + fetchTimeout: 8, + minimumFetchInterval: 0, + ); await remoteConfig.setConfigSettings(remoteConfigSettings); verify( - mockRemoteConfigPlatform.setConfigSettings(remoteConfigSettings), + mockRemoteConfigPlatform + .setConfigSettings(pigeonRemoteConfigSettings), ); }); }); @@ -301,7 +306,8 @@ class MockFirebaseRemoteConfig extends Mock } @override - Future setConfigSettings(RemoteConfigSettings? remoteConfigSettings) { + Future setConfigSettings( + PigeonRemoteConfigSettings? remoteConfigSettings) { return super.noSuchMethod( Invocation.method(#setConfigSettings, [remoteConfigSettings]), returnValue: Future.value(), @@ -319,11 +325,11 @@ class MockFirebaseRemoteConfig extends Mock } @override - Map getAll() { + Map getAll() { return super.noSuchMethod( Invocation.method(#getAll, []), - returnValue: {}, - returnValueForMissingStub: {}, + returnValue: {}, + returnValueForMissingStub: {}, ); } @@ -364,24 +370,33 @@ class MockFirebaseRemoteConfig extends Mock } @override - RemoteConfigValue getValue(String key) { + PigeonRemoteConfigValue getValue(String key) { return super.noSuchMethod( Invocation.method(#getValue, [key]), - returnValue: RemoteConfigValue( - [], - ValueSource.valueStatic, + returnValue: PigeonRemoteConfigValue( + value: [], + source: PigeonValueSource.valueStatic, ), - returnValueForMissingStub: RemoteConfigValue( - [], - ValueSource.valueStatic, + returnValueForMissingStub: PigeonRemoteConfigValue( + value: [], + source: PigeonValueSource.valueStatic, ), ); } @override - RemoteConfigFetchStatus get lastFetchStatus { + PigeonRemoteConfigFetchStatus get lastFetchStatus { return super.noSuchMethod( Invocation.getter(#lastFetchStatus), + returnValue: PigeonRemoteConfigFetchStatus.success, + returnValueForMissingStub: PigeonRemoteConfigFetchStatus.success, + ); + } + + @override + RemoteConfigFetchStatus getFetchStatus() { + return super.noSuchMethod( + Invocation.getter(#getFetchStatus), returnValue: RemoteConfigFetchStatus.success, returnValueForMissingStub: RemoteConfigFetchStatus.success, ); @@ -397,16 +412,16 @@ class MockFirebaseRemoteConfig extends Mock } @override - RemoteConfigSettings get settings { + PigeonRemoteConfigSettings get settings { return super.noSuchMethod( Invocation.getter(#settings), - returnValue: RemoteConfigSettings( - fetchTimeout: const Duration(seconds: 10), - minimumFetchInterval: const Duration(hours: 1), + returnValue: PigeonRemoteConfigSettings( + fetchTimeout: 10, + minimumFetchInterval: 3600, ), - returnValueForMissingStub: RemoteConfigSettings( - fetchTimeout: const Duration(seconds: 10), - minimumFetchInterval: const Duration(hours: 1), + returnValueForMissingStub: PigeonRemoteConfigSettings( + fetchTimeout: 10, + minimumFetchInterval: 3600, ), ); } diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/CMakeLists.txt b/packages/firebase_remote_config/firebase_remote_config/windows/CMakeLists.txt new file mode 100644 index 000000000000..4b3476bbad83 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/CMakeLists.txt @@ -0,0 +1,62 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + + +# Project-level configuration. +set(PROJECT_NAME "flutterfire_remote_config") +project(${PROJECT_NAME} LANGUAGES CXX) + +# This value is used when generating builds using this plugin, so it must +# not be changed +set(PLUGIN_NAME "firebase_remote_config_plugin") + +# Any new source files that you add to the plugin should be added here. +list(APPEND PLUGIN_SOURCES + "firebase_remote_config_plugin.cpp" + "firebase_remote_config_plugin.h" + "messages.g.cpp" + "messages.g.h" +) + +# Define the plugin library target. Its name must not be changed (see comment +# on PLUGIN_NAME above). +add_library(${PLUGIN_NAME} SHARED + "include/firebase_remote_config/firebase_remote_config_plugin_c_api.h" + "firebase_remote_config_plugin_c_api.cpp" + ${PLUGIN_SOURCES} +) + + +# Apply a standard set of build settings that are configured in the +# application-level CMakeLists.txt. This can be removed for plugins that want +# full control over build settings. +apply_standard_settings(${PLUGIN_NAME}) + +# Symbols are hidden by default to reduce the chance of accidental conflicts +# between plugins. This should not be removed; any symbols that should be +# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) + +# Source include directories and library dependencies. Add any plugin-specific +# dependencies here. +set(MSVC_RUNTIME_MODE MD) +set(firebase_libs firebase_core_plugin firebase_remote_config firebase_app) +set(ADDITIONAL_LIBS advapi32 ws2_32 crypt32 rpcrt4 ole32) +target_link_libraries(${PLUGIN_NAME} PRIVATE "${firebase_libs}" "${ADDITIONAL_LIBS}") + +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(firebase_remote_config_bundled_libraries + "" + PARENT_SCOPE +) diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.cpp b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.cpp new file mode 100644 index 000000000000..ba52f61ecc3d --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.cpp @@ -0,0 +1,173 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +#define _CRT_SECURE_NO_WARNINGS +#include "firebase_remote_config_plugin.h" + +// This must be included before many other Windows headers. +#include + +#include "firebase/app.h" +#include "firebase/future.h" +#include "firebase/remote_config.h" +#include "firebase_core/firebase_core_plugin_c_api.h" +#include "messages.g.h" + +// For getPlatformVersion; remove unless needed for your plugin implementation. +#include +#include +#include +#include +#include + +// #include +#include +#include +#include +#include +#include +#include +// #include +#include +using ::firebase::App; +using ::firebase::Future; +using ::firebase::remote_config::RemoteConfig; + +namespace firebase_remote_config_windows { + +// static +void FirebaseRemoteConfigPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarWindows* registrar) { + auto plugin = std::make_unique(); + + FirebaseRemoteConfigHostApi::SetUp(registrar->messenger(), plugin.get()); + + registrar->AddPlugin(std::move(plugin)); +} + +FirebaseRemoteConfigPlugin::FirebaseRemoteConfigPlugin() {} + +FirebaseRemoteConfigPlugin::~FirebaseRemoteConfigPlugin() = default; + +RemoteConfig* GetRCFromPigeon(const PigeonFirebaseApp& pigeonApp) { + void* rc_ptr = GetFirebaseRemoteConfig(pigeonApp.app_name()); + RemoteConfig* rc = static_cast(rc_ptr); + + return rc; +} + +void FirebaseRemoteConfigPlugin::Activate( + const PigeonFirebaseApp& app, + std::function reply)> result) { + RemoteConfig* rc = GetRCFromPigeon(app); + + Future activated_result = rc->Activate(); + activated_result.OnCompletion([result](const Future& bool_result) { + // TODO error handling + result(bool_result.result()); + std::cout << "[C++] FirebaseRemoteConfigPlugin::Activate() COMPLETE" + << std::endl; + }); +} + +void FirebaseRemoteConfigPlugin::EnsureInitialized( + const PigeonFirebaseApp& app, + std::function reply)> result) { + RemoteConfig* rc = GetRCFromPigeon(app); + + Future<::firebase::remote_config::ConfigInfo> init_result = + rc->EnsureInitialized(); +} + +void FirebaseRemoteConfigPlugin::Fetch( + const PigeonFirebaseApp& app, + std::function reply)> result) { + RemoteConfig* rc = GetRCFromPigeon(app); + + Future fetch_result = rc->Fetch(); + fetch_result.OnCompletion([result](const Future& void_result) { + // TODO error handling + std::cout << "[C++] FirebaseRemoteConfigPlugin::Fetch() COMPLETE" + << std::endl; + result(std::nullopt); + }); +} + +void FirebaseRemoteConfigPlugin::FetchAndActivate( + const PigeonFirebaseApp& app, + std::function reply)> result) { + RemoteConfig* rc = GetRCFromPigeon(app); + + Future fa_result = rc->FetchAndActivate(); + std::cout << "[C++] rc->FetchAndActivate()" << std::endl; + fa_result.OnCompletion([result](const Future& bool_result) { + // TODO error handling + result(bool_result.result()); + std::cout << "[C++] FirebaseRemoteConfigPlugin::FetchAndActivate() COMPLETE" + << std::endl; + }); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetAll( + const PigeonFirebaseApp& app) { + return flutter::EncodableMap(); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetBool(const PigeonFirebaseApp& app, + const std::string& key) { + RemoteConfig* rc = GetRCFromPigeon(app); + + return rc->GetBoolean(key.c_str()); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetInt( + const PigeonFirebaseApp& app, const std::string& key) { + RemoteConfig* rc = GetRCFromPigeon(app); + + return rc->GetLong(key.c_str()); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetDouble( + const PigeonFirebaseApp& app, const std::string& key) { + RemoteConfig* rc = GetRCFromPigeon(app); + + return rc->GetDouble(key.c_str()); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetString( + const PigeonFirebaseApp& app, const std::string& key) { + RemoteConfig* rc = GetRCFromPigeon(app); + + return rc->GetString(key.c_str()); +} + +ErrorOr FirebaseRemoteConfigPlugin::GetValue( + const PigeonFirebaseApp& app, const std::string& key) { + // RemoteConfig* rc = GetRCFromPigeon(app); + + // std::vector data = rc->GetData(key.c_str()); + + PigeonRemoteConfigValue* value_ptr = + new PigeonRemoteConfigValue(PigeonValueSource::valueStatic); + return *value_ptr; +} + +void FirebaseRemoteConfigPlugin::SetConfigSettings( + const PigeonFirebaseApp& app, + const PigeonRemoteConfigSettings& remote_config_settings, + std::function reply)> result) { + // TODO + std::cout << "[C++] FirebaseRemoteConfigPlugin::SetConfigSettings()" + << std::endl; + result(std::nullopt); +} + +void FirebaseRemoteConfigPlugin::SetDefaults( + const PigeonFirebaseApp& app, + const flutter::EncodableMap& default_parameters, + std::function reply)> result) { + // TODO + result(std::nullopt); +} + +} // namespace firebase_remote_config_windows diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.h b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.h new file mode 100644 index 000000000000..a7fa477e4cbc --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin.h @@ -0,0 +1,74 @@ +/* + * Copyright 2023, the Chromium project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_H_ +#define FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_H_ + +#include +#include + +#include + +#include "messages.g.h" + +namespace firebase_remote_config_windows { + +class FirebaseRemoteConfigPlugin : public flutter::Plugin, + public FirebaseRemoteConfigHostApi { + public: + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); + + FirebaseRemoteConfigPlugin(); + + virtual ~FirebaseRemoteConfigPlugin(); + + // Disallow copy and assign. + FirebaseRemoteConfigPlugin(const FirebaseRemoteConfigPlugin&) = delete; + FirebaseRemoteConfigPlugin& operator=(const FirebaseRemoteConfigPlugin&) = + delete; + + // FirebaseRemoteConfigHostApi + virtual void Activate( + const PigeonFirebaseApp& app, + std::function reply)> result) override; + virtual void EnsureInitialized( + const PigeonFirebaseApp& app, + std::function reply)> result) override; + virtual void Fetch( + const PigeonFirebaseApp& app, + std::function reply)> result) override; + virtual void FetchAndActivate( + const PigeonFirebaseApp& app, + std::function reply)> result) override; + + virtual ErrorOr GetAll( + const PigeonFirebaseApp& app) override; + virtual ErrorOr GetBool(const PigeonFirebaseApp& app, + const std::string& key) override; + virtual ErrorOr GetInt(const PigeonFirebaseApp& app, + const std::string& key) override; + virtual ErrorOr GetDouble(const PigeonFirebaseApp& app, + const std::string& key) override; + virtual ErrorOr GetString(const PigeonFirebaseApp& app, + const std::string& key) override; + virtual ErrorOr GetValue( + const PigeonFirebaseApp& app, const std::string& key) override; + virtual void SetConfigSettings( + const PigeonFirebaseApp& app, + const PigeonRemoteConfigSettings& remote_config_settings, + std::function reply)> result) override; + virtual void SetDefaults( + const PigeonFirebaseApp& app, + const flutter::EncodableMap& default_parameters, + std::function reply)> result) override; + + private: + bool rcInitialized = false; +}; + +} // namespace firebase_remote_config_windows + +#endif // FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin_c_api.cpp b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin_c_api.cpp new file mode 100644 index 000000000000..f20b22164198 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/firebase_remote_config_plugin_c_api.cpp @@ -0,0 +1,16 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "include/firebase_remote_config/firebase_remote_config_plugin_c_api.h" + +#include + +#include "firebase_remote_config_plugin.h" + +void FirebaseRemoteConfigPluginCApiRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + firebase_remote_config_windows::FirebaseRemoteConfigPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); +} diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/include/firebase_remote_config/firebase_remote_config_plugin_c_api.h b/packages/firebase_remote_config/firebase_remote_config/windows/include/firebase_remote_config/firebase_remote_config_plugin_c_api.h new file mode 100644 index 000000000000..f2b5d9b7d085 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/include/firebase_remote_config/firebase_remote_config_plugin_c_api.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023, the Chromium project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_C_API_H_ +#define FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_C_API_H_ + +#include + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +FLUTTER_PLUGIN_EXPORT void FirebaseRemoteConfigPluginCApiRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_PLUGIN_FIREBASE_REMOTE_CONFIG_PLUGIN_C_API_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.cpp b/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.cpp new file mode 100644 index 000000000000..287ae2b59430 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.cpp @@ -0,0 +1,622 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#undef _HAS_EXCEPTIONS + +#include "messages.g.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace firebase_remote_config_windows { +using flutter::BasicMessageChannel; +using flutter::CustomEncodableValue; +using flutter::EncodableList; +using flutter::EncodableMap; +using flutter::EncodableValue; + +// PigeonRemoteConfigSettings + +PigeonRemoteConfigSettings::PigeonRemoteConfigSettings( + int64_t fetch_timeout, + int64_t minimum_fetch_interval) + : fetch_timeout_(fetch_timeout), + minimum_fetch_interval_(minimum_fetch_interval) {} + +int64_t PigeonRemoteConfigSettings::fetch_timeout() const { + return fetch_timeout_; +} + +void PigeonRemoteConfigSettings::set_fetch_timeout(int64_t value_arg) { + fetch_timeout_ = value_arg; +} + + +int64_t PigeonRemoteConfigSettings::minimum_fetch_interval() const { + return minimum_fetch_interval_; +} + +void PigeonRemoteConfigSettings::set_minimum_fetch_interval(int64_t value_arg) { + minimum_fetch_interval_ = value_arg; +} + + +EncodableList PigeonRemoteConfigSettings::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(fetch_timeout_)); + list.push_back(EncodableValue(minimum_fetch_interval_)); + return list; +} + +PigeonRemoteConfigSettings PigeonRemoteConfigSettings::FromEncodableList(const EncodableList& list) { + PigeonRemoteConfigSettings decoded( + list[0].LongValue(), + list[1].LongValue()); + return decoded; +} + +// PigeonRemoteConfigValue + +PigeonRemoteConfigValue::PigeonRemoteConfigValue(const PigeonValueSource& source) + : source_(source) {} + +PigeonRemoteConfigValue::PigeonRemoteConfigValue( + const EncodableList* value, + const PigeonValueSource& source) + : value_(value ? std::optional(*value) : std::nullopt), + source_(source) {} + +const EncodableList* PigeonRemoteConfigValue::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PigeonRemoteConfigValue::set_value(const EncodableList* value_arg) { + value_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PigeonRemoteConfigValue::set_value(const EncodableList& value_arg) { + value_ = value_arg; +} + + +const PigeonValueSource& PigeonRemoteConfigValue::source() const { + return source_; +} + +void PigeonRemoteConfigValue::set_source(const PigeonValueSource& value_arg) { + source_ = value_arg; +} + + +EncodableList PigeonRemoteConfigValue::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(EncodableValue((int)source_)); + return list; +} + +PigeonRemoteConfigValue PigeonRemoteConfigValue::FromEncodableList(const EncodableList& list) { + PigeonRemoteConfigValue decoded( + (PigeonValueSource)(std::get(list[1]))); + auto& encodable_value = list[0]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get(encodable_value)); + } + return decoded; +} + +// PigeonFirebaseApp + +PigeonFirebaseApp::PigeonFirebaseApp(const std::string& app_name) + : app_name_(app_name) {} + +PigeonFirebaseApp::PigeonFirebaseApp( + const std::string& app_name, + const std::string* tenant_id) + : app_name_(app_name), + tenant_id_(tenant_id ? std::optional(*tenant_id) : std::nullopt) {} + +const std::string& PigeonFirebaseApp::app_name() const { + return app_name_; +} + +void PigeonFirebaseApp::set_app_name(std::string_view value_arg) { + app_name_ = value_arg; +} + + +const std::string* PigeonFirebaseApp::tenant_id() const { + return tenant_id_ ? &(*tenant_id_) : nullptr; +} + +void PigeonFirebaseApp::set_tenant_id(const std::string_view* value_arg) { + tenant_id_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PigeonFirebaseApp::set_tenant_id(std::string_view value_arg) { + tenant_id_ = value_arg; +} + + +EncodableList PigeonFirebaseApp::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(app_name_)); + list.push_back(tenant_id_ ? EncodableValue(*tenant_id_) : EncodableValue()); + return list; +} + +PigeonFirebaseApp PigeonFirebaseApp::FromEncodableList(const EncodableList& list) { + PigeonFirebaseApp decoded( + std::get(list[0])); + auto& encodable_tenant_id = list[1]; + if (!encodable_tenant_id.IsNull()) { + decoded.set_tenant_id(std::get(encodable_tenant_id)); + } + return decoded; +} + + +FirebaseRemoteConfigHostApiCodecSerializer::FirebaseRemoteConfigHostApiCodecSerializer() {} + +EncodableValue FirebaseRemoteConfigHostApiCodecSerializer::ReadValueOfType( + uint8_t type, + flutter::ByteStreamReader* stream) const { + switch (type) { + case 128: + return CustomEncodableValue(PigeonFirebaseApp::FromEncodableList(std::get(ReadValue(stream)))); + case 129: + return CustomEncodableValue(PigeonRemoteConfigSettings::FromEncodableList(std::get(ReadValue(stream)))); + case 130: + return CustomEncodableValue(PigeonRemoteConfigValue::FromEncodableList(std::get(ReadValue(stream)))); + default: + return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + } +} + +void FirebaseRemoteConfigHostApiCodecSerializer::WriteValue( + const EncodableValue& value, + flutter::ByteStreamWriter* stream) const { + if (const CustomEncodableValue* custom_value = std::get_if(&value)) { + if (custom_value->type() == typeid(PigeonFirebaseApp)) { + stream->WriteByte(128); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PigeonRemoteConfigSettings)) { + stream->WriteByte(129); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PigeonRemoteConfigValue)) { + stream->WriteByte(130); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + } + flutter::StandardCodecSerializer::WriteValue(value, stream); +} + +/// The codec used by FirebaseRemoteConfigHostApi. +const flutter::StandardMessageCodec& FirebaseRemoteConfigHostApi::GetCodec() { + return flutter::StandardMessageCodec::GetInstance(&FirebaseRemoteConfigHostApiCodecSerializer::GetInstance()); +} + +// Sets up an instance of `FirebaseRemoteConfigHostApi` to handle messages through the `binary_messenger`. +void FirebaseRemoteConfigHostApi::SetUp( + flutter::BinaryMessenger* binary_messenger, + FirebaseRemoteConfigHostApi* api) { + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + api->Activate(app_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + api->EnsureInitialized(app_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + api->Fetch(app_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + api->FetchAndActivate(app_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + ErrorOr output = api->GetAll(app_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_key_arg = args.at(1); + if (encodable_key_arg.IsNull()) { + reply(WrapError("key_arg unexpectedly null.")); + return; + } + const auto& key_arg = std::get(encodable_key_arg); + ErrorOr output = api->GetBool(app_arg, key_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_key_arg = args.at(1); + if (encodable_key_arg.IsNull()) { + reply(WrapError("key_arg unexpectedly null.")); + return; + } + const auto& key_arg = std::get(encodable_key_arg); + ErrorOr output = api->GetInt(app_arg, key_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_key_arg = args.at(1); + if (encodable_key_arg.IsNull()) { + reply(WrapError("key_arg unexpectedly null.")); + return; + } + const auto& key_arg = std::get(encodable_key_arg); + ErrorOr output = api->GetDouble(app_arg, key_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_key_arg = args.at(1); + if (encodable_key_arg.IsNull()) { + reply(WrapError("key_arg unexpectedly null.")); + return; + } + const auto& key_arg = std::get(encodable_key_arg); + ErrorOr output = api->GetString(app_arg, key_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_key_arg = args.at(1); + if (encodable_key_arg.IsNull()) { + reply(WrapError("key_arg unexpectedly null.")); + return; + } + const auto& key_arg = std::get(encodable_key_arg); + ErrorOr output = api->GetValue(app_arg, key_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(CustomEncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_remote_config_settings_arg = args.at(1); + if (encodable_remote_config_settings_arg.IsNull()) { + reply(WrapError("remote_config_settings_arg unexpectedly null.")); + return; + } + const auto& remote_config_settings_arg = std::any_cast(std::get(encodable_remote_config_settings_arg)); + api->SetConfigSettings(app_arg, remote_config_settings_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>(binary_messenger, "dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_arg = args.at(0); + if (encodable_app_arg.IsNull()) { + reply(WrapError("app_arg unexpectedly null.")); + return; + } + const auto& app_arg = std::any_cast(std::get(encodable_app_arg)); + const auto& encodable_default_parameters_arg = args.at(1); + if (encodable_default_parameters_arg.IsNull()) { + reply(WrapError("default_parameters_arg unexpectedly null.")); + return; + } + const auto& default_parameters_arg = std::get(encodable_default_parameters_arg); + api->SetDefaults(app_arg, default_parameters_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } +} + +EncodableValue FirebaseRemoteConfigHostApi::WrapError(std::string_view error_message) { + return EncodableValue(EncodableList{ + EncodableValue(std::string(error_message)), + EncodableValue("Error"), + EncodableValue() + }); +} + +EncodableValue FirebaseRemoteConfigHostApi::WrapError(const FlutterError& error) { + return EncodableValue(EncodableList{ + EncodableValue(error.code()), + EncodableValue(error.message()), + error.details() + }); +} + +} // namespace firebase_remote_config_windows diff --git a/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.h b/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.h new file mode 100644 index 000000000000..373c43811797 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config/windows/messages.g.h @@ -0,0 +1,245 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#ifndef PIGEON_MESSAGES_G_H_ +#define PIGEON_MESSAGES_G_H_ +#include +#include +#include +#include + +#include +#include +#include + +namespace firebase_remote_config_windows { + + +// Generated class from Pigeon. + +class FlutterError { + public: + explicit FlutterError(const std::string& code) + : code_(code) {} + explicit FlutterError(const std::string& code, const std::string& message) + : code_(code), message_(message) {} + explicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) + : code_(code), message_(message), details_(details) {} + + const std::string& code() const { return code_; } + const std::string& message() const { return message_; } + const flutter::EncodableValue& details() const { return details_; } + + private: + std::string code_; + std::string message_; + flutter::EncodableValue details_; +}; + +template class ErrorOr { + public: + ErrorOr(const T& rhs) : v_(rhs) {} + ErrorOr(const T&& rhs) : v_(std::move(rhs)) {} + ErrorOr(const FlutterError& rhs) : v_(rhs) {} + ErrorOr(const FlutterError&& rhs) : v_(std::move(rhs)) {} + + bool has_error() const { return std::holds_alternative(v_); } + const T& value() const { return std::get(v_); }; + const FlutterError& error() const { return std::get(v_); }; + + private: + friend class FirebaseRemoteConfigHostApi; + ErrorOr() = default; + T TakeValue() && { return std::get(std::move(v_)); } + + std::variant v_; +}; + + +// ValueSource defines the possible sources of a config parameter value. +enum class PigeonValueSource { + // The value was defined by a static constant. + valueStatic = 0, + // The value was defined by default config. + valueDefault = 1, + // The value was defined by fetched config. + valueRemote = 2 +}; + +enum class PigeonRemoteConfigFetchStatus { + // Indicates instance has not yet attempted a fetch. + noFetchYet = 0, + // Indicates the last fetch attempt succeeded. + success = 1, + // Indicates the last fetch attempt failed. + failure = 2, + // Indicates the last fetch attempt was rate-limited. + throttle = 3 +}; + +// Generated class from Pigeon that represents data sent in messages. +class PigeonRemoteConfigSettings { + public: + // Constructs an object setting all fields. + explicit PigeonRemoteConfigSettings( + int64_t fetch_timeout, + int64_t minimum_fetch_interval); + + int64_t fetch_timeout() const; + void set_fetch_timeout(int64_t value_arg); + + int64_t minimum_fetch_interval() const; + void set_minimum_fetch_interval(int64_t value_arg); + + + private: + static PigeonRemoteConfigSettings FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebaseRemoteConfigHostApi; + friend class FirebaseRemoteConfigHostApiCodecSerializer; + int64_t fetch_timeout_; + int64_t minimum_fetch_interval_; + +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PigeonRemoteConfigValue { + public: + // Constructs an object setting all non-nullable fields. + explicit PigeonRemoteConfigValue(const PigeonValueSource& source); + + // Constructs an object setting all fields. + explicit PigeonRemoteConfigValue( + const flutter::EncodableList* value, + const PigeonValueSource& source); + + const flutter::EncodableList* value() const; + void set_value(const flutter::EncodableList* value_arg); + void set_value(const flutter::EncodableList& value_arg); + + // Indicates at which source this value came from. + const PigeonValueSource& source() const; + void set_source(const PigeonValueSource& value_arg); + + + private: + static PigeonRemoteConfigValue FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebaseRemoteConfigHostApi; + friend class FirebaseRemoteConfigHostApiCodecSerializer; + std::optional value_; + PigeonValueSource source_; + +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PigeonFirebaseApp { + public: + // Constructs an object setting all non-nullable fields. + explicit PigeonFirebaseApp(const std::string& app_name); + + // Constructs an object setting all fields. + explicit PigeonFirebaseApp( + const std::string& app_name, + const std::string* tenant_id); + + const std::string& app_name() const; + void set_app_name(std::string_view value_arg); + + const std::string* tenant_id() const; + void set_tenant_id(const std::string_view* value_arg); + void set_tenant_id(std::string_view value_arg); + + + private: + static PigeonFirebaseApp FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebaseRemoteConfigHostApi; + friend class FirebaseRemoteConfigHostApiCodecSerializer; + std::string app_name_; + std::optional tenant_id_; + +}; + +class FirebaseRemoteConfigHostApiCodecSerializer : public flutter::StandardCodecSerializer { + public: + FirebaseRemoteConfigHostApiCodecSerializer(); + inline static FirebaseRemoteConfigHostApiCodecSerializer& GetInstance() { + static FirebaseRemoteConfigHostApiCodecSerializer sInstance; + return sInstance; + } + + void WriteValue( + const flutter::EncodableValue& value, + flutter::ByteStreamWriter* stream) const override; + + protected: + flutter::EncodableValue ReadValueOfType( + uint8_t type, + flutter::ByteStreamReader* stream) const override; + +}; + +// Generated interface from Pigeon that represents a handler of messages from Flutter. +class FirebaseRemoteConfigHostApi { + public: + FirebaseRemoteConfigHostApi(const FirebaseRemoteConfigHostApi&) = delete; + FirebaseRemoteConfigHostApi& operator=(const FirebaseRemoteConfigHostApi&) = delete; + virtual ~FirebaseRemoteConfigHostApi() {} + virtual void Activate( + const PigeonFirebaseApp& app, + std::function reply)> result) = 0; + virtual void EnsureInitialized( + const PigeonFirebaseApp& app, + std::function reply)> result) = 0; + virtual void Fetch( + const PigeonFirebaseApp& app, + std::function reply)> result) = 0; + virtual void FetchAndActivate( + const PigeonFirebaseApp& app, + std::function reply)> result) = 0; + virtual ErrorOr GetAll(const PigeonFirebaseApp& app) = 0; + virtual ErrorOr GetBool( + const PigeonFirebaseApp& app, + const std::string& key) = 0; + virtual ErrorOr GetInt( + const PigeonFirebaseApp& app, + const std::string& key) = 0; + virtual ErrorOr GetDouble( + const PigeonFirebaseApp& app, + const std::string& key) = 0; + virtual ErrorOr GetString( + const PigeonFirebaseApp& app, + const std::string& key) = 0; + virtual ErrorOr GetValue( + const PigeonFirebaseApp& app, + const std::string& key) = 0; + virtual void SetConfigSettings( + const PigeonFirebaseApp& app, + const PigeonRemoteConfigSettings& remote_config_settings, + std::function reply)> result) = 0; + virtual void SetDefaults( + const PigeonFirebaseApp& app, + const flutter::EncodableMap& default_parameters, + std::function reply)> result) = 0; + + // The codec used by FirebaseRemoteConfigHostApi. + static const flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `FirebaseRemoteConfigHostApi` to handle messages through the `binary_messenger`. + static void SetUp( + flutter::BinaryMessenger* binary_messenger, + FirebaseRemoteConfigHostApi* api); + static flutter::EncodableValue WrapError(std::string_view error_message); + static flutter::EncodableValue WrapError(const FlutterError& error); + + protected: + FirebaseRemoteConfigHostApi() = default; + +}; +} // namespace firebase_remote_config_windows +#endif // PIGEON_MESSAGES_G_H_ diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/firebase_remote_config_platform_interface.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/firebase_remote_config_platform_interface.dart index c21f3d5a68c2..612869d44898 100644 --- a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/firebase_remote_config_platform_interface.dart +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/firebase_remote_config_platform_interface.dart @@ -10,3 +10,9 @@ export 'src/remote_config_settings.dart'; export 'src/remote_config_status.dart'; export 'src/remote_config_update.dart'; export 'src/remote_config_value.dart'; +export 'src/pigeon/messages.pigeon.dart' + show + PigeonRemoteConfigSettings, + PigeonRemoteConfigValue, + PigeonRemoteConfigFetchStatus, + PigeonValueSource; diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/method_channel/method_channel_firebase_remote_config.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/method_channel/method_channel_firebase_remote_config.dart index f916e466fc49..16d852169a0d 100644 --- a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/method_channel/method_channel_firebase_remote_config.dart +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/method_channel/method_channel_firebase_remote_config.dart @@ -4,9 +4,12 @@ // ignore_for_file: require_trailing_commas import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; +import 'package:firebase_remote_config_platform_interface/src/pigeon/messages.pigeon.dart'; import '../../firebase_remote_config_platform_interface.dart'; import 'utils/exception.dart'; @@ -23,6 +26,8 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { /// is initialized via the [delegateFor] method. MethodChannelFirebaseRemoteConfig._() : super(appInstance: null); + final _api = FirebaseRemoteConfigHostApi(); + /// Keeps an internal handle ID for the channel. static int _methodChannelHandleId = 0; @@ -43,10 +48,41 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { return MethodChannelFirebaseRemoteConfig._(); } - late Map _activeParameters; - late RemoteConfigSettings _settings; + late Map _activeParameters; + late PigeonRemoteConfigSettings _settings; late DateTime _lastFetchTime; - late RemoteConfigFetchStatus _lastFetchStatus; + late PigeonRemoteConfigFetchStatus _lastFetchStatus; + + PigeonFirebaseApp get pigeonDefault { + return PigeonFirebaseApp( + appName: app.name, + tenantId: tenantId, + ); + } + + @override + RemoteConfigSettings getSettings() { + return RemoteConfigSettings( + fetchTimeout: Duration(seconds: _settings.fetchTimeout), + minimumFetchInterval: + Duration(seconds: _settings.minimumFetchInterval)); + } + + @override + RemoteConfigFetchStatus getFetchStatus() { + switch (_lastFetchStatus) { + case PigeonRemoteConfigFetchStatus.noFetchYet: + return RemoteConfigFetchStatus.noFetchYet; + case PigeonRemoteConfigFetchStatus.success: + return RemoteConfigFetchStatus.success; + case PigeonRemoteConfigFetchStatus.failure: + return RemoteConfigFetchStatus.failure; + case PigeonRemoteConfigFetchStatus.throttle: + return RemoteConfigFetchStatus.throttle; + default: + return RemoteConfigFetchStatus.noFetchYet; + } + } /// Gets a [FirebaseRemoteConfigPlatform] instance for a specific /// [FirebaseApp]. @@ -64,34 +100,44 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { FirebaseRemoteConfigPlatform setInitialValues({ required Map remoteConfigValues, }) { - final fetchTimeout = Duration(seconds: remoteConfigValues['fetchTimeout']); - final minimumFetchInterval = - Duration(seconds: remoteConfigValues['minimumFetchInterval']); - final lastFetchMillis = remoteConfigValues['lastFetchTime']; - final lastFetchStatus = remoteConfigValues['lastFetchStatus']; - - _settings = RemoteConfigSettings( - fetchTimeout: fetchTimeout, - minimumFetchInterval: minimumFetchInterval, + final fetchTimeout = remoteConfigValues.isEmpty + ? const Duration(seconds: 60) + : Duration(seconds: remoteConfigValues['fetchTimeout']); + final minimumFetchInterval = remoteConfigValues.isEmpty + ? const Duration(hours: 12) + : Duration(seconds: remoteConfigValues['minimumFetchInterval']); + final lastFetchMillis = + remoteConfigValues.isEmpty ? 0 : remoteConfigValues['lastFetchTime']; + final lastFetchStatus = remoteConfigValues.isEmpty + ? 'noFetchYet' + : remoteConfigValues['lastFetchStatus']; + + _settings = PigeonRemoteConfigSettings( + fetchTimeout: fetchTimeout.inSeconds, + minimumFetchInterval: minimumFetchInterval.inSeconds, ); _lastFetchTime = DateTime.fromMillisecondsSinceEpoch(lastFetchMillis); _lastFetchStatus = _parseFetchStatus(lastFetchStatus); - _activeParameters = _parseParameters(remoteConfigValues['parameters']); + if (remoteConfigValues.isNotEmpty) { + _activeParameters = + _parsePigeonParameters(remoteConfigValues['parameters']); + } + return this; } - RemoteConfigFetchStatus _parseFetchStatus(String? status) { + PigeonRemoteConfigFetchStatus _parseFetchStatus(String? status) { switch (status) { case 'noFetchYet': - return RemoteConfigFetchStatus.noFetchYet; + return PigeonRemoteConfigFetchStatus.noFetchYet; case 'success': - return RemoteConfigFetchStatus.success; + return PigeonRemoteConfigFetchStatus.success; case 'failure': - return RemoteConfigFetchStatus.failure; + return PigeonRemoteConfigFetchStatus.failure; case 'throttle': - return RemoteConfigFetchStatus.throttle; + return PigeonRemoteConfigFetchStatus.throttle; default: - return RemoteConfigFetchStatus.noFetchYet; + return PigeonRemoteConfigFetchStatus.noFetchYet; } } @@ -99,18 +145,15 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { DateTime get lastFetchTime => _lastFetchTime; @override - RemoteConfigFetchStatus get lastFetchStatus => _lastFetchStatus; + PigeonRemoteConfigFetchStatus get lastFetchStatus => _lastFetchStatus; @override - RemoteConfigSettings get settings => _settings; + PigeonRemoteConfigSettings get settings => _settings; @override Future ensureInitialized() async { try { - await channel.invokeMethod( - 'RemoteConfig#ensureInitialized', { - 'appName': app.name, - }); + await _api.ensureInitialized(pigeonDefault); } catch (exception, stackTrace) { convertPlatformException(exception, stackTrace); } @@ -119,12 +162,9 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { @override Future activate() async { try { - bool? configChanged = await channel - .invokeMethod('RemoteConfig#activate', { - 'appName': app.name, - }); + bool configChanged = await _api.activate(pigeonDefault); await _updateConfigParameters(); - return configChanged!; + return configChanged; } catch (exception, stackTrace) { convertPlatformException(exception, stackTrace); } @@ -133,13 +173,11 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { @override Future fetch() async { try { - await channel.invokeMethod('RemoteConfig#fetch', { - 'appName': app.name, - }); - await _updateConfigProperties(); + await _api.fetch(pigeonDefault); + // await _updateConfigProperties(); } catch (exception, stackTrace) { // Ensure that fetch status is updated. - await _updateConfigProperties(); + // await _updateConfigProperties(); convertPlatformException(exception, stackTrace); } } @@ -147,31 +185,41 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { @override Future fetchAndActivate() async { try { - bool? configChanged = await channel.invokeMethod( - 'RemoteConfig#fetchAndActivate', { - 'appName': app.name, - }); + log('method_remote_config fetchAndActivate'); + bool configChanged = await _api.fetchAndActivate(pigeonDefault); await _updateConfigParameters(); - await _updateConfigProperties(); - return configChanged!; + //await _updateConfigProperties(); + return configChanged; } catch (exception, stackTrace) { // Ensure that fetch status is updated. - await _updateConfigProperties(); + // await _updateConfigProperties(); convertPlatformException(exception, stackTrace); } } @override - Map getAll() { + Map getAll() { return _activeParameters; } + @override + Map getAllConverted() { + var parameters = {}; + for (final key in _activeParameters.keys) { + final rawValue = _activeParameters[key]!.value; + + parameters[key] = RemoteConfigValue(_pigoenListIntToListInt(rawValue!), + _pigeonToValueSource(_activeParameters[key]!.source)); + } + return parameters; + } + @override bool getBool(String key) { if (!_activeParameters.containsKey(key)) { return RemoteConfigValue.defaultValueForBool; } - return _activeParameters[key]!.asBool(); + return _pigeonValueToBool(_activeParameters[key]!); } @override @@ -179,7 +227,7 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { if (!_activeParameters.containsKey(key)) { return RemoteConfigValue.defaultValueForInt; } - return _activeParameters[key]!.asInt(); + return _pigeonValueToInt(_activeParameters[key]!); } @override @@ -187,7 +235,7 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { if (!_activeParameters.containsKey(key)) { return RemoteConfigValue.defaultValueForDouble; } - return _activeParameters[key]!.asDouble(); + return _pigeonValueToDouble(_activeParameters[key]!); } @override @@ -195,30 +243,42 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { if (!_activeParameters.containsKey(key)) { return RemoteConfigValue.defaultValueForString; } - return _activeParameters[key]!.asString(); + return _pigeonValueToString(_activeParameters[key]!); } @override - RemoteConfigValue getValue(String key) { + PigeonRemoteConfigValue getValue(String key) { if (!_activeParameters.containsKey(key)) { - return RemoteConfigValue(null, ValueSource.valueStatic); + return PigeonRemoteConfigValue(source: PigeonValueSource.valueStatic); } return _activeParameters[key]!; } + @override + RemoteConfigValue getValueConverted(String key) { + var pigeonValue = getValue(key); + return RemoteConfigValue(_pigoenListIntToListInt(pigeonValue.value!), + _pigeonToValueSource(pigeonValue.source)); + } + + @override + Future setConfigSettingsConverted( + RemoteConfigSettings remoteConfigSettings) { + log('method remote config setConfigSettingsConverted'); + var pigeonSettings = PigeonRemoteConfigSettings( + fetchTimeout: remoteConfigSettings.fetchTimeout.inSeconds, + minimumFetchInterval: + remoteConfigSettings.minimumFetchInterval.inSeconds); + return setConfigSettings(pigeonSettings); + } + @override Future setConfigSettings( - RemoteConfigSettings remoteConfigSettings, + PigeonRemoteConfigSettings pigeonRemoteConfigSettings, ) async { try { - await channel - .invokeMethod('RemoteConfig#setConfigSettings', { - 'appName': app.name, - 'fetchTimeout': remoteConfigSettings.fetchTimeout.inSeconds, - 'minimumFetchInterval': - remoteConfigSettings.minimumFetchInterval.inSeconds, - }); - await _updateConfigProperties(); + await _api.setConfigSettings(pigeonDefault, pigeonRemoteConfigSettings); + //await _updateConfigProperties(); } catch (exception, stackTrace) { convertPlatformException(exception, stackTrace); } @@ -227,10 +287,7 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { @override Future setDefaults(Map defaultParameters) async { try { - await channel.invokeMethod('RemoteConfig#setDefaults', { - 'appName': app.name, - 'defaults': defaultParameters - }); + await _api.setDefaults(pigeonDefault, defaultParameters); await _updateConfigParameters(); } catch (exception, stackTrace) { convertPlatformException(exception, stackTrace); @@ -238,12 +295,8 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { } Future _updateConfigParameters() async { - Map? parameters = await channel - .invokeMapMethod( - 'RemoteConfig#getAll', { - 'appName': app.name, - }); - _activeParameters = _parseParameters(parameters!); + Map? parameters = await _api.getAll(pigeonDefault); + _activeParameters = _parsePigeonParameters(parameters!); } Future _updateConfigProperties() async { @@ -258,9 +311,9 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { final lastFetchMillis = properties['lastFetchTime']; final lastFetchStatus = properties['lastFetchStatus']; - _settings = RemoteConfigSettings( - fetchTimeout: fetchTimeout, - minimumFetchInterval: minimumFetchInterval, + _settings = PigeonRemoteConfigSettings( + fetchTimeout: fetchTimeout.inSeconds, + minimumFetchInterval: minimumFetchInterval.inSeconds, ); _lastFetchTime = DateTime.fromMillisecondsSinceEpoch(lastFetchMillis); _lastFetchStatus = _parseFetchStatus(lastFetchStatus); @@ -277,6 +330,18 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { return parameters; } + Map _parsePigeonParameters( + Map rawParameters) { + var parameters = {}; + for (final key in rawParameters.keys) { + final rawValue = rawParameters[key]; + parameters[key] = PigeonRemoteConfigValue( + value: rawValue['value'], + source: _valueSourceToPigeon(_parseValueSource(rawValue['source']))); + } + return parameters; + } + ValueSource _parseValueSource(String? sourceStr) { switch (sourceStr) { case 'static': @@ -302,4 +367,85 @@ class MethodChannelFirebaseRemoteConfig extends FirebaseRemoteConfigPlatform { return RemoteConfigUpdate(updatedKeys); }); } + + PigeonValueSource _valueSourceToPigeon(ValueSource source) { + switch (source) { + case ValueSource.valueDefault: + return PigeonValueSource.valueDefault; + case ValueSource.valueRemote: + return PigeonValueSource.valueRemote; + case ValueSource.valueStatic: + default: + return PigeonValueSource.valueStatic; + } + } + + ValueSource _pigeonToValueSource(PigeonValueSource source) { + switch (source) { + case PigeonValueSource.valueDefault: + return ValueSource.valueDefault; + case PigeonValueSource.valueRemote: + return ValueSource.valueRemote; + case PigeonValueSource.valueStatic: + default: + return ValueSource.valueStatic; + } + } + + static int _pigeonValueToInt(PigeonRemoteConfigValue pigeonValue) { + final value = pigeonValue.value; + if (value != null) { + final String strValue = + const Utf8Codec().decode(_pigoenListIntToListInt(value)); + final int intValue = + int.tryParse(strValue) ?? RemoteConfigValue.defaultValueForInt; + return intValue; + } else { + return RemoteConfigValue.defaultValueForInt; + } + } + + static String _pigeonValueToString(PigeonRemoteConfigValue pigeonValue) { + final value = pigeonValue.value; + return value != null + ? const Utf8Codec().decode(_pigoenListIntToListInt(value)) + : RemoteConfigValue.defaultValueForString; + } + + /// Decode value to double. + static double _pigeonValueToDouble(PigeonRemoteConfigValue pigeonValue) { + final value = pigeonValue.value; + if (value != null) { + final String strValue = + const Utf8Codec().decode(_pigoenListIntToListInt(value)); + final double doubleValue = + double.tryParse(strValue) ?? RemoteConfigValue.defaultValueForDouble; + return doubleValue; + } else { + return RemoteConfigValue.defaultValueForDouble; + } + } + + /// Decode value to bool. + static bool _pigeonValueToBool(PigeonRemoteConfigValue pigeonValue) { + final value = pigeonValue.value; + if (value != null) { + final String strValue = + const Utf8Codec().decode(_pigoenListIntToListInt(value)); + final lowerCase = strValue.toLowerCase(); + return lowerCase == 'true' || lowerCase == '1'; + } else { + return RemoteConfigValue.defaultValueForBool; + } + } + + static List _pigoenListIntToListInt(List list) { + List newList = []; + for (final int? element in list) { + if (element != null) { + newList.add(element); + } + } + return newList; + } } diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/messages.pigeon.dart new file mode 100644 index 000000000000..7658b6c4404a --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -0,0 +1,460 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +/// ValueSource defines the possible sources of a config parameter value. +enum PigeonValueSource { + /// The value was defined by a static constant. + valueStatic, + /// The value was defined by default config. + valueDefault, + /// The value was defined by fetched config. + valueRemote, +} + +enum PigeonRemoteConfigFetchStatus { + /// Indicates instance has not yet attempted a fetch. + noFetchYet, + /// Indicates the last fetch attempt succeeded. + success, + /// Indicates the last fetch attempt failed. + failure, + /// Indicates the last fetch attempt was rate-limited. + throttle, +} + +class PigeonRemoteConfigSettings { + PigeonRemoteConfigSettings({ + required this.fetchTimeout, + required this.minimumFetchInterval, + }); + + int fetchTimeout; + + int minimumFetchInterval; + + Object encode() { + return [ + fetchTimeout, + minimumFetchInterval, + ]; + } + + static PigeonRemoteConfigSettings decode(Object result) { + result as List; + return PigeonRemoteConfigSettings( + fetchTimeout: result[0]! as int, + minimumFetchInterval: result[1]! as int, + ); + } +} + +class PigeonRemoteConfigValue { + PigeonRemoteConfigValue({ + this.value, + required this.source, + }); + + List? value; + + /// Indicates at which source this value came from. + PigeonValueSource source; + + Object encode() { + return [ + value, + source.index, + ]; + } + + static PigeonRemoteConfigValue decode(Object result) { + result as List; + return PigeonRemoteConfigValue( + value: (result[0] as List?)?.cast(), + source: PigeonValueSource.values[result[1]! as int], + ); + } +} + +class PigeonFirebaseApp { + PigeonFirebaseApp({ + required this.appName, + this.tenantId, + }); + + String appName; + + String? tenantId; + + Object encode() { + return [ + appName, + tenantId, + ]; + } + + static PigeonFirebaseApp decode(Object result) { + result as List; + return PigeonFirebaseApp( + appName: result[0]! as String, + tenantId: result[1] as String?, + ); + } +} + +class _FirebaseRemoteConfigHostApiCodec extends StandardMessageCodec { + const _FirebaseRemoteConfigHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is PigeonFirebaseApp) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is PigeonRemoteConfigSettings) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is PigeonRemoteConfigValue) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return PigeonFirebaseApp.decode(readValue(buffer)!); + case 129: + return PigeonRemoteConfigSettings.decode(readValue(buffer)!); + case 130: + return PigeonRemoteConfigValue.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class FirebaseRemoteConfigHostApi { + /// Constructor for [FirebaseRemoteConfigHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + FirebaseRemoteConfigHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _FirebaseRemoteConfigHostApiCodec(); + + Future activate(PigeonFirebaseApp arg_app) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as bool?)!; + } + } + + Future ensureInitialized(PigeonFirebaseApp arg_app) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future fetch(PigeonFirebaseApp arg_app) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future fetchAndActivate(PigeonFirebaseApp arg_app) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as bool?)!; + } + } + + Future> getAll(PigeonFirebaseApp arg_app) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as Map?)!.cast(); + } + } + + Future getBool(PigeonFirebaseApp arg_app, String arg_key) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_key]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as bool?)!; + } + } + + Future getInt(PigeonFirebaseApp arg_app, String arg_key) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_key]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as int?)!; + } + } + + Future getDouble(PigeonFirebaseApp arg_app, String arg_key) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_key]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as double?)!; + } + } + + Future getString(PigeonFirebaseApp arg_app, String arg_key) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_key]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } + + Future getValue(PigeonFirebaseApp arg_app, String arg_key) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_key]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as PigeonRemoteConfigValue?)!; + } + } + + Future setConfigSettings(PigeonFirebaseApp arg_app, PigeonRemoteConfigSettings arg_remoteConfigSettings) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_remoteConfigSettings]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future setDefaults(PigeonFirebaseApp arg_app, Map arg_defaultParameters) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_app, arg_defaultParameters]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/test_api.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/test_api.dart new file mode 100644 index 000000000000..f0e8b0365a0b --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/lib/src/pigeon/test_api.dart @@ -0,0 +1,328 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import +// ignore_for_file: avoid_relative_lib_imports +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'messages.pigeon.dart'; + +class _TestFirebaseRemoteConfigHostApiCodec extends StandardMessageCodec { + const _TestFirebaseRemoteConfigHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is PigeonFirebaseApp) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is PigeonRemoteConfigSettings) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is PigeonRemoteConfigValue) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return PigeonFirebaseApp.decode(readValue(buffer)!); + case 129: + return PigeonRemoteConfigSettings.decode(readValue(buffer)!); + case 130: + return PigeonRemoteConfigValue.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class TestFirebaseRemoteConfigHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = _TestFirebaseRemoteConfigHostApiCodec(); + + Future activate(PigeonFirebaseApp app); + + Future ensureInitialized(PigeonFirebaseApp app); + + Future fetch(PigeonFirebaseApp app); + + Future fetchAndActivate(PigeonFirebaseApp app); + + Map getAll(PigeonFirebaseApp app); + + bool getBool(PigeonFirebaseApp app, String key); + + int getInt(PigeonFirebaseApp app, String key); + + double getDouble(PigeonFirebaseApp app, String key); + + String getString(PigeonFirebaseApp app, String key); + + PigeonRemoteConfigValue getValue(PigeonFirebaseApp app, String key); + + Future setConfigSettings(PigeonFirebaseApp app, PigeonRemoteConfigSettings remoteConfigSettings); + + Future setDefaults(PigeonFirebaseApp app, Map defaultParameters); + + static void setup(TestFirebaseRemoteConfigHostApi? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.activate was null, expected non-null PigeonFirebaseApp.'); + final bool output = await api.activate(arg_app!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.ensureInitialized was null, expected non-null PigeonFirebaseApp.'); + await api.ensureInitialized(arg_app!); + return []; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetch was null, expected non-null PigeonFirebaseApp.'); + await api.fetch(arg_app!); + return []; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.fetchAndActivate was null, expected non-null PigeonFirebaseApp.'); + final bool output = await api.fetchAndActivate(arg_app!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getAll was null, expected non-null PigeonFirebaseApp.'); + final Map output = api.getAll(arg_app!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool was null, expected non-null PigeonFirebaseApp.'); + final String? arg_key = (args[1] as String?); + assert(arg_key != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getBool was null, expected non-null String.'); + final bool output = api.getBool(arg_app!, arg_key!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt was null, expected non-null PigeonFirebaseApp.'); + final String? arg_key = (args[1] as String?); + assert(arg_key != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getInt was null, expected non-null String.'); + final int output = api.getInt(arg_app!, arg_key!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble was null, expected non-null PigeonFirebaseApp.'); + final String? arg_key = (args[1] as String?); + assert(arg_key != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getDouble was null, expected non-null String.'); + final double output = api.getDouble(arg_app!, arg_key!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString was null, expected non-null PigeonFirebaseApp.'); + final String? arg_key = (args[1] as String?); + assert(arg_key != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getString was null, expected non-null String.'); + final String output = api.getString(arg_app!, arg_key!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue was null, expected non-null PigeonFirebaseApp.'); + final String? arg_key = (args[1] as String?); + assert(arg_key != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.getValue was null, expected non-null String.'); + final PigeonRemoteConfigValue output = api.getValue(arg_app!, arg_key!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings was null, expected non-null PigeonFirebaseApp.'); + final PigeonRemoteConfigSettings? arg_remoteConfigSettings = (args[1] as PigeonRemoteConfigSettings?); + assert(arg_remoteConfigSettings != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setConfigSettings was null, expected non-null PigeonRemoteConfigSettings.'); + await api.setConfigSettings(arg_app!, arg_remoteConfigSettings!); + return []; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults was null.'); + final List args = (message as List?)!; + final PigeonFirebaseApp? arg_app = (args[0] as PigeonFirebaseApp?); + assert(arg_app != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults was null, expected non-null PigeonFirebaseApp.'); + final Map? arg_defaultParameters = (args[1] as Map?)?.cast(); + assert(arg_defaultParameters != null, + 'Argument for dev.flutter.pigeon.FirebaseRemoteConfigHostApi.setDefaults was null, expected non-null Map.'); + await api.setDefaults(arg_app!, arg_defaultParameters!); + return []; + }); + } + } + } +} 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 51710973ee8d..c678963f260a 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 @@ -9,6 +9,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:firebase_remote_config_platform_interface/src/pigeon/messages.pigeon.dart'; import '../../firebase_remote_config_platform_interface.dart'; import '../method_channel/method_channel_firebase_remote_config.dart'; @@ -42,6 +43,11 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { static FirebaseRemoteConfigPlatform? _instance; + /// The current RemoteConfig instance's tenant ID. + /// + /// When you set the tenant ID of an RemoteConfig instance. + String? tenantId; + /// The current default [FirebaseRemoteConfigPlatform] instance. /// /// It will always default to [MethodChannelFirebaseRemoteConfig] @@ -91,12 +97,12 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { } /// Returns the status of the last fetch attempt. - RemoteConfigFetchStatus get lastFetchStatus { + PigeonRemoteConfigFetchStatus get lastFetchStatus { throw UnimplementedError('lastFetchStatus getter not implemented'); } - /// Returns the [RemoteConfigSettings] of the current instance. - RemoteConfigSettings get settings { + /// Returns the [PigeonRemoteConfigSettings] of the current instance. + PigeonRemoteConfigSettings get settings { throw UnimplementedError('settings getter not implemented'); } @@ -130,7 +136,7 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { } /// Returns a Map of all Remote Config parameters. - Map getAll() { + Map getAll() { throw UnimplementedError('getAll() is not implemented'); } @@ -163,12 +169,13 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { } /// Gets the [RemoteConfigValue] for a given key. - RemoteConfigValue getValue(String key) { + PigeonRemoteConfigValue getValue(String key) { throw UnimplementedError('getValue() is not implemented'); } /// Sets the [RemoteConfigSettings] for the current instance. - Future setConfigSettings(RemoteConfigSettings remoteConfigSettings) { + Future setConfigSettings( + PigeonRemoteConfigSettings pigeonRemoteConfigSettings) { throw UnimplementedError('setConfigSettings() is not implemented'); } @@ -181,4 +188,25 @@ abstract class FirebaseRemoteConfigPlatform extends PlatformInterface { Stream get onConfigUpdated { throw UnimplementedError('onConfigUpdated getter not implemented'); } + + RemoteConfigSettings getSettings() { + throw UnimplementedError('getSettings() is not implemented'); + } + + RemoteConfigFetchStatus getFetchStatus() { + throw UnimplementedError('getFetchStatus() is not implemented'); + } + + Map getAllConverted() { + throw UnimplementedError('getAllConverted() is not implemented'); + } + + RemoteConfigValue getValueConverted(String key) { + throw UnimplementedError('getValueConverted() is not implemented'); + } + + Future setConfigSettingsConverted( + RemoteConfigSettings remoteConfigSettings) { + throw UnimplementedError('setConfigSettingsConverted() is not implemented'); + } } diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/copyright.txt b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/copyright.txt new file mode 100644 index 000000000000..42fc84b1210b --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2023, the Chromium project authors. Please see the AUTHORS file +for details. All rights reserved. Use of this source code is governed by a +BSD-style license that can be found in the LICENSE file. \ No newline at end of file diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/messages.dart b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/messages.dart new file mode 100644 index 000000000000..b4ad4ddae011 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pigeons/messages.dart @@ -0,0 +1,135 @@ +// Copyright 2022, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/pigeon/messages.pigeon.dart', + // We export in the lib folder to expose the class to other packages. + dartTestOut: 'lib/src/pigeon/test_api.dart', + javaOut: + '../firebase_remote_config/android/src/main/java/io/flutter/plugins/firebase/firebaseremoteconfig/GeneratedAndroidFirebaseRemoteConfig.java', + javaOptions: JavaOptions( + package: 'io.flutter.plugins.firebase.remoteconfig', + className: 'GeneratedAndroidFirebaseRemoteConfig', + ), + objcHeaderOut: '../firebase_remote_config/ios/Classes/messages.g.h', + objcSourceOut: '../firebase_remote_config/ios/Classes/messages.g.m', + cppHeaderOut: '../firebase_remote_config/windows/messages.g.h', + cppSourceOut: '../firebase_remote_config/windows/messages.g.cpp', + cppOptions: CppOptions(namespace: 'firebase_remote_config_windows'), + copyrightHeader: 'pigeons/copyright.txt', + ), +) + +/// ValueSource defines the possible sources of a config parameter value. +enum PigeonValueSource { + /// The value was defined by a static constant. + valueStatic, + + /// The value was defined by default config. + valueDefault, + + /// The value was defined by fetched config. + valueRemote, +} + +enum PigeonRemoteConfigFetchStatus { + /// Indicates instance has not yet attempted a fetch. + noFetchYet, + + /// Indicates the last fetch attempt succeeded. + success, + + /// Indicates the last fetch attempt failed. + failure, + + /// Indicates the last fetch attempt was rate-limited. + throttle +} + +class PigeonRemoteConfigSettings { + PigeonRemoteConfigSettings({ + required this.fetchTimeout, + required this.minimumFetchInterval, + }); + + final int fetchTimeout; + + final int minimumFetchInterval; +} + +class PigeonRemoteConfigValue { + PigeonRemoteConfigValue(this.value, this.source); + + List? value; + + /// Indicates at which source this value came from. + final PigeonValueSource source; +} + +class PigeonFirebaseApp { + const PigeonFirebaseApp({ + required this.appName, + required this.tenantId, + }); + + final String appName; + final String? tenantId; +} + +@HostApi(dartHostTestHandler: 'TestFirebaseRemoteConfigHostApi') +abstract class FirebaseRemoteConfigHostApi { + @async + bool activate(PigeonFirebaseApp app); + + @async + void ensureInitialized(PigeonFirebaseApp app); + + @async + void fetch(PigeonFirebaseApp app); + + @async + bool fetchAndActivate(PigeonFirebaseApp app); + + Map getAll(PigeonFirebaseApp app); + + bool getBool( + PigeonFirebaseApp app, + String key, + ); + + int getInt( + PigeonFirebaseApp app, + String key, + ); + + double getDouble( + PigeonFirebaseApp app, + String key, + ); + + String getString( + PigeonFirebaseApp app, + String key, + ); + + PigeonRemoteConfigValue getValue( + PigeonFirebaseApp app, + String key, + ); + + @async + void setConfigSettings( + PigeonFirebaseApp app, + PigeonRemoteConfigSettings remoteConfigSettings, + ); + + @async + void setDefaults( + PigeonFirebaseApp app, + Map defaultParameters, + ); +} diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/pubspec.yaml b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pubspec.yaml index f205797bc167..50c31353b274 100644 --- a/packages/firebase_remote_config/firebase_remote_config_platform_interface/pubspec.yaml +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/pubspec.yaml @@ -24,3 +24,4 @@ dev_dependencies: sdk: flutter mockito: ^5.0.0 pedantic: ^1.8.0 + pigeon: ^9.0.6 diff --git a/packages/firebase_remote_config/firebase_remote_config_platform_interface/run_pigeon.sh b/packages/firebase_remote_config/firebase_remote_config_platform_interface/run_pigeon.sh new file mode 100644 index 000000000000..c6854102c961 --- /dev/null +++ b/packages/firebase_remote_config/firebase_remote_config_platform_interface/run_pigeon.sh @@ -0,0 +1,9 @@ +flutter pub run pigeon \ + --input pigeons/messages.dart + + + # \ + # --dart_out lib/src/pigeon/messages.pigeon.dart \ + # --cpp_header_out ../firebase_remote_config/windows/messages.g.h \ + # --cpp_source_out ../firebase_remote_config/windows/messages.g.cpp \ + # --cpp_namespace firebase_remote_config_windows \ No newline at end of file diff --git a/tests/integration_test/e2e_test.dart b/tests/integration_test/e2e_test.dart index 04c98b2deba8..921fb80bc785 100644 --- a/tests/integration_test/e2e_test.dart +++ b/tests/integration_test/e2e_test.dart @@ -53,7 +53,7 @@ void main() { firebase_storage.main(); } else { // Only tests available on Windows - firebase_core.main(); + firebase_core.main(); } }); }