From b21e8256655d8152567736ff79fa4690a74399ae Mon Sep 17 00:00:00 2001 From: "Shams Zakhour (ignore Sfshaza)" Date: Wed, 24 Dec 2025 10:44:24 -0500 Subject: [PATCH 1/7] Fix(docs): Add Groovy syntax tabs to Android deployment guide (fixes #12793) --- src/content/deployment/android.md | 177 +++++++++++++++++++++--------- 1 file changed, 128 insertions(+), 49 deletions(-) diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index 98cf71a720a..33386bf6d7d 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -75,13 +75,30 @@ For example: 1. Add the dependency on Android's Material in `/android/app/build.gradle.kts`: - ```groovy - dependencies { - // ... - implementation("com.google.android.material:material:") - // ... - } - ``` + + + +```groovy +dependencies { + // ... + implementation("com.google.android.material:material:") + // ... +} +``` + + + + +```groovy +dependencies { + // ... + implementation 'com.google.android.material:material:' + // ... +} +``` + + + To find out the latest version, visit [Google Maven][maven-material]. @@ -207,52 +224,114 @@ To configure Gradle, edit the `/android/app/build.gradle.kts` file. 1. Set the `keystoreProperties` object to load the `key.properties` file. - ```kotlin diff title="[project]/android/app/build.gradle.kts" - + import java.util.Properties - + import java.io.FileInputStream - + - plugins { - ... - } - + - + val keystoreProperties = Properties() - + val keystorePropertiesFile = rootProject.file("key.properties") - + if (keystorePropertiesFile.exists()) { - + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) - + } - + - android { - ... - } - ``` + + + +```kotlin diff title="[project]/android/app/build.gradle.kts" ++ import java.util.Properties ++ import java.io.FileInputStream ++ + plugins { + ... + } ++ ++ val keystoreProperties = Properties() ++ val keystorePropertiesFile = rootProject.file("key.properties") ++ if (keystorePropertiesFile.exists()) { ++ keystoreProperties.load(FileInputStream(keystorePropertiesFile)) ++ } ++ + android { + ... + } +``` + + + + +```groovy diff title="[project]/android/app/build.gradle" ++ import java.util.Properties ++ import java.io.FileInputStream ++ + plugins { + ... + } ++ ++ def keystoreProperties = new Properties() ++ def keystorePropertiesFile = rootProject.file('key.properties') ++ if (keystorePropertiesFile.exists()) { ++ keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) ++ } ++ + android { + ... + } +``` + + + 1. Add the signing configuration before the `buildTypes` property block inside the `android` property block. - ```kotlin diff title="[project]/android/app/build.gradle.kts" - android { - // ... - - + signingConfigs { - + create("release") { - + keyAlias = keystoreProperties["keyAlias"] as String - + keyPassword = keystoreProperties["keyPassword"] as String - + storeFile = keystoreProperties["storeFile"]?.let { file(it) } - + storePassword = keystoreProperties["storePassword"] as String - + } - + } - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, - // so `flutter run --release` works. - - signingConfig = signingConfigs.getByName("debug") - + signingConfig = signingConfigs.getByName("release") - } - } - ... - } - ``` + + + +```kotlin diff title="[project]/android/app/build.gradle.kts" + android { + // ... + ++ signingConfigs { ++ create("release") { ++ keyAlias = keystoreProperties["keyAlias"] as String ++ keyPassword = keystoreProperties["keyPassword"] as String ++ storeFile = keystoreProperties["storeFile"]?.let { file(it) } ++ storePassword = keystoreProperties["storePassword"] as String ++ } ++ } + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, + // so `flutter run --release` works. +- signingConfig = signingConfigs.getByName("debug") ++ signingConfig = signingConfigs.getByName("release") + } + } + ... + } +``` + + + + +```groovy diff title="[project]/android/app/build.gradle" + android { + // ... + ++ signingConfigs { ++ release { ++ keyAlias = keystoreProperties['keyAlias'] ++ keyPassword = keystoreProperties['keyPassword'] ++ storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null ++ storePassword = keystoreProperties['storePassword'] ++ } ++ } + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, + // so `flutter run --release` works. +- signingConfig = signingConfigs.debug ++ signingConfig = signingConfigs.release + } + } + ... + } +``` + + + Flutter now signs all release builds. From ab0758efdfcec814a96c63ec120aa115f4b03d77 Mon Sep 17 00:00:00 2001 From: "Shams Zakhour (ignore Sfshaza)" Date: Mon, 5 Jan 2026 10:24:05 -0800 Subject: [PATCH 2/7] docs: update GenUI docs for 0.6.0 --- src/content/ai/genui/components.md | 15 ++++++--- src/content/ai/genui/get-started.md | 47 +++++++++++++++-------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/content/ai/genui/components.md b/src/content/ai/genui/components.md index 66741c38f19..ceacd533192 100644 --- a/src/content/ai/genui/components.md +++ b/src/content/ai/genui/components.md @@ -23,13 +23,15 @@ The [`genui`][] package is built around the following main components: `GenUiConversation` : The primary facade and entry point for the package. - It includes the `GenUiManager` and `ContentGenerator` classes, + It includes the `A2uiMessageProcessor` and `ContentGenerator` classes, manages the conversation history, and orchestrates the entire generative UI process. `Catalog` : A collection of `CatalogItem` objects that defines the set of widgets that the AI is allowed to use. + The `A2uiMessageProcessor` supports multiple catalogs, + allowing you to organize your widgets into logical groups. Each `CatalogItem` specifies a widget's name (for the AI to reference), a data schema for its properties, and a builder function to render the Flutter widget. @@ -50,6 +52,11 @@ The [`genui`][] package is built around the following main components: instructing it to perform actions like `beginRendering`, `surfaceUpdate`, `dataModelUpdate`, or `deleteSurface`. +`A2uiMessageProcessor` +: Handles the processing of `A2uiMessage`s, + manages the `DataModel`, and maintains the state of UI surfaces. + + ## How it works The `GenUiConversation` manages the interaction cycle: @@ -77,12 +84,12 @@ The `GenUiConversation` manages the interaction cycle: 5. **UI state update** `GenUiConversation` listens to these streams. - `A2uiMessages` are passed to `GenUiManager.handleMessage()`, + `A2uiMessages` are passed to `A2uiMessageProcessor.handleMessage()`, which updates the UI state and `DataModel`. 6. **UI rendering** - The `GenUiManager` broadcasts an update, + The `A2uiMessageProcessor` broadcasts an update, and any `GenUiSurface` widgets listening for that surface ID will rebuild. Widgets are bound to the `DataModel`, so they update automatically when their data changes. @@ -98,7 +105,7 @@ The `GenUiConversation` manages the interaction cycle: (for example, by typing in a text field). This interaction directly updates the `DataModel`. If the interaction is an action (like a button click), the `GenUiSurface` captures the event and forwards it to the - `GenUiConversation`'s `GenUiManager`, which automatically creates + `GenUiConversation`'s `A2uiMessageProcessor`, which automatically creates a new `UserMessage` containing the current state of the data model and restarts the cycle. diff --git a/src/content/ai/genui/get-started.md b/src/content/ai/genui/get-started.md index 69690945614..adbc0493e94 100644 --- a/src/content/ai/genui/get-started.md +++ b/src/content/ai/genui/get-started.md @@ -88,6 +88,8 @@ consider using Firebase AI Logic instead. // ... ]); + final messageProcessor = A2uiMessageProcessor(catalogs: [catalog]); + final contentGenerator = GoogleGenerativeAiContentGenerator( catalog: catalog, systemInstruction: 'You are a helpful assistant.', @@ -97,6 +99,7 @@ consider using Firebase AI Logic instead. final conversation = GenUiConversation( contentGenerator: contentGenerator, + a2uiMessageProcessor: messageProcessor, ); ``` @@ -172,7 +175,7 @@ The main components in this package include: * `A2uiContentGenerator`: Implements the `ContentGenerator` that manages the connection to the A2A server and processes incoming A2UI messages, - updating the `GenUiManager`. + updating the `A2uiMessageProcessor`. * `A2uiAgentConnector`: Handles the low-level web socket communication with the A2A server, including sending messages and parsing stream events. @@ -189,8 +192,8 @@ Follow these instructions: $ dart pub add genui genui_a2ui a2a ``` - 2. Initialize `GenUIManager`: - Set up `GenUiManager` with your widget `Catalog`. + 2. Initialize `A2uiMessageProcessor`: + Set up `A2uiMessageProcessor` with your widget `Catalog`s. 3. Create `A2uiContentGenerator`: Instantiate `A2uiContentGenerator`, providing the A2A server URI. @@ -252,8 +255,8 @@ Follow these instructions: class _ChatScreenState extends State { final TextEditingController _textController = TextEditingController(); - final GenUiManager _genUiManager = - GenUiManager(catalog: CoreCatalogItems.asCatalog()); + final A2uiMessageProcessor _a2uiMessageProcessor = + A2uiMessageProcessor(catalogs: [CoreCatalogItems.asCatalog()]); late final A2uiContentGenerator _contentGenerator; late final GenUiConversation _uiAgent; final List _messages = []; @@ -267,7 +270,7 @@ Follow these instructions: ); _uiAgent = GenUiConversation( contentGenerator: _contentGenerator, - genUiManager: _genUiManager, + a2uiMessageProcessor: _a2uiMessageProcessor, ); // Listen for text responses from the agent. @@ -288,7 +291,7 @@ Follow these instructions: void dispose() { _textController.dispose(); _uiAgent.dispose(); - _genUiManager.dispose(); + _a2uiMessageProcessor.dispose(); _contentGenerator.dispose(); super.dispose(); } @@ -329,7 +332,7 @@ Follow these instructions: SizedBox( height: 300, child: GenUiSurface( - host: _genUiManager, + host: _a2uiMessageProcessor, surfaceId: 'main_surface', ), ), @@ -439,48 +442,48 @@ to enable outbound network requests: Next, use the following instructions to connect your app to your chosen agent provider. - 1. Create a `GenUiManager`, and provide it with the catalog + 1. Create a `A2uiMessageProcessor`, and provide it with the catalogs of widgets that you want to make available to the agent. 2. Create a `ContentGenerator`, and provide it with a system instruction and a set of tools (functions you want the agent to be able to invoke). - You should always include those provided by `GenUiManager`, + You should always include those provided by `A2uiMessageProcessor`, but feel free to include others. 3. Create a `GenUiConversation` using the instances of - `ContentGenerator` and `GenUiManager`. Your app will + `ContentGenerator` and `A2uiMessageProcessor`. Your app will primarily interact with this object to get things done. For example: ```dart class _MyHomePageState extends State { - late final GenUiManager _genUiManager; + late final A2uiMessageProcessor _a2uiMessageProcessor; late final GenUiConversation _genUiConversation; @override void initState() { super.initState(); - // Create a GenUiManager with a widget catalog. + // Create a A2uiMessageProcessor with a widget catalog. // The CoreCatalogItems contain basic widgets for text, markdown, and images. - _genUiManager = GenUiManager(catalog: CoreCatalogItems.asCatalog()); + _a2uiMessageProcessor = A2uiMessageProcessor(catalogs: [CoreCatalogItems.asCatalog()]); // Create a ContentGenerator to communicate with the LLM. - // Provide system instructions and the tools from the GenUiManager. + // Provide system instructions and the tools from the A2uiMessageProcessor. final contentGenerator = FirebaseAiContentGenerator( systemInstruction: ''' You are an expert in creating funny riddles. Every time I give you a word, you should generate UI that displays one new riddle related to that word. Each riddle should have both a question and an answer. ''', - tools: _genUiManager.getTools(), + additionalTools: _a2uiMessageProcessor.getTools(), ); // Create the GenUiConversation to orchestrate everything. _genUiConversation = GenUiConversation( - genUiManager: _genUiManager, + a2uiMessageProcessor: _a2uiMessageProcessor, contentGenerator: contentGenerator, onSurfaceAdded: _onSurfaceAdded, // Added in the next step. onSurfaceDeleted: _onSurfaceDeleted, // Added in the next step. @@ -674,11 +677,11 @@ To add your own widgets, use the following instructions. 4. Add the `CatalogItem` to the catalog - Include your catalog items when instantiating `GenUiManager`. + Include your catalog items when instantiating `A2uiMessageProcessor`. ```dart - _genUiManager = GenUiManager( - catalog: CoreCatalogItems.asCatalog().copyWith([riddleCard]), + _a2uiMessageProcessor = A2uiMessageProcessor( + catalogs: [CoreCatalogItems.asCatalog().copyWith([riddleCard])], ); ``` @@ -695,7 +698,7 @@ To add your own widgets, use the following instructions. generate a RiddleCard that displays one new riddle related to that word. Each riddle should have both a question and an answer. ''', - tools: _genUiManager.getTools(), + additionalTools: _a2uiMessageProcessor.getTools(), ); ``` @@ -788,7 +791,7 @@ final contentGenerator = FirebaseAiContentGenerator( displays one new riddle related to that word. Each riddle should have both a question and an answer. ''', - tools: _genUiManager.getTools(), + additionalTools: _a2uiMessageProcessor.getTools(), ); ``` From 3b6a96d9ce73661b6964a0c4b4bd51f8c4f6f970 Mon Sep 17 00:00:00 2001 From: Shams Zakhour <44418985+sfshaza2@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:35:15 -0800 Subject: [PATCH 3/7] Update src/content/deployment/android.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/content/deployment/android.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index 33386bf6d7d..e8227b102a8 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -231,9 +231,9 @@ To configure Gradle, edit the `/android/app/build.gradle.kts` file. + import java.util.Properties + import java.io.FileInputStream + - plugins { - ... - } +plugins { + ... +} + + val keystoreProperties = Properties() + val keystorePropertiesFile = rootProject.file("key.properties") From 9d387ac3f7cce46e4e45721555caa4bc4a907f5d Mon Sep 17 00:00:00 2001 From: Shams Zakhour <44418985+sfshaza2@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:35:22 -0800 Subject: [PATCH 4/7] Update src/content/deployment/android.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/content/deployment/android.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index e8227b102a8..643f923ccee 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -253,9 +253,9 @@ plugins { + import java.util.Properties + import java.io.FileInputStream + - plugins { - ... - } +plugins { + ... +} + + def keystoreProperties = new Properties() + def keystorePropertiesFile = rootProject.file('key.properties') From 45b4efa0f4c9bf48105cfc6014379c79fbe96662 Mon Sep 17 00:00:00 2001 From: Shams Zakhour <44418985+sfshaza2@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:35:47 -0800 Subject: [PATCH 5/7] Update src/content/deployment/android.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/content/deployment/android.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index 643f923ccee..4bf4ef8abc5 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -241,9 +241,9 @@ plugins { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) + } + - android { - ... - } +android { + ... +} ``` From 2e356bb01f794f0dc9c43bae17e4095b998f1923 Mon Sep 17 00:00:00 2001 From: Shams Zakhour <44418985+sfshaza2@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:36:00 -0800 Subject: [PATCH 6/7] Update src/content/deployment/android.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/content/deployment/android.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/deployment/android.md b/src/content/deployment/android.md index 4bf4ef8abc5..d384f199fc5 100644 --- a/src/content/deployment/android.md +++ b/src/content/deployment/android.md @@ -263,9 +263,9 @@ plugins { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + } + - android { - ... - } +android { + ... +} ``` From 5fb4ecb6d0cdbf7e690278292a10de25986a2e0e Mon Sep 17 00:00:00 2001 From: "Shams Zakhour (ignore Sfshaza)" Date: Mon, 5 Jan 2026 10:37:13 -0800 Subject: [PATCH 7/7] Removing extra newline --- src/content/ai/genui/components.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/ai/genui/components.md b/src/content/ai/genui/components.md index ceacd533192..50557a83754 100644 --- a/src/content/ai/genui/components.md +++ b/src/content/ai/genui/components.md @@ -56,7 +56,6 @@ The [`genui`][] package is built around the following main components: : Handles the processing of `A2uiMessage`s, manages the `DataModel`, and maintains the state of UI surfaces. - ## How it works The `GenUiConversation` manages the interaction cycle: