From 4db57d77f224eee665b6d442fb364a951525e5d0 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 22 Sep 2026 23:52:14 +0000 Subject: [PATCH 1/4] feat: register flutter-fire-ai and flutter-fire-dc platform versions and fix web late registration --- .../firebase_ai/android/build.gradle | 16 ++++++ .../android/src/main/AndroidManifest.xml | 6 +++ .../ai/FlutterFirebaseAppRegistrar.kt | 28 +++++++++++ .../firebase_ai/android/user-agent.gradle | 22 ++++++++ .../Sources/firebase_ai/Constants.swift | 16 ++++++ .../firebase_ai/FirebaseAIPlugin.swift | 11 ++++ .../firebase_ai/lib/src/firebase_ai.dart | 7 ++- .../lib/src/platform_version_stub.dart | 16 ++++++ .../lib/src/platform_version_web.dart | 50 +++++++++++++++++++ .../Sources/firebase_ai/Constants.swift | 1 + .../lib/src/firebase_core_web.dart | 3 ++ .../lib/src/firebase_data_connect.dart | 4 ++ .../src/network/hot_restart_guard_stub.dart | 2 + .../src/network/hot_restart_guard_web.dart | 33 ++++++++++++ scripts/generate_versions_spm.dart | 1 + 15 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 packages/firebase_ai/firebase_ai/android/src/main/kotlin/io/flutter/plugins/firebase/ai/FlutterFirebaseAppRegistrar.kt create mode 100644 packages/firebase_ai/firebase_ai/android/user-agent.gradle create mode 100644 packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift create mode 100644 packages/firebase_ai/firebase_ai/lib/src/platform_version_stub.dart create mode 100644 packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart create mode 120000 packages/firebase_ai/firebase_ai/macos/firebase_ai/Sources/firebase_ai/Constants.swift diff --git a/packages/firebase_ai/firebase_ai/android/build.gradle b/packages/firebase_ai/firebase_ai/android/build.gradle index 278104b4b9c2..a5673fbc5742 100644 --- a/packages/firebase_ai/firebase_ai/android/build.gradle +++ b/packages/firebase_ai/firebase_ai/android/build.gradle @@ -21,6 +21,11 @@ buildscript { } } +def firebaseCoreProject = findProject(':firebase_core') +if (firebaseCoreProject == null) { + throw new GradleException('Could not find the firebase_core FlutterFire plugin, have you added it as a dependency in your pubspec?') +} + android { if (project.android.hasProperty("namespace")) { namespace 'io.flutter.plugins.firebase.ai' @@ -41,9 +46,18 @@ android { main.java.srcDirs += "src/main/kotlin" } + buildFeatures { + buildConfig = true + } + lintOptions { disable 'InvalidPackage' } + + dependencies { + api firebaseCoreProject + implementation 'androidx.annotation:annotation:1.7.0' + } } plugins.withId("org.jetbrains.kotlin.android") { @@ -53,3 +67,5 @@ plugins.withId("org.jetbrains.kotlin.android") { } } } + +apply from: file("./user-agent.gradle") diff --git a/packages/firebase_ai/firebase_ai/android/src/main/AndroidManifest.xml b/packages/firebase_ai/firebase_ai/android/src/main/AndroidManifest.xml index db54cec9bea5..12fbf47e96eb 100644 --- a/packages/firebase_ai/firebase_ai/android/src/main/AndroidManifest.xml +++ b/packages/firebase_ai/firebase_ai/android/src/main/AndroidManifest.xml @@ -1,3 +1,9 @@ + + + + + diff --git a/packages/firebase_ai/firebase_ai/android/src/main/kotlin/io/flutter/plugins/firebase/ai/FlutterFirebaseAppRegistrar.kt b/packages/firebase_ai/firebase_ai/android/src/main/kotlin/io/flutter/plugins/firebase/ai/FlutterFirebaseAppRegistrar.kt new file mode 100644 index 000000000000..6c69cea53ef1 --- /dev/null +++ b/packages/firebase_ai/firebase_ai/android/src/main/kotlin/io/flutter/plugins/firebase/ai/FlutterFirebaseAppRegistrar.kt @@ -0,0 +1,28 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package io.flutter.plugins.firebase.ai + +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_ai/firebase_ai/android/user-agent.gradle b/packages/firebase_ai/firebase_ai/android/user-agent.gradle new file mode 100644 index 000000000000..863c976dcaef --- /dev/null +++ b/packages/firebase_ai/firebase_ai/android/user-agent.gradle @@ -0,0 +1,22 @@ +import java.util.regex.Matcher +import java.util.regex.Pattern + +String libraryVersionName = "UNKNOWN" +String libraryName = "flutter-fire-ai" +File pubspec = new File(project.projectDir.parentFile, 'pubspec.yaml') + +if (pubspec.exists()) { + String yaml = pubspec.text + // Using \s*['|"]?([^\n|'|"]*)['|"]? to extract version number. + Matcher versionMatcher = Pattern.compile("^version:\\s*['|\"]?([^\\n|'|\"]*)['|\"]?\$", Pattern.MULTILINE).matcher(yaml) + if (versionMatcher.find()) libraryVersionName = versionMatcher.group(1).replaceAll("\\+", "-") +} + +android { + defaultConfig { + // BuildConfig.VERSION_NAME + buildConfigField 'String', 'LIBRARY_VERSION', "\"${libraryVersionName}\"" + // BuildConfig.LIBRARY_NAME + buildConfigField 'String', 'LIBRARY_NAME', "\"${libraryName}\"" + } +} diff --git a/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift new file mode 100644 index 000000000000..54bc17e11a6c --- /dev/null +++ b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift @@ -0,0 +1,16 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Auto-generated file. Do not edit. +public let versionNumber = "4.0.0" diff --git a/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/FirebaseAIPlugin.swift b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/FirebaseAIPlugin.swift index a76212182bda..e0ae35823168 100644 --- a/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/FirebaseAIPlugin.swift +++ b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/FirebaseAIPlugin.swift @@ -32,6 +32,17 @@ public class FirebaseAIPlugin: NSObject, FlutterPlugin { ) let instance = FirebaseAIPlugin() registrar.addMethodCallDelegate(instance, channel: channel) + + let selector = NSSelectorFromString("registerLibrary:withVersion:") + if let firAppClass = NSClassFromString("FIRApp") as? NSObject.Type, + firAppClass.responds(to: selector) + { + _ = firAppClass.perform( + selector, + with: "flutter-fire-ai", + with: versionNumber + ) + } } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { diff --git a/packages/firebase_ai/firebase_ai/lib/src/firebase_ai.dart b/packages/firebase_ai/firebase_ai/lib/src/firebase_ai.dart index 188e46dc015d..82a37d2e7754 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/firebase_ai.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/firebase_ai.dart @@ -22,6 +22,9 @@ import 'package:meta/meta.dart'; import '../firebase_ai.dart'; import 'base_model.dart'; +import 'firebaseai_version.dart'; +import 'platform_version_stub.dart' + if (dart.library.js_interop) 'platform_version_web.dart'; const _defaultVertexAILocation = 'us-central1'; const _defaultAgentPlatformLocation = 'global'; @@ -36,7 +39,9 @@ class FirebaseAI extends FirebasePlugin { this.auth, this.useLimitedUseAppCheckTokens = false, }) : _useAgentPlatform = useAgentPlatform, - super(app.name, 'plugins.flutter.io/firebase_vertexai'); + super(app.name, 'plugins.flutter.io/firebase_vertexai') { + registerWebLibraryVersion('flutter-fire-ai', packageVersion); + } /// The [FirebaseApp] for this current [FirebaseAI] instance. FirebaseApp app; diff --git a/packages/firebase_ai/firebase_ai/lib/src/platform_version_stub.dart b/packages/firebase_ai/firebase_ai/lib/src/platform_version_stub.dart new file mode 100644 index 000000000000..4c4ca73600e9 --- /dev/null +++ b/packages/firebase_ai/firebase_ai/lib/src/platform_version_stub.dart @@ -0,0 +1,16 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Stub implementation of [registerWebLibraryVersion] on non-web platforms. +void registerWebLibraryVersion(String libraryName, String version) {} diff --git a/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart b/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart new file mode 100644 index 000000000000..fed7c782d668 --- /dev/null +++ b/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart @@ -0,0 +1,50 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; + +bool _registered = false; + +/// Registers [libraryName] and [version] with the Firebase Web JS SDK. +void registerWebLibraryVersion(String libraryName, String version) { + if (_registered) return; + try { + final firebaseCore = + globalContext.getProperty('firebase_core'.toJS) as JSObject?; + if (firebaseCore != null && + firebaseCore.hasProperty('registerVersion'.toJS).toDart) { + final sessionStorage = + globalContext.getProperty('sessionStorage'.toJS) as JSObject?; + final sessionKey = 'flutterfire-$libraryName-$version'.toJS; + final existing = + sessionStorage?.callMethod('getItem'.toJS, sessionKey); + if (existing == null) { + sessionStorage?.callMethod( + 'setItem'.toJS, + sessionKey, + version.toJS, + ); + firebaseCore.callMethod( + 'registerVersion'.toJS, + libraryName.toJS, + version.toJS, + ); + } + _registered = true; + } + } catch (_) { + // Ignore when running in unit test environments without firebase_core JS. + } +} diff --git a/packages/firebase_ai/firebase_ai/macos/firebase_ai/Sources/firebase_ai/Constants.swift b/packages/firebase_ai/firebase_ai/macos/firebase_ai/Sources/firebase_ai/Constants.swift new file mode 120000 index 000000000000..7fdbf7a4f382 --- /dev/null +++ b/packages/firebase_ai/firebase_ai/macos/firebase_ai/Sources/firebase_ai/Constants.swift @@ -0,0 +1 @@ +../../../../ios/firebase_ai/Sources/firebase_ai/Constants.swift \ No newline at end of file diff --git a/packages/firebase_core/firebase_core_web/lib/src/firebase_core_web.dart b/packages/firebase_core/firebase_core_web/lib/src/firebase_core_web.dart index ea15ec3cc17a..d006a0ccd93f 100644 --- a/packages/firebase_core/firebase_core_web/lib/src/firebase_core_web.dart +++ b/packages/firebase_core/firebase_core_web/lib/src/firebase_core_web.dart @@ -87,6 +87,9 @@ class FirebaseCoreWeb extends FirebasePlatform { static void registerLibraryVersion(String libraryName, String version) { _libraryVersions[libraryName] = version; + if (globalContext.getProperty('firebase_core'.toJS) != null) { + _registerVersionIfNeeded(libraryName, version); + } } static void _registerAllLibraryVersions() { diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart index 165b6f5d62fb..9690f0ccbf43 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart @@ -20,11 +20,14 @@ import 'package:firebase_data_connect/src/common/common_library.dart'; import 'package:firebase_data_connect/src/core/ref.dart'; import 'package:flutter/foundation.dart'; +import './network/hot_restart_guard_stub.dart' + if (dart.library.js_interop) './network/hot_restart_guard_web.dart'; import './network/rest_library.dart'; import './network/transport_library.dart'; import 'cache/cache_data_types.dart'; import 'cache/cache.dart'; +import 'dataconnect_version.dart'; /// DataConnect class class FirebaseDataConnect extends FirebasePlugin { @@ -48,6 +51,7 @@ class FirebaseDataConnect extends FirebasePlugin { connectorConfig.serviceId, ), super(app.name, 'plugins.flutter.io/firebase_data_connect') { + registerWebLibraryVersion('flutter-fire-dc', packageVersion); _queryManager = QueryManager(this); if (sdkType != null) { _sdkType = sdkType; diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_stub.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_stub.dart index 7bb61996e100..4e25f6e5e1ef 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_stub.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_stub.dart @@ -17,3 +17,5 @@ String? claimDataConnectWebSocketTransport(String key) => null; bool isCurrentDataConnectWebSocketTransport(String key, String? token) => true; void releaseDataConnectWebSocketTransport(String key, String? token) {} + +void registerWebLibraryVersion(String libraryName, String version) {} diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart index 1fdd9cc37718..373a1ef8f426 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart @@ -48,3 +48,36 @@ void releaseDataConnectWebSocketTransport(String key, String? token) { globalContext.delete(key.toJS); } } + +bool _registered = false; + +void registerWebLibraryVersion(String libraryName, String version) { + if (_registered) return; + try { + final firebaseCore = + globalContext.getProperty('firebase_core'.toJS) as JSObject?; + if (firebaseCore != null && + firebaseCore.hasProperty('registerVersion'.toJS).toDart) { + final sessionStorage = + globalContext.getProperty('sessionStorage'.toJS) as JSObject?; + final sessionKey = 'flutterfire-$libraryName-$version'.toJS; + final existing = + sessionStorage?.callMethod('getItem'.toJS, sessionKey); + if (existing == null) { + sessionStorage?.callMethod( + 'setItem'.toJS, + sessionKey, + version.toJS, + ); + firebaseCore.callMethod( + 'registerVersion'.toJS, + libraryName.toJS, + version.toJS, + ); + } + _registered = true; + } + } catch (_) { + // Ignore when running in unit test environments without firebase_core JS. + } +} diff --git a/scripts/generate_versions_spm.dart b/scripts/generate_versions_spm.dart index 2b7766dedcdb..66f05d871578 100644 --- a/scripts/generate_versions_spm.dart +++ b/scripts/generate_versions_spm.dart @@ -118,6 +118,7 @@ void updateLibraryVersionPureSwiftPlugins() { 'firebase_in_app_messaging', 'firebase_crashlytics', 'firebase_core', + 'firebase_ai', ]; for (final package in packages) { From c0076f3ccf2b706f6cc54d0d05ee03122d697197 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 23 Sep 2026 00:43:35 +0000 Subject: [PATCH 2/4] fix(firebase_ai): add firebase-common dependency to android build.gradle --- .../firebase_ai/android/build.gradle | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/firebase_ai/firebase_ai/android/build.gradle b/packages/firebase_ai/firebase_ai/android/build.gradle index a5673fbc5742..7e1c9c80e11d 100644 --- a/packages/firebase_ai/firebase_ai/android/build.gradle +++ b/packages/firebase_ai/firebase_ai/android/build.gradle @@ -21,9 +21,24 @@ buildscript { } } +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + def firebaseCoreProject = findProject(':firebase_core') if (firebaseCoreProject == null) { throw new GradleException('Could not find the firebase_core FlutterFire plugin, have you added it as a dependency in your pubspec?') +} else if (!firebaseCoreProject.properties['FirebaseSDKVersion']) { + throw new GradleException('A newer version of the firebase_core FlutterFire plugin is required, please update your firebase_core pubspec dependency.') +} + +def getRootProjectExtOrCoreProperty(name, firebaseCoreProject) { + if (!rootProject.ext.has('FlutterFire')) return firebaseCoreProject.properties[name] + if (!rootProject.ext.get('FlutterFire')[name]) return firebaseCoreProject.properties[name] + return rootProject.ext.get('FlutterFire').get(name) } android { @@ -56,6 +71,8 @@ android { dependencies { api firebaseCoreProject + implementation platform("com.google.firebase:firebase-bom:${getRootProjectExtOrCoreProperty("FirebaseSDKVersion", firebaseCoreProject)}") + implementation 'com.google.firebase:firebase-common' implementation 'androidx.annotation:annotation:1.7.0' } } From a8469631e96bdf48770928419d55c0810712d667 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 24 Sep 2026 15:26:54 +0000 Subject: [PATCH 3/4] chore: scope firebase_ai android repositories and shorten registerWebLibraryVersion --- .../firebase_ai/android/build.gradle | 8 +++--- .../lib/src/platform_version_web.dart | 26 ++++++------------- .../src/network/hot_restart_guard_web.dart | 26 ++++++------------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/packages/firebase_ai/firebase_ai/android/build.gradle b/packages/firebase_ai/firebase_ai/android/build.gradle index 7e1c9c80e11d..2905ef640cae 100644 --- a/packages/firebase_ai/firebase_ai/android/build.gradle +++ b/packages/firebase_ai/firebase_ai/android/build.gradle @@ -21,11 +21,9 @@ buildscript { } } -rootProject.allprojects { - repositories { - google() - mavenCentral() - } +repositories { + google() + mavenCentral() } def firebaseCoreProject = findProject(':firebase_core') diff --git a/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart b/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart index fed7c782d668..bd42f290be0c 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/platform_version_web.dart @@ -21,22 +21,14 @@ bool _registered = false; void registerWebLibraryVersion(String libraryName, String version) { if (_registered) return; try { - final firebaseCore = - globalContext.getProperty('firebase_core'.toJS) as JSObject?; - if (firebaseCore != null && - firebaseCore.hasProperty('registerVersion'.toJS).toDart) { - final sessionStorage = + final core = globalContext.getProperty('firebase_core'.toJS) as JSObject?; + if (core != null && core.hasProperty('registerVersion'.toJS).toDart) { + final storage = globalContext.getProperty('sessionStorage'.toJS) as JSObject?; - final sessionKey = 'flutterfire-$libraryName-$version'.toJS; - final existing = - sessionStorage?.callMethod('getItem'.toJS, sessionKey); - if (existing == null) { - sessionStorage?.callMethod( - 'setItem'.toJS, - sessionKey, - version.toJS, - ); - firebaseCore.callMethod( + final key = 'flutterfire-$libraryName-$version'.toJS; + if (storage?.callMethod('getItem'.toJS, key) == null) { + storage?.callMethod('setItem'.toJS, key, version.toJS); + core.callMethod( 'registerVersion'.toJS, libraryName.toJS, version.toJS, @@ -44,7 +36,5 @@ void registerWebLibraryVersion(String libraryName, String version) { } _registered = true; } - } catch (_) { - // Ignore when running in unit test environments without firebase_core JS. - } + } catch (_) {} } diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart index 373a1ef8f426..5066522f2342 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/hot_restart_guard_web.dart @@ -54,22 +54,14 @@ bool _registered = false; void registerWebLibraryVersion(String libraryName, String version) { if (_registered) return; try { - final firebaseCore = - globalContext.getProperty('firebase_core'.toJS) as JSObject?; - if (firebaseCore != null && - firebaseCore.hasProperty('registerVersion'.toJS).toDart) { - final sessionStorage = + final core = globalContext.getProperty('firebase_core'.toJS) as JSObject?; + if (core != null && core.hasProperty('registerVersion'.toJS).toDart) { + final storage = globalContext.getProperty('sessionStorage'.toJS) as JSObject?; - final sessionKey = 'flutterfire-$libraryName-$version'.toJS; - final existing = - sessionStorage?.callMethod('getItem'.toJS, sessionKey); - if (existing == null) { - sessionStorage?.callMethod( - 'setItem'.toJS, - sessionKey, - version.toJS, - ); - firebaseCore.callMethod( + final key = 'flutterfire-$libraryName-$version'.toJS; + if (storage?.callMethod('getItem'.toJS, key) == null) { + storage?.callMethod('setItem'.toJS, key, version.toJS); + core.callMethod( 'registerVersion'.toJS, libraryName.toJS, version.toJS, @@ -77,7 +69,5 @@ void registerWebLibraryVersion(String libraryName, String version) { } _registered = true; } - } catch (_) { - // Ignore when running in unit test environments without firebase_core JS. - } + } catch (_) {} } From 55a5d0b06f3b7431f55fb79e0491fe8a5ef75070 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 16 Oct 2026 22:35:18 +0000 Subject: [PATCH 4/4] test(core_web): add browser test for late library version registration and bump Constants.swift to 5.0.0 --- .../Sources/firebase_ai/Constants.swift | 2 +- ...ebase_core_web_late_registration_test.dart | 88 +++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/firebase_core/firebase_core_web/test/firebase_core_web_late_registration_test.dart diff --git a/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift index 54bc17e11a6c..f48f80600feb 100644 --- a/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift +++ b/packages/firebase_ai/firebase_ai/ios/firebase_ai/Sources/firebase_ai/Constants.swift @@ -13,4 +13,4 @@ // limitations under the License. /// Auto-generated file. Do not edit. -public let versionNumber = "4.0.0" +public let versionNumber = "5.0.0" diff --git a/packages/firebase_core/firebase_core_web/test/firebase_core_web_late_registration_test.dart b/packages/firebase_core/firebase_core_web/test/firebase_core_web_late_registration_test.dart new file mode 100644 index 000000000000..4b0b1fc85b1e --- /dev/null +++ b/packages/firebase_core/firebase_core_web/test/firebase_core_web_late_registration_test.dart @@ -0,0 +1,88 @@ +// Copyright 2026 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. + +@TestOn('browser') +library; + +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; + +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; +import 'package:firebase_core_web/firebase_core_web.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:web/web.dart' as web; + +String _getPlatformInfoString() { + final core = globalContext.getProperty('firebase_core'.toJS); + final jsApp = core.callMethod('getApp'.toJS); + final container = jsApp.getProperty('container'.toJS); + final provider = container.callMethod( + 'getProvider'.toJS, + 'platform-logger'.toJS, + ); + final logger = provider.callMethod('getImmediate'.toJS); + return logger.callMethod('getPlatformInfoString'.toJS).toDart; +} + +void main() { + group('FirebaseCoreWeb late library version registration', () { + setUp(() { + FirebasePlatform.instance = FirebaseCoreWeb(); + web.window.sessionStorage.clear(); + }); + + test( + 'registers library version with PlatformLogger when called after initializeApp', + () async { + const options = FirebaseOptions( + apiKey: 'fake-api-key', + appId: '1:1234567890:web:fake', + messagingSenderId: '1234567890', + projectId: 'fake-project', + authDomain: 'fake-project.firebaseapp.com', + ); + + await FirebasePlatform.instance.initializeApp(options: options); + + final initialPlatformInfo = _getPlatformInfoString(); + expect(initialPlatformInfo, contains('flutter-fire-core/')); + expect( + initialPlatformInfo, + isNot(contains('flutter-fire-late-test/1.2.3')), + ); + + FirebaseCoreWeb.registerLibraryVersion( + 'flutter-fire-late-test', + '1.2.3', + ); + + expect( + web.window.sessionStorage + .getItem('flutterfire-flutter-fire-late-test-1.2.3'), + '1.2.3', + ); + expect( + _getPlatformInfoString(), + contains('flutter-fire-late-test/1.2.3'), + ); + + // Clearing sessionStorage allows re-registering a subsequent version. + web.window.sessionStorage.clear(); + FirebaseCoreWeb.registerLibraryVersion( + 'flutter-fire-late-test-2', + '2.0.0', + ); + expect( + web.window.sessionStorage + .getItem('flutterfire-flutter-fire-late-test-2-2.0.0'), + '2.0.0', + ); + expect( + _getPlatformInfoString(), + contains('flutter-fire-late-test-2/2.0.0'), + ); + }, + ); + }); +}