From e99719eef1353655df2487d86b6a9f000b2fd068 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 1 Sep 2025 08:39:28 +0000 Subject: [PATCH 1/5] feat(performance): add support for Pigeon. Update iOS to Swift and Android to Kotlin --- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/main.cpp | 2 +- .../windows/firebase_core_plugin.cpp | 36 +- .../windows/firebase_core_plugin.h | 16 +- .../analysis_options.yaml | 10 + .../firebase_performance/android/build.gradle | 15 + .../FlutterFirebaseAppRegistrar.java | 21 - .../FlutterFirebasePerformancePlugin.java | 345 ---------- .../FlutterFirebaseAppRegistrar.kt | 18 + .../FlutterFirebasePerformancePlugin.kt | 218 +++++++ .../GeneratedAndroidFirebasePerformance.g.kt | 390 +++++++++++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../ios/firebase_performance.podspec | 4 +- .../firebase_performance/Constants.swift | 6 + .../FLTFirebasePerformancePlugin.m | 232 ------- .../FirebasePerformanceMessages.g.swift | 461 +++++++++++++ .../FirebasePerformancePlugin.swift | 162 +++++ .../include/FLTFirebasePerformancePlugin.h | 16 - .../firebase_performance/pubspec.yaml | 2 +- .../windows/messages.g.cpp | 604 ++++++++++++++++++ .../firebase_performance/windows/messages.g.h | 227 +++++++ .../method_channel_firebase_performance.dart | 13 +- .../method_channel_http_metric.dart | 58 +- .../method_channel/method_channel_trace.dart | 20 +- .../lib/src/pigeon/messages.pigeon.dart | 439 +++++++++++++ .../pigeons/copyright.txt | 3 + .../pigeons/messages.dart | 92 +++ .../pubspec.yaml | 1 + .../test/pigeon/test_api.dart | 277 ++++++++ .../example/windows/runner/main.cpp | 2 +- 31 files changed, 3008 insertions(+), 688 deletions(-) create mode 100644 packages/firebase_performance/analysis_options.yaml delete mode 100644 packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.java delete mode 100644 packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.java create mode 100644 packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.kt create mode 100644 packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.kt create mode 100644 packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/GeneratedAndroidFirebasePerformance.g.kt create mode 100644 packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/Constants.swift delete mode 100644 packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FLTFirebasePerformancePlugin.m create mode 100644 packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformanceMessages.g.swift create mode 100644 packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift delete mode 100644 packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/include/FLTFirebasePerformancePlugin.h create mode 100644 packages/firebase_performance/firebase_performance/windows/messages.g.cpp create mode 100644 packages/firebase_performance/firebase_performance/windows/messages.g.h create mode 100644 packages/firebase_performance/firebase_performance_platform_interface/lib/src/pigeon/messages.pigeon.dart create mode 100644 packages/firebase_performance/firebase_performance_platform_interface/pigeons/copyright.txt create mode 100644 packages/firebase_performance/firebase_performance_platform_interface/pigeons/messages.dart create mode 100644 packages/firebase_performance/firebase_performance_platform_interface/test/pigeon/test_api.dart diff --git a/packages/cloud_firestore/cloud_firestore/example/windows/runner/main.cpp b/packages/cloud_firestore/cloud_firestore/example/windows/runner/main.cpp index a5a1cd3f91f0..10519d1ac390 100644 --- a/packages/cloud_firestore/cloud_firestore/example/windows/runner/main.cpp +++ b/packages/cloud_firestore/cloud_firestore/example/windows/runner/main.cpp @@ -10,7 +10,7 @@ #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { + _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()) { diff --git a/packages/firebase_auth/firebase_auth/example/windows/runner/main.cpp b/packages/firebase_auth/firebase_auth/example/windows/runner/main.cpp index bf07e45b3a4a..7a451dd2d11c 100644 --- a/packages/firebase_auth/firebase_auth/example/windows/runner/main.cpp +++ b/packages/firebase_auth/firebase_auth/example/windows/runner/main.cpp @@ -10,7 +10,7 @@ #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { + _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()) { diff --git a/packages/firebase_core/firebase_core/example/windows/runner/main.cpp b/packages/firebase_core/firebase_core/example/windows/runner/main.cpp index aa6bf684c007..2794d24a876b 100644 --- a/packages/firebase_core/firebase_core/example/windows/runner/main.cpp +++ b/packages/firebase_core/firebase_core/example/windows/runner/main.cpp @@ -10,7 +10,7 @@ #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { + _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()) { 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 f6c9ded368f5..b544e85ecb36 100644 --- a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp +++ b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.cpp @@ -34,7 +34,7 @@ static std::string kLibraryName = "flutter-fire-core"; // static void FirebaseCorePlugin::RegisterWithRegistrar( - flutter::PluginRegistrarWindows *registrar) { + flutter::PluginRegistrarWindows* registrar) { auto plugin = std::make_unique(); FirebaseCoreHostApi::SetUp(registrar->messenger(), plugin.get()); @@ -53,7 +53,7 @@ FirebaseCorePlugin::~FirebaseCorePlugin() = default; // Convert a CoreFirebaseOptions to a Firebase Options. firebase::AppOptions CoreFirebaseOptionsToAppOptions( - const CoreFirebaseOptions &pigeon_options) { + const CoreFirebaseOptions& pigeon_options) { firebase::AppOptions options; options.set_api_key(pigeon_options.api_key().c_str()); options.set_app_id(pigeon_options.app_id().c_str()); @@ -74,19 +74,19 @@ firebase::AppOptions CoreFirebaseOptionsToAppOptions( } // Convert a AppOptions to CoreFirebaseOptions -CoreFirebaseOptions optionsFromFIROptions(const firebase::AppOptions &options) { +CoreFirebaseOptions optionsFromFIROptions(const firebase::AppOptions& options) { CoreFirebaseOptions pigeon_options = CoreFirebaseOptions(options.api_key(), options.app_id(), options.messaging_sender_id(), options.project_id()); // AppOptions initialises as empty char so we check to stop empty string to // Flutter Same for storage bucket below - const char *db_url = options.database_url(); + const char* db_url = options.database_url(); if (db_url != nullptr && db_url[0] != '\0') { pigeon_options.set_database_u_r_l(db_url); } pigeon_options.set_tracking_id(nullptr); - const char *storage_bucket = options.storage_bucket(); + const char* storage_bucket = options.storage_bucket(); if (storage_bucket != nullptr && storage_bucket[0] != '\0') { pigeon_options.set_storage_bucket(storage_bucket); } @@ -94,7 +94,7 @@ CoreFirebaseOptions optionsFromFIROptions(const firebase::AppOptions &options) { } // Convert a firebase::App to CoreInitializeResponse -CoreInitializeResponse AppToCoreInitializeResponse(const App &app) { +CoreInitializeResponse AppToCoreInitializeResponse(const App& app) { flutter::EncodableMap plugin_constants; CoreInitializeResponse response = CoreInitializeResponse( app.name(), optionsFromFIROptions(app.options()), plugin_constants); @@ -102,11 +102,11 @@ CoreInitializeResponse AppToCoreInitializeResponse(const App &app) { } void FirebaseCorePlugin::InitializeApp( - const std::string &app_name, - const CoreFirebaseOptions &initialize_app_request, + const std::string& app_name, + const CoreFirebaseOptions& initialize_app_request, std::function reply)> result) { // Create an app - App *app = + App* app = App::Create(CoreFirebaseOptionsToAppOptions(initialize_app_request), app_name.c_str()); @@ -118,14 +118,14 @@ 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) { + std::vector all_apps = App::GetApps(); + for (const App* app : all_apps) { initializedApps.push_back(AppToCoreInitializeResponse(*app)); } flutter::EncodableList encodableList; - for (const auto &item : initializedApps) { + for (const auto& item : initializedApps) { encodableList.push_back(flutter::CustomEncodableValue(item)); } result(encodableList); @@ -135,9 +135,9 @@ void FirebaseCorePlugin::OptionsFromResource( std::function reply)> result) {} void FirebaseCorePlugin::SetAutomaticDataCollectionEnabled( - const std::string &app_name, bool enabled, + const std::string& app_name, bool enabled, std::function reply)> result) { - App *firebaseApp = App::GetInstance(app_name.c_str()); + App* firebaseApp = App::GetInstance(app_name.c_str()); if (firebaseApp != nullptr) { // TODO: Missing method } @@ -145,9 +145,9 @@ void FirebaseCorePlugin::SetAutomaticDataCollectionEnabled( } void FirebaseCorePlugin::SetAutomaticResourceManagementEnabled( - const std::string &app_name, bool enabled, + const std::string& app_name, bool enabled, std::function reply)> result) { - App *firebaseApp = App::GetInstance(app_name.c_str()); + App* firebaseApp = App::GetInstance(app_name.c_str()); if (firebaseApp != nullptr) { // TODO: Missing method } @@ -156,9 +156,9 @@ void FirebaseCorePlugin::SetAutomaticResourceManagementEnabled( } void FirebaseCorePlugin::Delete( - const std::string &app_name, + const std::string& app_name, std::function reply)> result) { - App *firebaseApp = App::GetInstance(app_name.c_str()); + App* firebaseApp = App::GetInstance(app_name.c_str()); if (firebaseApp != nullptr) { // TODO: Missing method } 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 2044a25b8664..84eb21987fa3 100644 --- a/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h +++ b/packages/firebase_core/firebase_core/windows/firebase_core_plugin.h @@ -21,20 +21,20 @@ class FirebaseCorePlugin : public flutter::Plugin, public FirebaseCoreHostApi, public FirebaseAppHostApi { public: - static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); FirebaseCorePlugin(); virtual ~FirebaseCorePlugin(); // Disallow copy and assign. - FirebaseCorePlugin(const FirebaseCorePlugin &) = delete; - FirebaseCorePlugin &operator=(const FirebaseCorePlugin &) = delete; + FirebaseCorePlugin(const FirebaseCorePlugin&) = delete; + FirebaseCorePlugin& operator=(const FirebaseCorePlugin&) = delete; // FirebaseCoreHostApi virtual void InitializeApp( - const std::string &app_name, - const CoreFirebaseOptions &initialize_app_request, + const std::string& app_name, + const CoreFirebaseOptions& initialize_app_request, std::function reply)> result) override; virtual void InitializeCore( @@ -45,13 +45,13 @@ class FirebaseCorePlugin : public flutter::Plugin, // FirebaseAppHostApi virtual void SetAutomaticDataCollectionEnabled( - const std::string &app_name, bool enabled, + const std::string& app_name, bool enabled, std::function reply)> result) override; virtual void SetAutomaticResourceManagementEnabled( - const std::string &app_name, bool enabled, + const std::string& app_name, bool enabled, std::function reply)> result) override; virtual void Delete( - const std::string &app_name, + const std::string& app_name, std::function reply)> result) override; private: diff --git a/packages/firebase_performance/analysis_options.yaml b/packages/firebase_performance/analysis_options.yaml new file mode 100644 index 000000000000..a9341971bf6a --- /dev/null +++ b/packages/firebase_performance/analysis_options.yaml @@ -0,0 +1,10 @@ +# Copyright 2025 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# in the LICENSE file. + +include: ../../analysis_options.yaml + +analyzer: + exclude: + - firebase_performance_platform_interface/lib/src/pigeon/messages.pigeon.dart + - firebase_performance_platform_interface/test/pigeon/test_api.dart \ No newline at end of file diff --git a/packages/firebase_performance/firebase_performance/android/build.gradle b/packages/firebase_performance/firebase_performance/android/build.gradle index 8f0b4fb8a89d..682805cda15f 100644 --- a/packages/firebase_performance/firebase_performance/android/build.gradle +++ b/packages/firebase_performance/firebase_performance/android/build.gradle @@ -3,12 +3,18 @@ version '1.0-SNAPSHOT' apply plugin: 'com.android.library' apply from: file("local-config.gradle") +apply plugin: 'kotlin-android' buildscript { + ext.kotlin_version = "1.8.22" + repositories { google() mavenCentral() } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } rootProject.allprojects { @@ -49,6 +55,15 @@ android { targetCompatibility project.ext.javaVersion } + sourceSets { + main.java.srcDirs += "src/main/kotlin" + test.java.srcDirs += "src/test/kotlin" + } + + kotlinOptions { + jvmTarget = project.ext.javaVersion + } + buildFeatures { buildConfig true } diff --git a/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.java b/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.java deleted file mode 100644 index 56b2acb97622..000000000000 --- a/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.firebase.performance; - -import androidx.annotation.Keep; -import com.google.firebase.components.Component; -import com.google.firebase.components.ComponentRegistrar; -import com.google.firebase.platforminfo.LibraryVersionComponent; -import java.util.Collections; -import java.util.List; - -@Keep -public class FlutterFirebaseAppRegistrar implements ComponentRegistrar { - @Override - public List> getComponents() { - return Collections.>singletonList( - LibraryVersionComponent.create(BuildConfig.LIBRARY_NAME, BuildConfig.LIBRARY_VERSION)); - } -} diff --git a/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.java b/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.java deleted file mode 100644 index 4be1326d0bb3..000000000000 --- a/packages/firebase_performance/firebase_performance/android/src/main/java/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.java +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.firebase.performance; - -import static io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry.registerPlugin; - -import androidx.annotation.NonNull; -import com.google.android.gms.tasks.Task; -import com.google.android.gms.tasks.TaskCompletionSource; -import com.google.firebase.FirebaseApp; -import com.google.firebase.perf.FirebasePerformance; -import com.google.firebase.perf.metrics.HttpMetric; -import com.google.firebase.perf.metrics.Trace; -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugins.firebase.core.FlutterFirebasePlugin; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * Flutter plugin accessing Firebase Performance API. - * - *

Instantiate this in an add to app scenario to gracefully handle activity and context changes. - */ -public class FlutterFirebasePerformancePlugin - implements FlutterFirebasePlugin, FlutterPlugin, MethodCallHandler { - private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_performance"; - - static final HashMap _httpMetrics = new HashMap<>(); - static final HashMap _traces = new HashMap<>(); - static int _traceHandle = 0; - static int _httpMetricHandle = 0; - private MethodChannel channel; - - private void initInstance(BinaryMessenger messenger) { - registerPlugin(METHOD_CHANNEL_NAME, this); - channel = new MethodChannel(messenger, METHOD_CHANNEL_NAME); - channel.setMethodCallHandler(this); - } - - @Override - public void onAttachedToEngine(FlutterPluginBinding binding) { - initInstance(binding.getBinaryMessenger()); - } - - @Override - public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - if (channel != null) { - channel.setMethodCallHandler(null); - channel = null; - } - } - - private static String parseHttpMethod(String httpMethod) { - switch (httpMethod) { - case "HttpMethod.Connect": - return FirebasePerformance.HttpMethod.CONNECT; - case "HttpMethod.Delete": - return FirebasePerformance.HttpMethod.DELETE; - case "HttpMethod.Get": - return FirebasePerformance.HttpMethod.GET; - case "HttpMethod.Head": - return FirebasePerformance.HttpMethod.HEAD; - case "HttpMethod.Options": - return FirebasePerformance.HttpMethod.OPTIONS; - case "HttpMethod.Patch": - return FirebasePerformance.HttpMethod.PATCH; - case "HttpMethod.Post": - return FirebasePerformance.HttpMethod.POST; - case "HttpMethod.Put": - return FirebasePerformance.HttpMethod.PUT; - case "HttpMethod.Trace": - return FirebasePerformance.HttpMethod.TRACE; - default: - throw new IllegalArgumentException(String.format("No HttpMethod for: %s", httpMethod)); - } - } - - private Task isPerformanceCollectionEnabled() { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - taskCompletionSource.setResult( - FirebasePerformance.getInstance().isPerformanceCollectionEnabled()); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - private Task setPerformanceCollectionEnabled(MethodCall call) { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - final Boolean enable = call.argument("enable"); - FirebasePerformance.getInstance().setPerformanceCollectionEnabled(enable); - taskCompletionSource.setResult(null); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - private Task traceStart(MethodCall call) { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - final String name = Objects.requireNonNull(call.argument("name")); - final Trace trace = FirebasePerformance.getInstance().newTrace(name); - trace.start(); - final int traceHandle = _traceHandle++; - _traces.put(traceHandle, trace); - taskCompletionSource.setResult(traceHandle); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - private Task traceStop(MethodCall call) { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - final int traceHandle = Objects.requireNonNull(call.argument("handle")); - final Map attributes = - Objects.requireNonNull((call.argument("attributes"))); - final Map metrics = Objects.requireNonNull((call.argument("metrics"))); - final Trace trace = _traces.get(traceHandle); - - if (trace == null) { - taskCompletionSource.setResult(null); - return; - } - - for (String key : attributes.keySet()) { - String attributeValue = (String) attributes.get(key); - if (attributeValue == null) { - continue; - } - - trace.putAttribute(key, attributeValue); - } - - for (String key : metrics.keySet()) { - Integer metricValue = (Integer) metrics.get(key); - if (metricValue == null) { - continue; - } - - trace.putMetric(key, metricValue); - } - - trace.stop(); - - _traces.remove(traceHandle); - taskCompletionSource.setResult(null); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - private Task httpMetricStart(MethodCall call) { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - final String url = Objects.requireNonNull(call.argument("url")); - final String httpMethod = Objects.requireNonNull(call.argument("httpMethod")); - - final HttpMetric httpMetric = - FirebasePerformance.getInstance().newHttpMetric(url, parseHttpMethod(httpMethod)); - httpMetric.start(); - final int httpMetricHandle = _httpMetricHandle++; - _httpMetrics.put(httpMetricHandle, httpMetric); - taskCompletionSource.setResult(httpMetricHandle); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - private Task httpMetricStop(MethodCall call) { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - final int httpMetricHandle = Objects.requireNonNull(call.argument("handle")); - final Map attributes = - Objects.requireNonNull((call.argument("attributes"))); - final Integer httpResponseCode = call.argument("httpResponseCode"); - final Integer requestPayloadSize = call.argument("requestPayloadSize"); - final String responseContentType = call.argument("responseContentType"); - final Integer responsePayloadSize = call.argument("responsePayloadSize"); - - final HttpMetric httpMetric = _httpMetrics.get(httpMetricHandle); - - if (httpMetric == null) { - // If httpMetric is null, it means that the httpMetric has already been stopped. - taskCompletionSource.setResult(null); - return; - } - - if (httpResponseCode != null) { - httpMetric.setHttpResponseCode(httpResponseCode); - } - if (requestPayloadSize != null) { - httpMetric.setRequestPayloadSize(requestPayloadSize); - } - if (responseContentType != null) { - httpMetric.setResponseContentType(responseContentType); - } - if (responsePayloadSize != null) { - httpMetric.setResponsePayloadSize(responsePayloadSize); - } - - for (String key : attributes.keySet()) { - String attributeValue = (String) attributes.get(key); - if (attributeValue == null) { - continue; - } - - httpMetric.putAttribute(key, attributeValue); - } - - httpMetric.stop(); - _httpMetrics.remove(httpMetricHandle); - - taskCompletionSource.setResult(null); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - @Override - public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { - Task methodCallTask; - - switch (call.method) { - case "FirebasePerformance#isPerformanceCollectionEnabled": - methodCallTask = isPerformanceCollectionEnabled(); - break; - case "FirebasePerformance#setPerformanceCollectionEnabled": - methodCallTask = setPerformanceCollectionEnabled(call); - break; - case "FirebasePerformance#httpMetricStart": - methodCallTask = httpMetricStart(call); - break; - case "FirebasePerformance#httpMetricStop": - methodCallTask = httpMetricStop(call); - break; - case "FirebasePerformance#traceStart": - methodCallTask = traceStart(call); - break; - case "FirebasePerformance#traceStop": - methodCallTask = traceStop(call); - break; - default: - result.notImplemented(); - return; - } - - methodCallTask.addOnCompleteListener( - task -> { - if (task.isSuccessful()) { - result.success(task.getResult()); - } else { - Exception exception = task.getException(); - String message = - exception != null ? exception.getMessage() : "An unknown error occurred"; - result.error("firebase_crashlytics", message, null); - } - }); - } - - @Override - public Task> getPluginConstantsForFirebaseApp(FirebaseApp firebaseApp) { - TaskCompletionSource> taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - taskCompletionSource.setResult(new HashMap() {}); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } - - @Override - public Task didReinitializeFirebaseCore() { - TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); - - cachedThreadPool.execute( - () -> { - try { - for (Trace trace : _traces.values()) { - trace.stop(); - } - _traces.clear(); - for (HttpMetric httpMetric : _httpMetrics.values()) { - httpMetric.stop(); - } - _httpMetrics.clear(); - - taskCompletionSource.setResult(null); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); - - return taskCompletionSource.getTask(); - } -} diff --git a/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.kt b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.kt new file mode 100644 index 000000000000..c4f81db754bb --- /dev/null +++ b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebaseAppRegistrar.kt @@ -0,0 +1,18 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +package io.flutter.plugins.firebase.performance + +import androidx.annotation.Keep +import com.google.firebase.components.Component +import com.google.firebase.components.ComponentRegistrar +import com.google.firebase.platforminfo.LibraryVersionComponent + +@Keep +class FlutterFirebaseAppRegistrar : ComponentRegistrar { + override fun getComponents(): List> { + return listOf( + LibraryVersionComponent.create(BuildConfig.LIBRARY_NAME, BuildConfig.LIBRARY_VERSION) + ) + } +} diff --git a/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.kt b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.kt new file mode 100644 index 000000000000..dfc913d0700e --- /dev/null +++ b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/FlutterFirebasePerformancePlugin.kt @@ -0,0 +1,218 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +package io.flutter.plugins.firebase.performance + +import com.google.android.gms.tasks.Task +import com.google.android.gms.tasks.TaskCompletionSource +import com.google.firebase.FirebaseApp +import com.google.firebase.perf.FirebasePerformance +import com.google.firebase.perf.metrics.HttpMetric +import com.google.firebase.perf.metrics.Trace +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugins.firebase.core.FlutterFirebasePlugin +import io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry + +/** + * Flutter plugin accessing Firebase Performance API. + * + * + * Instantiate this in an add to app scenario to gracefully handle activity and context changes. + */ +class FlutterFirebasePerformancePlugin + : FlutterFirebasePlugin, FlutterPlugin, FirebasePerformanceHostApi { + private var binaryMessenger: BinaryMessenger? = null + + private fun initInstance(messenger: BinaryMessenger) { + FlutterFirebasePluginRegistry.registerPlugin( + METHOD_CHANNEL_NAME, + this + ) + binaryMessenger = messenger + FirebasePerformanceHostApi.setUp(messenger, this) + } + + override fun onAttachedToEngine(binding: FlutterPluginBinding) { + initInstance(binding.binaryMessenger) + } + + override fun onDetachedFromEngine(binding: FlutterPluginBinding) { + binaryMessenger = null + FirebasePerformanceHostApi.setUp(binding.binaryMessenger, null) + } + + override fun setPerformanceCollectionEnabled(enabled: Boolean, callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + FirebasePerformance.getInstance().isPerformanceCollectionEnabled = enabled + callback(Result.success(Unit)) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + override fun isPerformanceCollectionEnabled(callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + val result = FirebasePerformance.getInstance().isPerformanceCollectionEnabled + callback(Result.success(result)) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + override fun startTrace(name: String, callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + val trace = FirebasePerformance.getInstance().newTrace(name) + trace.start() + val traceHandle = _traceHandle++ + _traces[traceHandle] = trace + callback(Result.success(traceHandle.toLong())) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + override fun stopTrace(handle: Long, attributes: TraceAttributes, callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + val trace = _traces[handle.toInt()] + if (trace == null) { + callback(Result.success(Unit)) + return@execute + } + + attributes.attributes?.forEach { (key, value) -> + trace.putAttribute(key, value) + } + + attributes.metrics?.forEach { (key, value) -> + trace.putMetric(key, value) + } + + trace.stop() + _traces.remove(handle.toInt()) + callback(Result.success(Unit)) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + override fun startHttpMetric(options: HttpMetricOptions, callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + val httpMethod = parseHttpMethod(options.httpMethod) + val httpMetric = FirebasePerformance.getInstance().newHttpMetric( + options.url, + httpMethod + ) + httpMetric.start() + val httpMetricHandle = _httpMetricHandle++ + _httpMetrics[httpMetricHandle] = httpMetric + callback(Result.success(httpMetricHandle.toLong())) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + override fun stopHttpMetric(handle: Long, attributes: HttpMetricAttributes, callback: (Result) -> Unit) { + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + val httpMetric = _httpMetrics[handle.toInt()] + if (httpMetric == null) { + callback(Result.success(Unit)) + return@execute + } + + attributes.httpResponseCode?.let { httpMetric.setHttpResponseCode(it.toInt()) } + attributes.requestPayloadSize?.let { httpMetric.setRequestPayloadSize(it) } + attributes.responseContentType?.let { httpMetric.setResponseContentType(it) } + attributes.responsePayloadSize?.let { httpMetric.setResponsePayloadSize(it) } + + attributes.attributes?.forEach { (key, value) -> + httpMetric.putAttribute(key, value) + } + + httpMetric.stop() + _httpMetrics.remove(handle.toInt()) + callback(Result.success(Unit)) + } catch (e: Exception) { + handleFailure(callback, e) + } + } + } + + private fun handleFailure (callback: (Result) -> Unit, exception: Exception?) { + val message = + if (exception != null) exception.message else "An unknown error occurred" + callback(Result.failure(FlutterError("firebase_performance", message, null))) + } + + override fun getPluginConstantsForFirebaseApp(firebaseApp: FirebaseApp): Task> { + val taskCompletionSource = TaskCompletionSource>() + + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + taskCompletionSource.setResult(HashMap()) + } catch (e: Exception) { + taskCompletionSource.setException(e) + } + } + + return taskCompletionSource.task + } + + override fun didReinitializeFirebaseCore(): Task { + val taskCompletionSource = TaskCompletionSource() + + FlutterFirebasePlugin.cachedThreadPool.execute { + try { + for (trace in _traces.values) { + trace.stop() + } + _traces.clear() + for (httpMetric in _httpMetrics.values) { + httpMetric.stop() + } + _httpMetrics.clear() + + taskCompletionSource.setResult(null) + } catch (e: Exception) { + taskCompletionSource.setException(e) + } + } + + return taskCompletionSource.task + } + + companion object { + private const val METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_performance" + + val _httpMetrics: HashMap = HashMap() + val _traces: HashMap = HashMap() + var _traceHandle: Int = 0 + var _httpMetricHandle: Int = 0 + + private fun parseHttpMethod(httpMethod: HttpMethod): String { + return when (httpMethod) { + HttpMethod.CONNECT -> FirebasePerformance.HttpMethod.CONNECT + HttpMethod.DELETE -> FirebasePerformance.HttpMethod.DELETE + HttpMethod.GET -> FirebasePerformance.HttpMethod.GET + HttpMethod.HEAD -> FirebasePerformance.HttpMethod.HEAD + HttpMethod.OPTIONS -> FirebasePerformance.HttpMethod.OPTIONS + HttpMethod.PATCH -> FirebasePerformance.HttpMethod.PATCH + HttpMethod.POST -> FirebasePerformance.HttpMethod.POST + HttpMethod.PUT -> FirebasePerformance.HttpMethod.PUT + HttpMethod.TRACE -> FirebasePerformance.HttpMethod.TRACE + } + } + } +} diff --git a/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/GeneratedAndroidFirebasePerformance.g.kt b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/GeneratedAndroidFirebasePerformance.g.kt new file mode 100644 index 000000000000..39423870b952 --- /dev/null +++ b/packages/firebase_performance/firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/GeneratedAndroidFirebasePerformance.g.kt @@ -0,0 +1,390 @@ +// Copyright 2025, 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 (v25.3.2), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package io.flutter.plugins.firebase.performance + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer +private object GeneratedAndroidFirebasePerformancePigeonUtils { + + fun wrapResult(result: Any?): List { + return listOf(result) + } + + fun wrapError(exception: Throwable): List { + return if (exception is FlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a is ByteArray && b is ByteArray) { + return a.contentEquals(b) + } + if (a is IntArray && b is IntArray) { + return a.contentEquals(b) + } + if (a is LongArray && b is LongArray) { + return a.contentEquals(b) + } + if (a is DoubleArray && b is DoubleArray) { + return a.contentEquals(b) + } + if (a is Array<*> && b is Array<*>) { + return a.size == b.size && + a.indices.all{ deepEquals(a[it], b[it]) } + } + if (a is List<*> && b is List<*>) { + return a.size == b.size && + a.indices.all{ deepEquals(a[it], b[it]) } + } + if (a is Map<*, *> && b is Map<*, *>) { + return a.size == b.size && a.all { + (b as Map).containsKey(it.key) && + deepEquals(it.value, b[it.key]) + } + } + return a == b + } + +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + +enum class HttpMethod(val raw: Int) { + CONNECT(0), + DELETE(1), + GET(2), + HEAD(3), + OPTIONS(4), + PATCH(5), + POST(6), + PUT(7), + TRACE(8); + + companion object { + fun ofRaw(raw: Int): HttpMethod? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class HttpMetricOptions ( + val url: String, + val httpMethod: HttpMethod +) + { + companion object { + fun fromList(pigeonVar_list: List): HttpMetricOptions { + val url = pigeonVar_list[0] as String + val httpMethod = pigeonVar_list[1] as HttpMethod + return HttpMetricOptions(url, httpMethod) + } + } + fun toList(): List { + return listOf( + url, + httpMethod, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is HttpMetricOptions) { + return false + } + if (this === other) { + return true + } + return GeneratedAndroidFirebasePerformancePigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class HttpMetricAttributes ( + val httpResponseCode: Long? = null, + val requestPayloadSize: Long? = null, + val responsePayloadSize: Long? = null, + val responseContentType: String? = null, + val attributes: Map? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): HttpMetricAttributes { + val httpResponseCode = pigeonVar_list[0] as Long? + val requestPayloadSize = pigeonVar_list[1] as Long? + val responsePayloadSize = pigeonVar_list[2] as Long? + val responseContentType = pigeonVar_list[3] as String? + val attributes = pigeonVar_list[4] as Map? + return HttpMetricAttributes(httpResponseCode, requestPayloadSize, responsePayloadSize, responseContentType, attributes) + } + } + fun toList(): List { + return listOf( + httpResponseCode, + requestPayloadSize, + responsePayloadSize, + responseContentType, + attributes, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is HttpMetricAttributes) { + return false + } + if (this === other) { + return true + } + return GeneratedAndroidFirebasePerformancePigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class TraceAttributes ( + val metrics: Map? = null, + val attributes: Map? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): TraceAttributes { + val metrics = pigeonVar_list[0] as Map? + val attributes = pigeonVar_list[1] as Map? + return TraceAttributes(metrics, attributes) + } + } + fun toList(): List { + return listOf( + metrics, + attributes, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is TraceAttributes) { + return false + } + if (this === other) { + return true + } + return GeneratedAndroidFirebasePerformancePigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} +private open class GeneratedAndroidFirebasePerformancePigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 129.toByte() -> { + return (readValue(buffer) as Long?)?.let { + HttpMethod.ofRaw(it.toInt()) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + HttpMetricOptions.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + HttpMetricAttributes.fromList(it) + } + } + 132.toByte() -> { + return (readValue(buffer) as? List)?.let { + TraceAttributes.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is HttpMethod -> { + stream.write(129) + writeValue(stream, value.raw) + } + is HttpMetricOptions -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is HttpMetricAttributes -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is TraceAttributes -> { + stream.write(132) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface FirebasePerformanceHostApi { + fun setPerformanceCollectionEnabled(enabled: Boolean, callback: (Result) -> Unit) + fun isPerformanceCollectionEnabled(callback: (Result) -> Unit) + fun startTrace(name: String, callback: (Result) -> Unit) + fun stopTrace(handle: Long, attributes: TraceAttributes, callback: (Result) -> Unit) + fun startHttpMetric(options: HttpMetricOptions, callback: (Result) -> Unit) + fun stopHttpMetric(handle: Long, attributes: HttpMetricAttributes, callback: (Result) -> Unit) + + companion object { + /** The codec used by FirebasePerformanceHostApi. */ + val codec: MessageCodec by lazy { + GeneratedAndroidFirebasePerformancePigeonCodec() + } + /** Sets up an instance of `FirebasePerformanceHostApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: FirebasePerformanceHostApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val enabledArg = args[0] as Boolean + api.setPerformanceCollectionEnabled(enabledArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.isPerformanceCollectionEnabled$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.isPerformanceCollectionEnabled{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val nameArg = args[0] as String + api.startTrace(nameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val handleArg = args[0] as Long + val attributesArg = args[1] as TraceAttributes + api.stopTrace(handleArg, attributesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val optionsArg = args[0] as HttpMetricOptions + api.startHttpMetric(optionsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val handleArg = args[0] as Long + val attributesArg = args[1] as HttpMetricAttributes + api.stopHttpMetric(handleArg, attributesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebasePerformancePigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} diff --git a/packages/firebase_performance/firebase_performance/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/firebase_performance/firebase_performance/example/android/gradle/wrapper/gradle-wrapper.properties index da1db5f04e88..e411586a54a8 100644 --- a/packages/firebase_performance/firebase_performance/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/firebase_performance/firebase_performance/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance.podspec b/packages/firebase_performance/firebase_performance/ios/firebase_performance.podspec index 3b1ac20f77e5..c342f6571432 100644 --- a/packages/firebase_performance/firebase_performance/ios/firebase_performance.podspec +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance.podspec @@ -27,13 +27,13 @@ Pod::Spec.new do |s| s.license = { :file => '../LICENSE' } s.authors = 'The Chromium Authors' s.source = { :path => '.' } - s.source_files = 'firebase_performance/Sources/firebase_performance/**/*.{h,m}' - s.public_header_files = 'firebase_performance/Sources/firebase_performance/include/*.h' + s.source_files = 'firebase_performance/Sources/firebase_performance/**/*.swift' s.dependency 'Flutter' s.dependency 'firebase_core' s.dependency 'Firebase/Performance', firebase_sdk_version s.ios.deployment_target = '15.0' s.static_framework = true + s.swift_version = '5.0' s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\\"#{library_version}\\\" LIBRARY_NAME=\\\"flutter-fire-perf\\\"", diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/Constants.swift b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/Constants.swift new file mode 100644 index 000000000000..f54904db4ab4 --- /dev/null +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/Constants.swift @@ -0,0 +1,6 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Auto-generated file. Do not edit. +public let versionNumber = "0.11.0" diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FLTFirebasePerformancePlugin.m b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FLTFirebasePerformancePlugin.m deleted file mode 100644 index 3a19f69846a6..000000000000 --- a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FLTFirebasePerformancePlugin.m +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "FLTFirebasePerformancePlugin.h" - -#if __has_include() -#import -#else -#import -#endif - -NSString *const kFLTFirebasePerformanceChannelName = @"plugins.flutter.io/firebase_performance"; - -@implementation FLTFirebasePerformancePlugin { - NSMutableDictionary *_httpMetrics; - NSMutableDictionary *_traces; - NSNumber *_traceHandle; - NSNumber *_httpMetricHandle; -} - -- (instancetype)init { - self = [super init]; - if (self) { - [[FLTFirebasePluginRegistry sharedInstance] registerFirebasePlugin:self]; - _httpMetrics = [NSMutableDictionary dictionary]; - _traces = [NSMutableDictionary dictionary]; - _traceHandle = [NSNumber numberWithInt:0]; - _httpMetricHandle = [NSNumber numberWithInt:0]; - } - return self; -} - -+ (void)registerWithRegistrar:(NSObject *)registrar { - FlutterMethodChannel *channel = - [FlutterMethodChannel methodChannelWithName:kFLTFirebasePerformanceChannelName - binaryMessenger:[registrar messenger]]; - FLTFirebasePerformancePlugin *instance = [[FLTFirebasePerformancePlugin alloc] init]; - - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutterResult { - FLTFirebaseMethodCallErrorBlock errorBlock = - ^(NSString *_Nullable code, NSString *_Nullable message, NSDictionary *_Nullable details, - NSError *_Nullable error) { - // `result.error` is not called in this plugin so this block does nothing. - flutterResult(nil); - }; - - FLTFirebaseMethodCallResult *methodCallResult = - [FLTFirebaseMethodCallResult createWithSuccess:flutterResult andErrorBlock:errorBlock]; - - if ([@"FirebasePerformance#isPerformanceCollectionEnabled" isEqualToString:call.method]) { - [self isPerformanceCollectionEnabled:methodCallResult]; - } else if ([@"FirebasePerformance#setPerformanceCollectionEnabled" isEqualToString:call.method]) { - [self setPerformanceCollectionEnabled:call.arguments withMethodCallResult:methodCallResult]; - } else if ([@"FirebasePerformance#httpMetricStart" isEqualToString:call.method]) { - [self httpMetricStart:call.arguments withMethodCallResult:methodCallResult]; - } else if ([@"FirebasePerformance#httpMetricStop" isEqualToString:call.method]) { - [self httpMetricStop:call.arguments withMethodCallResult:methodCallResult]; - } else if ([@"FirebasePerformance#traceStart" isEqualToString:call.method]) { - [self traceStart:call.arguments withMethodCallResult:methodCallResult]; - } else if ([@"FirebasePerformance#traceStop" isEqualToString:call.method]) { - [self traceStop:call.arguments withMethodCallResult:methodCallResult]; - } else { - methodCallResult.success(FlutterMethodNotImplemented); - } -} - -#pragma mark - Firebase Performance API - -- (void)isPerformanceCollectionEnabled:(FLTFirebaseMethodCallResult *)result { - result.success(@([[FIRPerformance sharedInstance] isDataCollectionEnabled])); -} - -- (void)setPerformanceCollectionEnabled:(id)arguments - withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - NSNumber *enable = arguments[@"enable"]; - - [[FIRPerformance sharedInstance] setDataCollectionEnabled:[enable boolValue]]; - result.success(nil); -} - -- (void)httpMetricStart:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - FIRHTTPMethod method = [FLTFirebasePerformancePlugin parseHttpMethod:arguments[@"httpMethod"]]; - NSURL *url = [NSURL URLWithString:arguments[@"url"]]; - FIRHTTPMetric *httpMetric = [[FIRHTTPMetric alloc] initWithURL:url HTTPMethod:method]; - if (httpMetric == nil) { - // Performance collection is disabled - result.success(nil); - return; - } - - [httpMetric start]; - _httpMetricHandle = [NSNumber numberWithInt:[_httpMetricHandle intValue] + 1]; - - [_httpMetrics setObject:httpMetric forKey:_httpMetricHandle]; - result.success(_httpMetricHandle); -} - -- (void)httpMetricStop:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - NSDictionary *attributes = arguments[@"attributes"]; - NSNumber *httpResponseCode = arguments[@"httpResponseCode"]; - NSNumber *requestPayloadSize = arguments[@"requestPayloadSize"]; - NSString *responseContentType = arguments[@"responseContentType"]; - NSNumber *responsePayloadSize = arguments[@"responsePayloadSize"]; - NSNumber *handle = arguments[@"handle"]; - - FIRHTTPMetric *httpMetric = [_httpMetrics objectForKey:handle]; - - [attributes - enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, NSString *value, BOOL *stop) { - [httpMetric setValue:value forAttribute:attributeName]; - }]; - - if (httpResponseCode != nil) { - httpMetric.responseCode = [httpResponseCode integerValue]; - } - if (responseContentType != nil) { - httpMetric.responseContentType = responseContentType; - } - if (requestPayloadSize != nil) { - httpMetric.requestPayloadSize = [requestPayloadSize longValue]; - } - if (responsePayloadSize != nil) { - httpMetric.responsePayloadSize = [responsePayloadSize longValue]; - } - - [httpMetric stop]; - [_httpMetrics removeObjectForKey:handle]; - - result.success(nil); -} - -- (void)traceStart:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - NSString *name = arguments[@"name"]; - - FIRTrace *trace = [FIRPerformance startTraceWithName:name]; - if (trace == nil) { - // Performance collection is disabled - result.success(nil); - return; - } - _traceHandle = [NSNumber numberWithInt:[_traceHandle intValue] + 1]; - [_traces setObject:trace forKey:_traceHandle]; - - result.success(_traceHandle); -} - -- (void)traceStop:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - NSDictionary *metrics = arguments[@"metrics"]; - NSDictionary *attributes = arguments[@"attributes"]; - NSNumber *handle = arguments[@"handle"]; - - FIRTrace *trace = [_traces objectForKey:handle]; - - [metrics enumerateKeysAndObjectsUsingBlock:^(NSString *metricName, NSNumber *value, BOOL *stop) { - [trace setIntValue:[value longLongValue] forMetric:metricName]; - }]; - - [attributes - enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, NSString *value, BOOL *stop) { - [trace setValue:value forAttribute:attributeName]; - }]; - - [trace stop]; - [_traces removeObjectForKey:handle]; - - result.success(nil); -} - -+ (FIRHTTPMethod)parseHttpMethod:(NSString *)method { - if ([@"HttpMethod.Connect" isEqualToString:method]) { - return FIRHTTPMethodCONNECT; - } else if ([@"HttpMethod.Delete" isEqualToString:method]) { - return FIRHTTPMethodDELETE; - } else if ([@"HttpMethod.Get" isEqualToString:method]) { - return FIRHTTPMethodGET; - } else if ([@"HttpMethod.Head" isEqualToString:method]) { - return FIRHTTPMethodHEAD; - } else if ([@"HttpMethod.Options" isEqualToString:method]) { - return FIRHTTPMethodOPTIONS; - } else if ([@"HttpMethod.Patch" isEqualToString:method]) { - return FIRHTTPMethodPATCH; - } else if ([@"HttpMethod.Post" isEqualToString:method]) { - return FIRHTTPMethodPOST; - } else if ([@"HttpMethod.Put" isEqualToString:method]) { - return FIRHTTPMethodPUT; - } else if ([@"HttpMethod.Trace" isEqualToString:method]) { - return FIRHTTPMethodTRACE; - } - - NSString *reason = [NSString stringWithFormat:@"Invalid HttpMethod: %@", method]; - @throw [[NSException alloc] initWithName:NSInvalidArgumentException reason:reason userInfo:nil]; -} - -#pragma mark - FLTFirebasePlugin - -- (void)didReinitializeFirebaseCore:(void (^)(void))completion { - for (FIRTrace *trace in self->_traces.allValues) { - [trace stop]; - } - [self->_traces removeAllObjects]; - - for (FIRHTTPMetric *httpMetric in self->_httpMetrics.allValues) { - [httpMetric stop]; - } - [self->_httpMetrics removeAllObjects]; - - if (completion != nil) { - completion(); - } -} - -- (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app { - return @{}; -} - -- (NSString *_Nonnull)firebaseLibraryName { - return @LIBRARY_NAME; -} - -- (NSString *_Nonnull)firebaseLibraryVersion { - return @LIBRARY_VERSION; -} - -- (NSString *_Nonnull)flutterChannelName { - return kFLTFirebasePerformanceChannelName; -} - -@end diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformanceMessages.g.swift b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformanceMessages.g.swift new file mode 100644 index 000000000000..f0b2150e101c --- /dev/null +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformanceMessages.g.swift @@ -0,0 +1,461 @@ +// Copyright 2025, 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 (v25.3.2), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +/// Error class for passing custom error details to Dart side. +final class PigeonError: Error { + let code: String + let message: String? + let details: Sendable? + + init(code: String, message: String?, details: Sendable?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + +private func wrapResult(_ result: Any?) -> [Any?] { + [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PigeonError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func isNullish(_ value: Any?) -> Bool { + value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +func deepEqualsFirebasePerformanceMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { + let cleanLhs = nilOrValue(lhs) as Any? + let cleanRhs = nilOrValue(rhs) as Any? + switch (cleanLhs, cleanRhs) { + case (nil, nil): + return true + + case (nil, _), (_, nil): + return false + + case is (Void, Void): + return true + + case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): + return cleanLhsHashable == cleanRhsHashable + + case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): + guard cleanLhsArray.count == cleanRhsArray.count else { return false } + for (index, element) in cleanLhsArray.enumerated() { + if !deepEqualsFirebasePerformanceMessages(element, cleanRhsArray[index]) { + return false + } + } + return true + + case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } + for (key, cleanLhsValue) in cleanLhsDictionary { + guard cleanRhsDictionary.index(forKey: key) != nil else { return false } + if !deepEqualsFirebasePerformanceMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + return false + } + } + return true + + default: + // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be + // untrue. + return false + } +} + +func deepHashFirebasePerformanceMessages(value: Any?, hasher: inout Hasher) { + if let valueList = value as? [AnyHashable] { + for item in valueList { + deepHashFirebasePerformanceMessages(value: item, hasher: &hasher) + } + return + } + + if let valueDict = value as? [AnyHashable: AnyHashable] { + for key in valueDict.keys { + hasher.combine(key) + deepHashFirebasePerformanceMessages(value: valueDict[key]!, hasher: &hasher) + } + return + } + + if let hashableValue = value as? AnyHashable { + hasher.combine(hashableValue.hashValue) + } + + return hasher.combine(String(describing: value)) +} + +enum HttpMethod: Int { + case connect = 0 + case delete = 1 + case get = 2 + case head = 3 + case options = 4 + case patch = 5 + case post = 6 + case put = 7 + case trace = 8 +} + +/// Generated class from Pigeon that represents data sent in messages. +struct HttpMetricOptions: Hashable { + var url: String + var httpMethod: HttpMethod + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> HttpMetricOptions? { + let url = pigeonVar_list[0] as! String + let httpMethod = pigeonVar_list[1] as! HttpMethod + + return HttpMetricOptions( + url: url, + httpMethod: httpMethod + ) + } + + func toList() -> [Any?] { + [ + url, + httpMethod, + ] + } + + static func == (lhs: HttpMetricOptions, rhs: HttpMetricOptions) -> Bool { + deepEqualsFirebasePerformanceMessages(lhs.toList(), rhs.toList()) + } + + func hash(into hasher: inout Hasher) { + deepHashFirebasePerformanceMessages(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct HttpMetricAttributes: Hashable { + var httpResponseCode: Int64? + var requestPayloadSize: Int64? + var responsePayloadSize: Int64? + var responseContentType: String? + var attributes: [String: String]? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> HttpMetricAttributes? { + let httpResponseCode: Int64? = nilOrValue(pigeonVar_list[0]) + let requestPayloadSize: Int64? = nilOrValue(pigeonVar_list[1]) + let responsePayloadSize: Int64? = nilOrValue(pigeonVar_list[2]) + let responseContentType: String? = nilOrValue(pigeonVar_list[3]) + let attributes: [String: String]? = nilOrValue(pigeonVar_list[4]) + + return HttpMetricAttributes( + httpResponseCode: httpResponseCode, + requestPayloadSize: requestPayloadSize, + responsePayloadSize: responsePayloadSize, + responseContentType: responseContentType, + attributes: attributes + ) + } + + func toList() -> [Any?] { + [ + httpResponseCode, + requestPayloadSize, + responsePayloadSize, + responseContentType, + attributes, + ] + } + + static func == (lhs: HttpMetricAttributes, rhs: HttpMetricAttributes) -> Bool { + deepEqualsFirebasePerformanceMessages(lhs.toList(), rhs.toList()) + } + + func hash(into hasher: inout Hasher) { + deepHashFirebasePerformanceMessages(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct TraceAttributes: Hashable { + var metrics: [String: Int64]? + var attributes: [String: String]? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> TraceAttributes? { + let metrics: [String: Int64]? = nilOrValue(pigeonVar_list[0]) + let attributes: [String: String]? = nilOrValue(pigeonVar_list[1]) + + return TraceAttributes( + metrics: metrics, + attributes: attributes + ) + } + + func toList() -> [Any?] { + [ + metrics, + attributes, + ] + } + + static func == (lhs: TraceAttributes, rhs: TraceAttributes) -> Bool { + deepEqualsFirebasePerformanceMessages(lhs.toList(), rhs.toList()) + } + + func hash(into hasher: inout Hasher) { + deepHashFirebasePerformanceMessages(value: toList(), hasher: &hasher) + } +} + +private class FirebasePerformanceMessagesPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return HttpMethod(rawValue: enumResultAsInt) + } + return nil + case 130: + return HttpMetricOptions.fromList(readValue() as! [Any?]) + case 131: + return HttpMetricAttributes.fromList(readValue() as! [Any?]) + case 132: + return TraceAttributes.fromList(readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class FirebasePerformanceMessagesPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? HttpMethod { + super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? HttpMetricOptions { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? HttpMetricAttributes { + super.writeByte(131) + super.writeValue(value.toList()) + } else if let value = value as? TraceAttributes { + super.writeByte(132) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class FirebasePerformanceMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + FirebasePerformanceMessagesPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + FirebasePerformanceMessagesPigeonCodecWriter(data: data) + } +} + +class FirebasePerformanceMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = + FirebasePerformanceMessagesPigeonCodec( + readerWriter: FirebasePerformanceMessagesPigeonCodecReaderWriter() + ) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol FirebasePerformanceHostApi { + func setPerformanceCollectionEnabled(enabled: Bool, + completion: @escaping (Result) -> Void) + func isPerformanceCollectionEnabled(completion: @escaping (Result) -> Void) + func startTrace(name: String, completion: @escaping (Result) -> Void) + func stopTrace(handle: Int64, attributes: TraceAttributes, + completion: @escaping (Result) -> Void) + func startHttpMetric(options: HttpMetricOptions, + completion: @escaping (Result) -> Void) + func stopHttpMetric(handle: Int64, attributes: HttpMetricAttributes, + completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class FirebasePerformanceHostApiSetup { + static var codec: FlutterStandardMessageCodec { FirebasePerformanceMessagesPigeonCodec.shared } + /// Sets up an instance of `FirebasePerformanceHostApi` to handle messages through the + /// `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebasePerformanceHostApi?, + messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let setPerformanceCollectionEnabledChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + setPerformanceCollectionEnabledChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let enabledArg = args[0] as! Bool + api.setPerformanceCollectionEnabled(enabled: enabledArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + setPerformanceCollectionEnabledChannel.setMessageHandler(nil) + } + let isPerformanceCollectionEnabledChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.isPerformanceCollectionEnabled\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + isPerformanceCollectionEnabledChannel.setMessageHandler { _, reply in + api.isPerformanceCollectionEnabled { result in + switch result { + case let .success(res): + reply(wrapResult(res)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + isPerformanceCollectionEnabledChannel.setMessageHandler(nil) + } + let startTraceChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + startTraceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let nameArg = args[0] as! String + api.startTrace(name: nameArg) { result in + switch result { + case let .success(res): + reply(wrapResult(res)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + startTraceChannel.setMessageHandler(nil) + } + let stopTraceChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + stopTraceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let handleArg = args[0] as! Int64 + let attributesArg = args[1] as! TraceAttributes + api.stopTrace(handle: handleArg, attributes: attributesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + stopTraceChannel.setMessageHandler(nil) + } + let startHttpMetricChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + startHttpMetricChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let optionsArg = args[0] as! HttpMetricOptions + api.startHttpMetric(options: optionsArg) { result in + switch result { + case let .success(res): + reply(wrapResult(res)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + startHttpMetricChannel.setMessageHandler(nil) + } + let stopHttpMetricChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + stopHttpMetricChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let handleArg = args[0] as! Int64 + let attributesArg = args[1] as! HttpMetricAttributes + api.stopHttpMetric(handle: handleArg, attributes: attributesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case let .failure(error): + reply(wrapError(error)) + } + } + } + } else { + stopHttpMetricChannel.setMessageHandler(nil) + } + } +} diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift new file mode 100644 index 000000000000..3f567c0c7272 --- /dev/null +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift @@ -0,0 +1,162 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import firebase_core +import FirebasePerformance +import Flutter + +let FirebasePerformanceChannelName = "plugins.flutter.io/firebase_performance" + +extension FlutterError: Error {} + +public class FirebasePerformancePlugin: NSObject, FlutterPlugin, FLTFirebasePluginProtocol, + FirebasePerformanceHostApi { + public func didReinitializeFirebaseCore(_ completion: @escaping () -> Void) { + completion() + } + + public func pluginConstants(for firebaseApp: FirebaseApp) -> [AnyHashable: Any] { + [:] + } + + public func firebaseLibraryName() -> String { + "flutter-fire-perf" + } + + public func firebaseLibraryVersion() -> String { + versionNumber + } + + public func flutterChannelName() -> String { + FirebasePerformanceChannelName + } + + private var httpMetrics: [Int: HTTPMetric] = [:] + private var traces: [Int: Trace] = [:] + private var traceHandle: Int = 0 + private var httpMetricHandle: Int = 0 + + public static func register(with registrar: FlutterPluginRegistrar) { + let binaryMessenger: FlutterBinaryMessenger + + #if os(macOS) + binaryMessenger = registrar.messenger + #elseif os(iOS) + binaryMessenger = registrar.messenger() + #endif + let instance = FirebasePerformancePlugin() + FirebasePerformanceHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: instance) + } + + public func setPerformanceCollectionEnabled(enabled: Bool, + completion: @escaping (Result) -> Void) { + Performance.sharedInstance().isInstrumentationEnabled = enabled + completion(.success(())) + } + + public func isPerformanceCollectionEnabled(completion: @escaping (Result) -> Void) { + let result = Performance.sharedInstance().isInstrumentationEnabled + completion(.success(result)) + } + + public func startTrace(name: String, completion: @escaping (Result) -> Void) { + let trace = Performance.sharedInstance().trace(name: name) + trace?.start() + traceHandle += 1 + traces[traceHandle] = trace + completion(.success(Int64(traceHandle))) + } + + func stopTrace(handle: Int64, attributes: TraceAttributes, + completion: @escaping (Result) -> Void) { + guard let trace = traces[Int(handle)] else { + completion(.success(())) + return + } + + if let metrics = attributes.metrics { + for (key, value) in metrics { + trace.setValue(value, forMetric: key) + } + } + + if let attributes = attributes.attributes { + for (key, value) in attributes { + trace.setValue(value, forAttribute: key) + } + } + + trace.stop() + traces.removeValue(forKey: Int(handle)) + completion(.success(())) + } + + func startHttpMetric(options: HttpMetricOptions, + completion: @escaping (Result) -> Void) { + guard let url = URL(string: options.url) else { + completion(.failure(FlutterError(code: "invalid-url", message: "Invalid url", details: nil))) + return + } + + guard let httpMethod = parseHttpMethod(options.httpMethod) else { + completion(.failure(FlutterError( + code: "invalid-argument", + message: "Invalid httpMethod", + details: nil + ))) + return + } + + let httpMetric = HTTPMetric(url: url, httpMethod: httpMethod) + httpMetric?.start() + httpMetricHandle += 1 + httpMetrics[httpMetricHandle] = httpMetric + completion(.success(Int64(httpMetricHandle))) + } + + func stopHttpMetric(handle: Int64, attributes: HttpMetricAttributes, + completion: @escaping (Result) -> Void) { + guard let httpMetric = httpMetrics[Int(handle)] else { + completion(.success(())) + return + } + + if let httpResponseCode = attributes.httpResponseCode { + httpMetric.responseCode = Int(httpResponseCode) + } + if let responseContentType = attributes.responseContentType { + httpMetric.responseContentType = responseContentType + } + if let requestPayloadSize = attributes.requestPayloadSize { + httpMetric.requestPayloadSize = Int(requestPayloadSize) + } + if let responsePayloadSize = attributes.responsePayloadSize { + httpMetric.responsePayloadSize = Int(responsePayloadSize) + } + + if let attributes = attributes.attributes { + for (key, value) in attributes { + httpMetric.setValue(value, forAttribute: key) + } + } + + httpMetric.stop() + httpMetrics.removeValue(forKey: Int(handle)) + completion(.success(())) + } + + private func parseHttpMethod(_ method: HttpMethod) -> HTTPMethod? { + switch method { + case HttpMethod.connect: return .connect + case HttpMethod.delete: return .delete + case HttpMethod.get: return .get + case HttpMethod.head: return .head + case HttpMethod.options: return .options + case HttpMethod.patch: return .patch + case HttpMethod.post: return .post + case HttpMethod.put: return .put + case HttpMethod.trace: return .trace + } + } +} diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/include/FLTFirebasePerformancePlugin.h b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/include/FLTFirebasePerformancePlugin.h deleted file mode 100644 index 65b30ab94a1b..000000000000 --- a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/include/FLTFirebasePerformancePlugin.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebasePerformance; -#import -#import -#if __has_include() -#import -#else -#import -#endif - -@interface FLTFirebasePerformancePlugin : FLTFirebasePlugin - -@end diff --git a/packages/firebase_performance/firebase_performance/pubspec.yaml b/packages/firebase_performance/firebase_performance/pubspec.yaml index 1efac1cc029e..595a4d93cede 100644 --- a/packages/firebase_performance/firebase_performance/pubspec.yaml +++ b/packages/firebase_performance/firebase_performance/pubspec.yaml @@ -41,6 +41,6 @@ flutter: package: io.flutter.plugins.firebase.performance pluginClass: FlutterFirebasePerformancePlugin ios: - pluginClass: FLTFirebasePerformancePlugin + pluginClass: FirebasePerformancePlugin web: default_package: firebase_performance_web diff --git a/packages/firebase_performance/firebase_performance/windows/messages.g.cpp b/packages/firebase_performance/firebase_performance/windows/messages.g.cpp new file mode 100644 index 000000000000..f5934afda061 --- /dev/null +++ b/packages/firebase_performance/firebase_performance/windows/messages.g.cpp @@ -0,0 +1,604 @@ +// Copyright 2025, 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 (v25.3.2), 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_performance_windows { +using flutter::BasicMessageChannel; +using flutter::CustomEncodableValue; +using flutter::EncodableList; +using flutter::EncodableMap; +using flutter::EncodableValue; + +FlutterError CreateConnectionError(const std::string channel_name) { + return FlutterError( + "channel-error", + "Unable to establish connection on channel: '" + channel_name + "'.", + EncodableValue("")); +} + +// HttpMetricOptions + +HttpMetricOptions::HttpMetricOptions(const std::string& url, + const HttpMethod& http_method) + : url_(url), http_method_(http_method) {} + +const std::string& HttpMetricOptions::url() const { return url_; } + +void HttpMetricOptions::set_url(std::string_view value_arg) { + url_ = value_arg; +} + +const HttpMethod& HttpMetricOptions::http_method() const { + return http_method_; +} + +void HttpMetricOptions::set_http_method(const HttpMethod& value_arg) { + http_method_ = value_arg; +} + +EncodableList HttpMetricOptions::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(url_)); + list.push_back(CustomEncodableValue(http_method_)); + return list; +} + +HttpMetricOptions HttpMetricOptions::FromEncodableList( + const EncodableList& list) { + HttpMetricOptions decoded(std::get(list[0]), + std::any_cast( + std::get(list[1]))); + return decoded; +} + +// HttpMetricAttributes + +HttpMetricAttributes::HttpMetricAttributes() {} + +HttpMetricAttributes::HttpMetricAttributes( + const int64_t* http_response_code, const int64_t* request_payload_size, + const int64_t* response_payload_size, + const std::string* response_content_type, const EncodableMap* attributes) + : http_response_code_(http_response_code + ? std::optional(*http_response_code) + : std::nullopt), + request_payload_size_(request_payload_size + ? std::optional(*request_payload_size) + : std::nullopt), + response_payload_size_( + response_payload_size ? std::optional(*response_payload_size) + : std::nullopt), + response_content_type_(response_content_type ? std::optional( + *response_content_type) + : std::nullopt), + attributes_(attributes ? std::optional(*attributes) + : std::nullopt) {} + +const int64_t* HttpMetricAttributes::http_response_code() const { + return http_response_code_ ? &(*http_response_code_) : nullptr; +} + +void HttpMetricAttributes::set_http_response_code(const int64_t* value_arg) { + http_response_code_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void HttpMetricAttributes::set_http_response_code(int64_t value_arg) { + http_response_code_ = value_arg; +} + +const int64_t* HttpMetricAttributes::request_payload_size() const { + return request_payload_size_ ? &(*request_payload_size_) : nullptr; +} + +void HttpMetricAttributes::set_request_payload_size(const int64_t* value_arg) { + request_payload_size_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void HttpMetricAttributes::set_request_payload_size(int64_t value_arg) { + request_payload_size_ = value_arg; +} + +const int64_t* HttpMetricAttributes::response_payload_size() const { + return response_payload_size_ ? &(*response_payload_size_) : nullptr; +} + +void HttpMetricAttributes::set_response_payload_size(const int64_t* value_arg) { + response_payload_size_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void HttpMetricAttributes::set_response_payload_size(int64_t value_arg) { + response_payload_size_ = value_arg; +} + +const std::string* HttpMetricAttributes::response_content_type() const { + return response_content_type_ ? &(*response_content_type_) : nullptr; +} + +void HttpMetricAttributes::set_response_content_type( + const std::string_view* value_arg) { + response_content_type_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void HttpMetricAttributes::set_response_content_type( + std::string_view value_arg) { + response_content_type_ = value_arg; +} + +const EncodableMap* HttpMetricAttributes::attributes() const { + return attributes_ ? &(*attributes_) : nullptr; +} + +void HttpMetricAttributes::set_attributes(const EncodableMap* value_arg) { + attributes_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void HttpMetricAttributes::set_attributes(const EncodableMap& value_arg) { + attributes_ = value_arg; +} + +EncodableList HttpMetricAttributes::ToEncodableList() const { + EncodableList list; + list.reserve(5); + list.push_back(http_response_code_ ? EncodableValue(*http_response_code_) + : EncodableValue()); + list.push_back(request_payload_size_ ? EncodableValue(*request_payload_size_) + : EncodableValue()); + list.push_back(response_payload_size_ + ? EncodableValue(*response_payload_size_) + : EncodableValue()); + list.push_back(response_content_type_ + ? EncodableValue(*response_content_type_) + : EncodableValue()); + list.push_back(attributes_ ? EncodableValue(*attributes_) : EncodableValue()); + return list; +} + +HttpMetricAttributes HttpMetricAttributes::FromEncodableList( + const EncodableList& list) { + HttpMetricAttributes decoded; + auto& encodable_http_response_code = list[0]; + if (!encodable_http_response_code.IsNull()) { + decoded.set_http_response_code( + std::get(encodable_http_response_code)); + } + auto& encodable_request_payload_size = list[1]; + if (!encodable_request_payload_size.IsNull()) { + decoded.set_request_payload_size( + std::get(encodable_request_payload_size)); + } + auto& encodable_response_payload_size = list[2]; + if (!encodable_response_payload_size.IsNull()) { + decoded.set_response_payload_size( + std::get(encodable_response_payload_size)); + } + auto& encodable_response_content_type = list[3]; + if (!encodable_response_content_type.IsNull()) { + decoded.set_response_content_type( + std::get(encodable_response_content_type)); + } + auto& encodable_attributes = list[4]; + if (!encodable_attributes.IsNull()) { + decoded.set_attributes(std::get(encodable_attributes)); + } + return decoded; +} + +// TraceAttributes + +TraceAttributes::TraceAttributes() {} + +TraceAttributes::TraceAttributes(const EncodableMap* metrics, + const EncodableMap* attributes) + : metrics_(metrics ? std::optional(*metrics) : std::nullopt), + attributes_(attributes ? std::optional(*attributes) + : std::nullopt) {} + +const EncodableMap* TraceAttributes::metrics() const { + return metrics_ ? &(*metrics_) : nullptr; +} + +void TraceAttributes::set_metrics(const EncodableMap* value_arg) { + metrics_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void TraceAttributes::set_metrics(const EncodableMap& value_arg) { + metrics_ = value_arg; +} + +const EncodableMap* TraceAttributes::attributes() const { + return attributes_ ? &(*attributes_) : nullptr; +} + +void TraceAttributes::set_attributes(const EncodableMap* value_arg) { + attributes_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void TraceAttributes::set_attributes(const EncodableMap& value_arg) { + attributes_ = value_arg; +} + +EncodableList TraceAttributes::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(metrics_ ? EncodableValue(*metrics_) : EncodableValue()); + list.push_back(attributes_ ? EncodableValue(*attributes_) : EncodableValue()); + return list; +} + +TraceAttributes TraceAttributes::FromEncodableList(const EncodableList& list) { + TraceAttributes decoded; + auto& encodable_metrics = list[0]; + if (!encodable_metrics.IsNull()) { + decoded.set_metrics(std::get(encodable_metrics)); + } + auto& encodable_attributes = list[1]; + if (!encodable_attributes.IsNull()) { + decoded.set_attributes(std::get(encodable_attributes)); + } + return decoded; +} + +PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} + +EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( + uint8_t type, flutter::ByteStreamReader* stream) const { + switch (type) { + case 129: { + const auto& encodable_enum_arg = ReadValue(stream); + const int64_t enum_arg_value = + encodable_enum_arg.IsNull() ? 0 : encodable_enum_arg.LongValue(); + return encodable_enum_arg.IsNull() + ? EncodableValue() + : CustomEncodableValue( + static_cast(enum_arg_value)); + } + case 130: { + return CustomEncodableValue(HttpMetricOptions::FromEncodableList( + std::get(ReadValue(stream)))); + } + case 131: { + return CustomEncodableValue(HttpMetricAttributes::FromEncodableList( + std::get(ReadValue(stream)))); + } + case 132: { + return CustomEncodableValue(TraceAttributes::FromEncodableList( + std::get(ReadValue(stream)))); + } + default: + return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + } +} + +void PigeonInternalCodecSerializer::WriteValue( + const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + if (const CustomEncodableValue* custom_value = + std::get_if(&value)) { + if (custom_value->type() == typeid(HttpMethod)) { + stream->WriteByte(129); + WriteValue(EncodableValue(static_cast( + std::any_cast(*custom_value))), + stream); + return; + } + if (custom_value->type() == typeid(HttpMetricOptions)) { + stream->WriteByte(130); + WriteValue(EncodableValue(std::any_cast(*custom_value) + .ToEncodableList()), + stream); + return; + } + if (custom_value->type() == typeid(HttpMetricAttributes)) { + stream->WriteByte(131); + WriteValue( + EncodableValue(std::any_cast(*custom_value) + .ToEncodableList()), + stream); + return; + } + if (custom_value->type() == typeid(TraceAttributes)) { + stream->WriteByte(132); + WriteValue( + EncodableValue( + std::any_cast(*custom_value).ToEncodableList()), + stream); + return; + } + } + flutter::StandardCodecSerializer::WriteValue(value, stream); +} + +/// The codec used by FirebasePerformanceHostApi. +const flutter::StandardMessageCodec& FirebasePerformanceHostApi::GetCodec() { + return flutter::StandardMessageCodec::GetInstance( + &PigeonInternalCodecSerializer::GetInstance()); +} + +// Sets up an instance of `FirebasePerformanceHostApi` to handle messages +// through the `binary_messenger`. +void FirebasePerformanceHostApi::SetUp( + flutter::BinaryMessenger* binary_messenger, + FirebasePerformanceHostApi* api) { + FirebasePerformanceHostApi::SetUp(binary_messenger, api, ""); +} + +void FirebasePerformanceHostApi::SetUp( + flutter::BinaryMessenger* binary_messenger, FirebasePerformanceHostApi* api, + const std::string& message_channel_suffix) { + const std::string prepended_suffix = + message_channel_suffix.length() > 0 + ? std::string(".") + message_channel_suffix + : ""; + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.setPerformanceCollectionEnabled" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_enabled_arg = args.at(0); + if (encodable_enabled_arg.IsNull()) { + reply(WrapError("enabled_arg unexpectedly null.")); + return; + } + const auto& enabled_arg = std::get(encodable_enabled_arg); + api->SetPerformanceCollectionEnabled( + enabled_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); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.isPerformanceCollectionEnabled" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + api->IsPerformanceCollectionEnabled( + [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); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.startTrace" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_name_arg = args.at(0); + if (encodable_name_arg.IsNull()) { + reply(WrapError("name_arg unexpectedly null.")); + return; + } + const auto& name_arg = std::get(encodable_name_arg); + api->StartTrace(name_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); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.stopTrace" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_handle_arg = args.at(0); + if (encodable_handle_arg.IsNull()) { + reply(WrapError("handle_arg unexpectedly null.")); + return; + } + const int64_t handle_arg = encodable_handle_arg.LongValue(); + const auto& encodable_attributes_arg = args.at(1); + if (encodable_attributes_arg.IsNull()) { + reply(WrapError("attributes_arg unexpectedly null.")); + return; + } + const auto& attributes_arg = + std::any_cast( + std::get(encodable_attributes_arg)); + api->StopTrace(handle_arg, attributes_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); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.startHttpMetric" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_options_arg = args.at(0); + if (encodable_options_arg.IsNull()) { + reply(WrapError("options_arg unexpectedly null.")); + return; + } + const auto& options_arg = std::any_cast( + std::get(encodable_options_arg)); + api->StartHttpMetric( + options_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); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.firebase_performance_platform_interface." + "FirebasePerformanceHostApi.stopHttpMetric" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_handle_arg = args.at(0); + if (encodable_handle_arg.IsNull()) { + reply(WrapError("handle_arg unexpectedly null.")); + return; + } + const int64_t handle_arg = encodable_handle_arg.LongValue(); + const auto& encodable_attributes_arg = args.at(1); + if (encodable_attributes_arg.IsNull()) { + reply(WrapError("attributes_arg unexpectedly null.")); + return; + } + const auto& attributes_arg = + std::any_cast( + std::get(encodable_attributes_arg)); + api->StopHttpMetric( + handle_arg, attributes_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 FirebasePerformanceHostApi::WrapError( + std::string_view error_message) { + return EncodableValue( + EncodableList{EncodableValue(std::string(error_message)), + EncodableValue("Error"), EncodableValue()}); +} + +EncodableValue FirebasePerformanceHostApi::WrapError( + const FlutterError& error) { + return EncodableValue(EncodableList{EncodableValue(error.code()), + EncodableValue(error.message()), + error.details()}); +} + +} // namespace firebase_performance_windows diff --git a/packages/firebase_performance/firebase_performance/windows/messages.g.h b/packages/firebase_performance/firebase_performance/windows/messages.g.h new file mode 100644 index 000000000000..a9802f4c703a --- /dev/null +++ b/packages/firebase_performance/firebase_performance/windows/messages.g.h @@ -0,0 +1,227 @@ +// Copyright 2025, 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 (v25.3.2), 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_performance_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 FirebasePerformanceHostApi; + ErrorOr() = default; + T TakeValue() && { return std::get(std::move(v_)); } + + std::variant v_; +}; + +enum class HttpMethod { + kConnect = 0, + kDelete = 1, + kGet = 2, + kHead = 3, + kOptions = 4, + kPatch = 5, + kPost = 6, + kPut = 7, + kTrace = 8 +}; + +// Generated class from Pigeon that represents data sent in messages. +class HttpMetricOptions { + public: + // Constructs an object setting all fields. + explicit HttpMetricOptions(const std::string& url, + const HttpMethod& http_method); + + const std::string& url() const; + void set_url(std::string_view value_arg); + + const HttpMethod& http_method() const; + void set_http_method(const HttpMethod& value_arg); + + private: + static HttpMetricOptions FromEncodableList( + const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebasePerformanceHostApi; + friend class PigeonInternalCodecSerializer; + std::string url_; + HttpMethod http_method_; +}; + +// Generated class from Pigeon that represents data sent in messages. +class HttpMetricAttributes { + public: + // Constructs an object setting all non-nullable fields. + HttpMetricAttributes(); + + // Constructs an object setting all fields. + explicit HttpMetricAttributes(const int64_t* http_response_code, + const int64_t* request_payload_size, + const int64_t* response_payload_size, + const std::string* response_content_type, + const flutter::EncodableMap* attributes); + + const int64_t* http_response_code() const; + void set_http_response_code(const int64_t* value_arg); + void set_http_response_code(int64_t value_arg); + + const int64_t* request_payload_size() const; + void set_request_payload_size(const int64_t* value_arg); + void set_request_payload_size(int64_t value_arg); + + const int64_t* response_payload_size() const; + void set_response_payload_size(const int64_t* value_arg); + void set_response_payload_size(int64_t value_arg); + + const std::string* response_content_type() const; + void set_response_content_type(const std::string_view* value_arg); + void set_response_content_type(std::string_view value_arg); + + const flutter::EncodableMap* attributes() const; + void set_attributes(const flutter::EncodableMap* value_arg); + void set_attributes(const flutter::EncodableMap& value_arg); + + private: + static HttpMetricAttributes FromEncodableList( + const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebasePerformanceHostApi; + friend class PigeonInternalCodecSerializer; + std::optional http_response_code_; + std::optional request_payload_size_; + std::optional response_payload_size_; + std::optional response_content_type_; + std::optional attributes_; +}; + +// Generated class from Pigeon that represents data sent in messages. +class TraceAttributes { + public: + // Constructs an object setting all non-nullable fields. + TraceAttributes(); + + // Constructs an object setting all fields. + explicit TraceAttributes(const flutter::EncodableMap* metrics, + const flutter::EncodableMap* attributes); + + const flutter::EncodableMap* metrics() const; + void set_metrics(const flutter::EncodableMap* value_arg); + void set_metrics(const flutter::EncodableMap& value_arg); + + const flutter::EncodableMap* attributes() const; + void set_attributes(const flutter::EncodableMap* value_arg); + void set_attributes(const flutter::EncodableMap& value_arg); + + private: + static TraceAttributes FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class FirebasePerformanceHostApi; + friend class PigeonInternalCodecSerializer; + std::optional metrics_; + std::optional attributes_; +}; + +class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { + public: + PigeonInternalCodecSerializer(); + inline static PigeonInternalCodecSerializer& GetInstance() { + static PigeonInternalCodecSerializer 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 FirebasePerformanceHostApi { + public: + FirebasePerformanceHostApi(const FirebasePerformanceHostApi&) = delete; + FirebasePerformanceHostApi& operator=(const FirebasePerformanceHostApi&) = + delete; + virtual ~FirebasePerformanceHostApi() {} + virtual void SetPerformanceCollectionEnabled( + bool enabled, + std::function reply)> result) = 0; + virtual void IsPerformanceCollectionEnabled( + std::function reply)> result) = 0; + virtual void StartTrace( + const std::string& name, + std::function reply)> result) = 0; + virtual void StopTrace( + int64_t handle, const TraceAttributes& attributes, + std::function reply)> result) = 0; + virtual void StartHttpMetric( + const HttpMetricOptions& options, + std::function reply)> result) = 0; + virtual void StopHttpMetric( + int64_t handle, const HttpMetricAttributes& attributes, + std::function reply)> result) = 0; + + // The codec used by FirebasePerformanceHostApi. + static const flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `FirebasePerformanceHostApi` to handle messages + // through the `binary_messenger`. + static void SetUp(flutter::BinaryMessenger* binary_messenger, + FirebasePerformanceHostApi* api); + static void SetUp(flutter::BinaryMessenger* binary_messenger, + FirebasePerformanceHostApi* api, + const std::string& message_channel_suffix); + static flutter::EncodableValue WrapError(std::string_view error_message); + static flutter::EncodableValue WrapError(const FlutterError& error); + + protected: + FirebasePerformanceHostApi() = default; +}; +} // namespace firebase_performance_windows +#endif // PIGEON_MESSAGES_G_H_ diff --git a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart index a361e3d8753e..b07d56fc5215 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart @@ -4,6 +4,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_performance_platform_interface/src/method_channel/method_channel_trace.dart'; +import 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart'; import 'package:flutter/services.dart'; import '../../firebase_performance_platform_interface.dart'; @@ -29,6 +30,8 @@ class MethodChannelFirebasePerformance extends FirebasePerformancePlatform { return MethodChannelFirebasePerformance._(); } + static final pigeonChannel = FirebasePerformanceHostApi(); + /// Instances are cached and reused for incoming event handlers. @override FirebasePerformancePlatform delegateFor({required FirebaseApp app}) { @@ -38,10 +41,7 @@ class MethodChannelFirebasePerformance extends FirebasePerformancePlatform { @override Future isPerformanceCollectionEnabled() async { try { - final isPerformanceCollectionEnabled = await channel.invokeMethod( - 'FirebasePerformance#isPerformanceCollectionEnabled', - ); - return isPerformanceCollectionEnabled!; + return await pigeonChannel.isPerformanceCollectionEnabled(); } catch (e, s) { convertPlatformException(e, s); } @@ -50,10 +50,7 @@ class MethodChannelFirebasePerformance extends FirebasePerformancePlatform { @override Future setPerformanceCollectionEnabled(bool enabled) async { try { - await channel.invokeMethod( - 'FirebasePerformance#setPerformanceCollectionEnabled', - {'enable': enabled}, - ); + await pigeonChannel.setPerformanceCollectionEnabled(enabled); } catch (e, s) { convertPlatformException(e, s); } diff --git a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_http_metric.dart b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_http_metric.dart index e04a6ba1fa0c..d002a8849b0c 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_http_metric.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_http_metric.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart' + as pigeon; import '../../firebase_performance_platform_interface.dart'; import 'method_channel_firebase_performance.dart'; import 'utils/exception.dart'; @@ -60,14 +62,12 @@ class MethodChannelHttpMetric extends HttpMetricPlatform { Future start() async { if (_httpMetricHandle != null) return; try { - _httpMetricHandle = - await MethodChannelFirebasePerformance.channel.invokeMethod( - 'FirebasePerformance#httpMetricStart', - { - 'url': _url, - 'httpMethod': _httpMethod.toString(), - }, + final options = pigeon.HttpMetricOptions( + url: _url, + httpMethod: _convertHttpMethod(_httpMethod), ); + _httpMetricHandle = await MethodChannelFirebasePerformance.pigeonChannel + .startHttpMetric(options); } catch (e, s) { convertPlatformException(e, s); } @@ -77,20 +77,15 @@ class MethodChannelHttpMetric extends HttpMetricPlatform { Future stop() async { if (_httpMetricHandle == null || _hasStopped) return; try { - await MethodChannelFirebasePerformance.channel.invokeMethod( - 'FirebasePerformance#httpMetricStop', - { - 'handle': _httpMetricHandle, - 'attributes': _attributes, - if (_httpResponseCode != null) 'httpResponseCode': _httpResponseCode, - if (_requestPayloadSize != null) - 'requestPayloadSize': _requestPayloadSize, - if (_responseContentType != null) - 'responseContentType': _responseContentType, - if (_responsePayloadSize != null) - 'responsePayloadSize': _responsePayloadSize, - }, + final attributes = pigeon.HttpMetricAttributes( + httpResponseCode: _httpResponseCode, + requestPayloadSize: _requestPayloadSize, + responsePayloadSize: _responsePayloadSize, + responseContentType: _responseContentType, + attributes: _attributes, ); + await MethodChannelFirebasePerformance.pigeonChannel + .stopHttpMetric(_httpMetricHandle!, attributes); _hasStopped = true; } catch (e, s) { convertPlatformException(e, s); @@ -119,4 +114,27 @@ class MethodChannelHttpMetric extends HttpMetricPlatform { Map getAttributes() { return {..._attributes}; } + + pigeon.HttpMethod _convertHttpMethod(HttpMethod method) { + switch (method) { + case HttpMethod.Connect: + return pigeon.HttpMethod.connect; + case HttpMethod.Delete: + return pigeon.HttpMethod.delete; + case HttpMethod.Get: + return pigeon.HttpMethod.get; + case HttpMethod.Head: + return pigeon.HttpMethod.head; + case HttpMethod.Options: + return pigeon.HttpMethod.options; + case HttpMethod.Patch: + return pigeon.HttpMethod.patch; + case HttpMethod.Post: + return pigeon.HttpMethod.post; + case HttpMethod.Put: + return pigeon.HttpMethod.put; + case HttpMethod.Trace: + return pigeon.HttpMethod.trace; + } + } } diff --git a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_trace.dart b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_trace.dart index ef8925baa74b..d6d46f1d1b35 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_trace.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_trace.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart'; import '../../firebase_performance_platform_interface.dart'; import 'method_channel_firebase_performance.dart'; import 'utils/exception.dart'; @@ -24,11 +25,8 @@ class MethodChannelTrace extends TracePlatform { if (_traceHandle != null) return; try { - _traceHandle = - await MethodChannelFirebasePerformance.channel.invokeMethod( - 'FirebasePerformance#traceStart', - {'name': _name}, - ); + _traceHandle = await MethodChannelFirebasePerformance.pigeonChannel + .startTrace(_name); } catch (e, s) { convertPlatformException(e, s); } @@ -39,14 +37,12 @@ class MethodChannelTrace extends TracePlatform { if (_traceHandle == null || _hasStopped) return; try { - await MethodChannelFirebasePerformance.channel.invokeMethod( - 'FirebasePerformance#traceStop', - { - 'handle': _traceHandle, - 'metrics': _metrics, - 'attributes': _attributes, - }, + final attributes = TraceAttributes( + metrics: _metrics, + attributes: _attributes, ); + await MethodChannelFirebasePerformance.pigeonChannel + .stopTrace(_traceHandle!, attributes); _hasStopped = true; } catch (e, s) { convertPlatformException(e, s); diff --git a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/pigeon/messages.pigeon.dart new file mode 100644 index 000000000000..b01f643749c4 --- /dev/null +++ b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -0,0 +1,439 @@ +// Copyright 2025, 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 (v25.3.2), 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, no_leading_underscores_for_local_identifiers + +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'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +bool _deepEquals(Object? a, Object? b) { + if (a is List && b is List) { + return a.length == b.length && + a.indexed + .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); + } + if (a is Map && b is Map) { + return a.length == b.length && + a.entries.every((MapEntry entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key])); + } + return a == b; +} + +enum HttpMethod { + connect, + delete, + get, + head, + options, + patch, + post, + put, + trace, +} + +class HttpMetricOptions { + HttpMetricOptions({ + required this.url, + required this.httpMethod, + }); + + String url; + + HttpMethod httpMethod; + + List _toList() { + return [ + url, + httpMethod, + ]; + } + + Object encode() { + return _toList(); + } + + static HttpMetricOptions decode(Object result) { + result as List; + return HttpMetricOptions( + url: result[0]! as String, + httpMethod: result[1]! as HttpMethod, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! HttpMetricOptions || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class HttpMetricAttributes { + HttpMetricAttributes({ + this.httpResponseCode, + this.requestPayloadSize, + this.responsePayloadSize, + this.responseContentType, + this.attributes, + }); + + int? httpResponseCode; + + int? requestPayloadSize; + + int? responsePayloadSize; + + String? responseContentType; + + Map? attributes; + + List _toList() { + return [ + httpResponseCode, + requestPayloadSize, + responsePayloadSize, + responseContentType, + attributes, + ]; + } + + Object encode() { + return _toList(); + } + + static HttpMetricAttributes decode(Object result) { + result as List; + return HttpMetricAttributes( + httpResponseCode: result[0] as int?, + requestPayloadSize: result[1] as int?, + responsePayloadSize: result[2] as int?, + responseContentType: result[3] as String?, + attributes: (result[4] as Map?)?.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! HttpMetricAttributes || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class TraceAttributes { + TraceAttributes({ + this.metrics, + this.attributes, + }); + + Map? metrics; + + Map? attributes; + + List _toList() { + return [ + metrics, + attributes, + ]; + } + + Object encode() { + return _toList(); + } + + static TraceAttributes decode(Object result) { + result as List; + return TraceAttributes( + metrics: (result[0] as Map?)?.cast(), + attributes: (result[1] as Map?)?.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! TraceAttributes || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is HttpMethod) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is HttpMetricOptions) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is HttpMetricAttributes) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is TraceAttributes) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : HttpMethod.values[value]; + case 130: + return HttpMetricOptions.decode(readValue(buffer)!); + case 131: + return HttpMetricAttributes.decode(readValue(buffer)!); + case 132: + return TraceAttributes.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class FirebasePerformanceHostApi { + /// Constructor for [FirebasePerformanceHostApi]. 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. + FirebasePerformanceHostApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future setPerformanceCollectionEnabled(bool enabled) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([enabled]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future isPerformanceCollectionEnabled() async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.isPerformanceCollectionEnabled$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future startTrace(String name) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([name]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as int?)!; + } + } + + Future stopTrace(int handle, TraceAttributes attributes) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([handle, attributes]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future startHttpMetric(HttpMetricOptions options) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([options]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as int?)!; + } + } + + Future stopHttpMetric( + int handle, HttpMetricAttributes attributes) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([handle, attributes]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} diff --git a/packages/firebase_performance/firebase_performance_platform_interface/pigeons/copyright.txt b/packages/firebase_performance/firebase_performance_platform_interface/pigeons/copyright.txt new file mode 100644 index 000000000000..4e197781c6db --- /dev/null +++ b/packages/firebase_performance/firebase_performance_platform_interface/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2025, 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_performance/firebase_performance_platform_interface/pigeons/messages.dart b/packages/firebase_performance/firebase_performance_platform_interface/pigeons/messages.dart new file mode 100644 index 000000000000..10603e2a480a --- /dev/null +++ b/packages/firebase_performance/firebase_performance_platform_interface/pigeons/messages.dart @@ -0,0 +1,92 @@ +// Copyright 2025 The Chromium Authors. 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', + dartTestOut: 'test/pigeon/test_api.dart', + dartPackageName: 'firebase_performance_platform_interface', + kotlinOut: + '../firebase_performance/android/src/main/kotlin/io/flutter/plugins/firebase/performance/GeneratedAndroidFirebasePerformance.g.kt', + kotlinOptions: KotlinOptions( + package: 'io.flutter.plugins.firebase.performance', + ), + swiftOut: + '../firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformanceMessages.g.swift', + cppHeaderOut: '../firebase_performance/windows/messages.g.h', + cppSourceOut: '../firebase_performance/windows/messages.g.cpp', + cppOptions: CppOptions(namespace: 'firebase_performance_windows'), + copyrightHeader: 'pigeons/copyright.txt', + ), +) +enum HttpMethod { + connect, + delete, + get, + head, + options, + patch, + post, + put, + trace, +} + +class HttpMetricOptions { + const HttpMetricOptions({ + required this.url, + required this.httpMethod, + }); + + final String url; + final HttpMethod httpMethod; +} + +class HttpMetricAttributes { + const HttpMetricAttributes({ + this.httpResponseCode, + this.requestPayloadSize, + this.responsePayloadSize, + this.responseContentType, + this.attributes, + }); + + final int? httpResponseCode; + final int? requestPayloadSize; + final int? responsePayloadSize; + final String? responseContentType; + final Map? attributes; +} + +class TraceAttributes { + const TraceAttributes({ + this.metrics, + this.attributes, + }); + + final Map? metrics; + final Map? attributes; +} + +@HostApi(dartHostTestHandler: 'TestFirebasePerformanceHostApi') +abstract class FirebasePerformanceHostApi { + @async + void setPerformanceCollectionEnabled(bool enabled); + + @async + bool isPerformanceCollectionEnabled(); + + @async + int startTrace(String name); + + @async + void stopTrace(int handle, TraceAttributes attributes); + + @async + int startHttpMetric(HttpMetricOptions options); + + @async + void stopHttpMetric(int handle, HttpMetricAttributes attributes); +} diff --git a/packages/firebase_performance/firebase_performance_platform_interface/pubspec.yaml b/packages/firebase_performance/firebase_performance_platform_interface/pubspec.yaml index caa551db2f87..9fdd0b27e18c 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/pubspec.yaml +++ b/packages/firebase_performance/firebase_performance_platform_interface/pubspec.yaml @@ -18,3 +18,4 @@ dev_dependencies: firebase_core_platform_interface: ^6.0.0 flutter_test: sdk: flutter + pigeon: 25.3.2 diff --git a/packages/firebase_performance/firebase_performance_platform_interface/test/pigeon/test_api.dart b/packages/firebase_performance/firebase_performance_platform_interface/test/pigeon/test_api.dart new file mode 100644 index 000000000000..4426bc6d19af --- /dev/null +++ b/packages/firebase_performance/firebase_performance_platform_interface/test/pigeon/test_api.dart @@ -0,0 +1,277 @@ +// Copyright 2025, 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 (v25.3.2), 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, no_leading_underscores_for_local_identifiers +// 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 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart'; + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is HttpMethod) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is HttpMetricOptions) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is HttpMetricAttributes) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is TraceAttributes) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : HttpMethod.values[value]; + case 130: + return HttpMetricOptions.decode(readValue(buffer)!); + case 131: + return HttpMetricAttributes.decode(readValue(buffer)!); + case 132: + return TraceAttributes.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class TestFirebasePerformanceHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + Future setPerformanceCollectionEnabled(bool enabled); + + Future isPerformanceCollectionEnabled(); + + Future startTrace(String name); + + Future stopTrace(int handle, TraceAttributes attributes); + + Future startHttpMetric(HttpMetricOptions options); + + Future stopHttpMetric(int handle, HttpMetricAttributes attributes); + + static void setUp( + TestFirebasePerformanceHostApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled was null.'); + final List args = (message as List?)!; + final bool? arg_enabled = (args[0] as bool?); + assert(arg_enabled != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.setPerformanceCollectionEnabled was null, expected non-null bool.'); + try { + await api.setPerformanceCollectionEnabled(arg_enabled!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.isPerformanceCollectionEnabled$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + try { + final bool output = await api.isPerformanceCollectionEnabled(); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace was null.'); + final List args = (message as List?)!; + final String? arg_name = (args[0] as String?); + assert(arg_name != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startTrace was null, expected non-null String.'); + try { + final int output = await api.startTrace(arg_name!); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace was null.'); + final List args = (message as List?)!; + final int? arg_handle = (args[0] as int?); + assert(arg_handle != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace was null, expected non-null int.'); + final TraceAttributes? arg_attributes = (args[1] as TraceAttributes?); + assert(arg_attributes != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopTrace was null, expected non-null TraceAttributes.'); + try { + await api.stopTrace(arg_handle!, arg_attributes!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric was null.'); + final List args = (message as List?)!; + final HttpMetricOptions? arg_options = + (args[0] as HttpMetricOptions?); + assert(arg_options != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.startHttpMetric was null, expected non-null HttpMetricOptions.'); + try { + final int output = await api.startHttpMetric(arg_options!); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric was null.'); + final List args = (message as List?)!; + final int? arg_handle = (args[0] as int?); + assert(arg_handle != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric was null, expected non-null int.'); + final HttpMetricAttributes? arg_attributes = + (args[1] as HttpMetricAttributes?); + assert(arg_attributes != null, + 'Argument for dev.flutter.pigeon.firebase_performance_platform_interface.FirebasePerformanceHostApi.stopHttpMetric was null, expected non-null HttpMetricAttributes.'); + try { + await api.stopHttpMetric(arg_handle!, arg_attributes!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/packages/firebase_storage/firebase_storage/example/windows/runner/main.cpp b/packages/firebase_storage/firebase_storage/example/windows/runner/main.cpp index bf07e45b3a4a..7a451dd2d11c 100644 --- a/packages/firebase_storage/firebase_storage/example/windows/runner/main.cpp +++ b/packages/firebase_storage/firebase_storage/example/windows/runner/main.cpp @@ -10,7 +10,7 @@ #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { + _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()) { From 9d3efc06b8bc13da8406a84d09fe8ede1514a671 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 1 Sep 2025 09:12:35 +0000 Subject: [PATCH 2/5] chore: fix ci --- .../FirebasePerformancePlugin.swift | 13 +++++++++++-- .../method_channel_firebase_performance.dart | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift index 3f567c0c7272..d1d0c98c0074 100644 --- a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift @@ -2,9 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import firebase_core +#if canImport(FlutterMacOS) + import FlutterMacOS +#else + import Flutter +#endif + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif import FirebasePerformance -import Flutter let FirebasePerformanceChannelName = "plugins.flutter.io/firebase_performance" diff --git a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart index b07d56fc5215..70b070c25e55 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/lib/src/method_channel/method_channel_firebase_performance.dart @@ -4,7 +4,8 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_performance_platform_interface/src/method_channel/method_channel_trace.dart'; -import 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart'; +import 'package:firebase_performance_platform_interface/src/pigeon/messages.pigeon.dart' + as pigeon; import 'package:flutter/services.dart'; import '../../firebase_performance_platform_interface.dart'; @@ -30,7 +31,7 @@ class MethodChannelFirebasePerformance extends FirebasePerformancePlatform { return MethodChannelFirebasePerformance._(); } - static final pigeonChannel = FirebasePerformanceHostApi(); + static final pigeonChannel = pigeon.FirebasePerformanceHostApi(); /// Instances are cached and reused for incoming event handlers. @override From b39d08136f819b067ba30d3457bd0c7efdc5c939 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 1 Sep 2025 10:25:54 +0000 Subject: [PATCH 3/5] fix(performance): update performance collection methods to use data collection field --- .../firebase_performance/FirebasePerformancePlugin.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift index d1d0c98c0074..6d0ac5c39979 100644 --- a/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift +++ b/packages/firebase_performance/firebase_performance/ios/firebase_performance/Sources/firebase_performance/FirebasePerformancePlugin.swift @@ -60,12 +60,12 @@ public class FirebasePerformancePlugin: NSObject, FlutterPlugin, FLTFirebasePlug public func setPerformanceCollectionEnabled(enabled: Bool, completion: @escaping (Result) -> Void) { - Performance.sharedInstance().isInstrumentationEnabled = enabled + Performance.sharedInstance().isDataCollectionEnabled = enabled completion(.success(())) } public func isPerformanceCollectionEnabled(completion: @escaping (Result) -> Void) { - let result = Performance.sharedInstance().isInstrumentationEnabled + let result = Performance.sharedInstance().isDataCollectionEnabled completion(.success(result)) } From dbf4e72c92db7955f172b33c6e1d9a8505270243 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 1 Sep 2025 10:26:27 +0000 Subject: [PATCH 4/5] tests: remove redundant performance collection tests --- ...hod_channel_firebase_performance_test.dart | 48 ------- .../method_channel_http_metric_test.dart | 72 ----------- .../method_channel_trace_test.dart | 119 ------------------ 3 files changed, 239 deletions(-) diff --git a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_firebase_performance_test.dart b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_firebase_performance_test.dart index e806929ed083..49b990c607a9 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_firebase_performance_test.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_firebase_performance_test.dart @@ -75,54 +75,6 @@ void main() { expect(result.app, isA()); }); - group('isPerformanceCollectionEnabled', () { - test('should call delegate method successfully', () async { - await performance.isPerformanceCollectionEnabled(); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#isPerformanceCollectionEnabled', - arguments: null, - ), - ]); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - mockPlatformExceptionThrown = true; - - await testExceptionHandling( - 'PLATFORM', - performance.isPerformanceCollectionEnabled, - ); - }); - }); - - group('setPerformanceCollectionEnabled', () { - test('should call delegate method successfully', () async { - await performance.setPerformanceCollectionEnabled(true); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#setPerformanceCollectionEnabled', - arguments: {'enable': true}, - ), - ]); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - mockPlatformExceptionThrown = true; - - await testExceptionHandling( - 'PLATFORM', - () => performance.setPerformanceCollectionEnabled(true), - ); - }); - }); - group('newTrace', () { test('should call delegate method successfully', () { final trace = performance.newTrace('trace-name'); diff --git a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_http_metric_test.dart b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_http_metric_test.dart index a0c26407fb1d..7edcc62c095e 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_http_metric_test.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_http_metric_test.dart @@ -65,78 +65,6 @@ void main() { expect(httpMetric, isA()); }); - group('start', () { - test('should call delegate method successfully', () async { - await httpMetric.start(); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#httpMetricStart', - arguments: { - 'url': kUrl, - 'httpMethod': kMethod.toString(), - }, - ), - ]); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - mockPlatformExceptionThrown = true; - - await testExceptionHandling('PLATFORM', httpMetric.start); - }); - }); - - group('stop', () { - test('should call delegate method successfully', () async { - await httpMetric.start(); - - httpMetric.putAttribute('foo', 'bar'); - httpMetric.httpResponseCode = 2; - httpMetric.requestPayloadSize = 28; - httpMetric.responseContentType = 'baz'; - httpMetric.responsePayloadSize = 23; - await httpMetric.stop(); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#httpMetricStart', - arguments: {'url': kUrl, 'httpMethod': kMethod.toString()}, - ), - isMethodCall( - 'FirebasePerformance#httpMetricStop', - arguments: { - 'handle': kHttpMetricHandle, - 'attributes': { - 'foo': 'bar', - }, - 'httpResponseCode': 2, - 'requestPayloadSize': 28, - 'responseContentType': 'baz', - 'responsePayloadSize': 23, - }, - ), - ]); - }); - - test("will immediately return if start() hasn't been called first", - () async { - await httpMetric.stop(); - expect(log, []); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - await httpMetric.start(); - mockPlatformExceptionThrown = true; - - await testExceptionHandling('PLATFORM', httpMetric.stop); - }); - }); - group('httpResponseCode', () { test('httpResponseCode', () async { httpMetric.httpResponseCode = 3; diff --git a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart index e99d62e3ffa5..e3fa3c0dcac2 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart @@ -61,125 +61,6 @@ void main() { expect(trace, isA()); }); - group('start', () { - test('should call delegate method successfully', () async { - await trace.start(); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#traceStart', - arguments: {'name': kName}, - ), - ]); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - mockPlatformExceptionThrown = true; - - await testExceptionHandling('PLATFORM', trace.start); - }); - }); - - group('stop', () { - test('should call delegate method successfully', () async { - await trace.start(); - trace.putAttribute('bar', 'baz'); - trace.setMetric('yoo', 33); - - await trace.stop(); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#traceStart', - arguments: {'name': kName}, - ), - isMethodCall( - 'FirebasePerformance#traceStop', - arguments: { - 'handle': kTraceHandle, - 'metrics': { - 'yoo': 33, - }, - 'attributes': { - 'bar': 'baz', - }, - }, - ), - ]); - }); - - test("will immediately return if start() hasn't been called first", - () async { - await trace.stop(); - expect(log, []); - }); - - test( - 'catch a [PlatformException] error and throws a [FirebaseException] error', - () async { - await trace.start(); - mockPlatformExceptionThrown = true; - - await testExceptionHandling('PLATFORM', trace.stop); - }); - }); - - group('incrementMetric', () { - const String metricName = 'test-metric-name'; - const int metricValue = 453; - test('should call delegate method successfully', () async { - await trace.start(); - trace.incrementMetric(metricName, metricValue); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#traceStart', - arguments: {'name': kName}, - ), - ]); - - expect(trace.getMetric(metricName), metricValue); - }); - }); - - group('setMetric', () { - const String metricName = 'test-metric-name'; - const int metricValue = 4; - test('should call delegate method successfully', () async { - await trace.start(); - trace.setMetric(metricName, metricValue); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#traceStart', - arguments: {'name': kName}, - ), - ]); - - expect(trace.getMetric(metricName), metricValue); - }); - }); - - group('getMetric', () { - const String metricName = 'test-metric-name'; - const int metricValue = 546; - test('should call delegate method successfully', () async { - await trace.start(); - trace.setMetric(metricName, metricValue); - - expect(log, [ - isMethodCall( - 'FirebasePerformance#traceStart', - arguments: {'name': kName}, - ), - ]); - - expect(trace.getMetric(metricName), metricValue); - }); - }); - group('putAttribute', () { test('should call delegate method successfully', () async { const String attributeName = 'test-attribute-name'; From ea7f167c3b516946927f85d7cacc9c7258f1c900 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 1 Sep 2025 10:39:16 +0000 Subject: [PATCH 5/5] chore: remove unused trace handle constant from method channel trace tests --- .../test/method_channel_tests/method_channel_trace_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart index e3fa3c0dcac2..ed423c3e8cea 100644 --- a/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart +++ b/packages/firebase_performance/firebase_performance_platform_interface/test/method_channel_tests/method_channel_trace_test.dart @@ -14,7 +14,6 @@ void main() { setupFirebasePerformanceMocks(); late TestMethodChannelTrace trace; - const int kTraceHandle = 1; const String kName = 'test-trace-name'; final List log = []; // mock props