Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

Welcome to the **Maps Agentic UI Toolkit Samples**! 🎉

This repository (`a2ui-samples`) contains reference samples for the Maps Agentic UI Toolkit. It provides a fully working, interactive sample application implementing the Agent-to-User Interface (A2UI) standard, allowing AI agents to present rich, dynamic map interfaces directly in your web browser.
This repository (`a2ui-samples`) contains reference samples for the Maps Agentic UI Toolkit. It provides fully working, interactive sample applications implementing the Agent-to-User Interface (A2UI) standard, allowing AI agents to present rich, dynamic map interfaces directly across Web, Android, and iOS platforms.

This project is intended for demonstration purposes to help you get up and running quickly!

Expand All @@ -24,13 +24,20 @@ Here is an overview of how the directory structure looks when set up correctly:
parent-folder/
├── a2ui/ <-- SIBLING REPOSITORY (Core Toolkit)
│ ├── agent/python-agent/ <-- Core Python agent libraries (maui-a2ui-python)
│ └── client/web/ <-- Core web UI component library (@googlemaps/a2ui)
│ └── client/ <-- Core client UI libraries
│ ├── web/ <-- Core Web UI component library (@googlemaps/a2ui)
│ ├── android/ <-- Android View component library (GoogleMapsA2UI)
│ └── ios/ <-- iOS SwiftUI component library (GoogleMapsA2UI)
└── a2ui-samples/ <-- THIS REPOSITORY (Quickstart & Demos)
├── agent/python/ <-- Sample backend Python agent server
└── client/web/react/ <-- Sample frontend React web application
└── client/ <-- Sample client applications
├── web/react/ <-- Sample frontend React web application
├── android/ <-- Sample Android application
└── ios/ <-- Sample iOS application
```


Understanding this layout ensures you will feel entirely comfortable linking the backend and frontend components in the quickstart steps below!

## 🚀 Quickstart Guide
Expand Down Expand Up @@ -77,6 +84,10 @@ For more information about the environment variables, see the **Google API Key C
`npm` is the standard package manager for JavaScript and TypeScript web applications, used to download frontend libraries and run development servers.
* **Installation:** Download and install Node.js (which includes `npm`) from [https://nodejs.org/](https://nodejs.org/).

#### 4. Mobile Development Tools (Optional for mobile samples)
* **Android**: [Android Studio](https://developer.android.com/studio) to build and run the native Android sample app.
* **iOS**: macOS with [Xcode](https://developer.apple.com/xcode/) to build and run the native iOS sample app.

---

### Step 1: Run the Backend (Python Agent)
Expand Down Expand Up @@ -106,7 +117,11 @@ The backend server is powered by Python and runs our sample agent.

---

### Step 2: Run the Frontend (React Client)
### Step 2: Run a Client Application

Once your backend agent is up and running, you can connect to it using any of our sample client platforms.

#### Option A: Web Client (React)

The frontend is a React web application that communicates with the backend agent and renders the interactive UI.

Expand All @@ -119,6 +134,25 @@ The frontend is a React web application that communicates with the backend agent
2. **See the demo working live!** 🌟
Open [http://localhost:5173](http://localhost:5173) in your web browser to interact with your fully functioning Agentic UI demo!


#### Option B: Android Client

The Android sample is a native app utilizing Android Views and [GoogleMapsA2UI(Android)](https://github.com/googlemaps/a2ui/tree/main/client/android) to render agent-driven UI.

1. **Open Project**: Open the `client/android` directory in Android Studio.
2. **Run**: Build and run the application. It will automatically connect to your running Python agent at `http://10.0.2.2:10002` (for an emulator) or `http://127.0.0.1:10002` (for a physical device).

For more server configration and other detailed setup, refer to the [Android Sample README](client/android/README.md).

#### Option C: iOS Client

The iOS sample is a native app utilizing SwiftUI and the [GoogleMapsA2UI(iOS)](https://github.com/googlemaps/a2ui/tree/main/client/ios) to render agent-driven UI.

1. **Setup**: Open the `.xcodeproj` file in the `client/ios` directory in Xcode (use a `.xcworkspace` file instead if your project uses one).
2. **Run**: Build and run the app in the simulator. It will automatically connect to your running Python agent at `http://localhost:10002`.

For more server configration and other detailed setup, refer to the [iOS Sample README](client/ios/README.md).

## Google API Keys

### Google Maps API Key
Expand Down
14 changes: 14 additions & 0 deletions client/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Built artifacts
bin/
gen/
out/
build/
app/build/

# Gradle
.gradle/
.kotlin/
local.properties

# Android Studio / IntelliJ
.idea/
81 changes: 81 additions & 0 deletions client/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# A2UI Android Sample App

## Overview
This directory contains the Android sample application for the Google Maps Agentic UI (A2UI) Toolkit. It demonstrates how to integrate the underlying `GoogleMapsA2UI` Library to render generative AI responses containing interactive map elements and conversational text natively within an Android WebView.

**Compatibility:** This sample app is designed for **A2UI v0.9**. It is not compatible with earlier versions (e.g., v0.8).

## Instructions

### 1. Build and Publish the A2UI SDK Locally

Before building the sample app, you must build the underlying **GoogleMapsA2UI** library (the core A2UI SDK) and publish it to your local Maven repository.

For instructions on how to build and publish the library, please refer to the [A2UI Android README](https://github.com/googlemaps/a2ui/tree/main/client/android/README.md).

### 2. Set API Keys and Gateway URL

Add your API keys and server connection settings to the `local.properties` file in the root `android` directory (e.g., `ai-kit/a2ui-samples/client/android/local.properties`):

```properties
sdk.dir=/Users/YOUR_USERNAME/Library/Android/sdk
MAPS_API_KEY=your_actual_google_maps_api_key_here
GATEWAY_API_KEY=your_actual_gateway_api_key_here
GATEWAY_URL=your_actual_gateway_url_here
```

The build system uses the `secrets-gradle-plugin` to securely inject these values into the app at runtime.

* **`MAPS_API_KEY`**: Obtain a Google Maps API Key from the Google Cloud Console.
* **`GATEWAY_URL`** and **`GATEWAY_API_KEY`**:
* **For Remote Server:** If you have deployed a Remote Server to Google Cloud, set `GATEWAY_URL` to your Cloud Run or API Gateway endpoint. Optionally, set `GATEWAY_API_KEY` if your server uses API key-based authentication.
* **For Local Server:** Set `GATEWAY_URL` to `http://127.0.0.1:10002` (physical device) or `http://10.0.2.2:10002` (emulator).

*(Note: Before building this sample app, ensure you have built and published the `GoogleMapsA2UI` Android Library locally. See [a2ui/client/android/README.md](https://github.com/googlemaps/a2ui/tree/main/client/android/README.md) for instructions).*

### 3. Server Configuration & Connectivity Options

In `app/src/main/java/com/example/maui/MainActivity.kt`, verify the flags match your environment:

#### Server Type (`activeServer`)
* `ServerType.DEMO`: Connects to the `GATEWAY_URL` specified in `local.properties`. Use this for your Remote Server or the local Demo Server.
* `ServerType.VANILLA`: Connects to a standalone Python agent running locally (e.g., `python -m my_agent --port 8000`).

#### Device Type (`deviceType`)
* `DeviceType.PHYSICAL`: Use when testing on real Android devices. *(Note: If using a local Demo Server on a physical device, run `adb reverse tcp:10002 tcp:10002`)*
* `DeviceType.EMULATOR`: Use when testing on emulators.

### 4. Build and Run the App

1. Navigate to the Android sample app directory:
```bash
cd ~/ai-kit/a2ui-samples/client/android
```
2. Build and install the app (Debug version):
```bash
./gradlew :app:installDebug
```
*(For release builds, use `./gradlew :app:installRelease`)*
3. Launch the app on your emulator or connected device:
```bash
adb shell am start -n com.example.maui/.MainActivity
```

### 5. Example Prompts & Canned Responses

To facilitate rapid demonstration and UI testing, the sample app includes a dropdown list of frequently used example prompts.

**Important Behavior Note:**
* **Example Prompts:** Selecting an example prompt from the dropdown menu will load a **local, pre-stored JSON response** (found in `assets/canned_responses`) instead of making a live call to the backend server. This is intended for consistent UI testing and fast demonstrations without LLM latency.

## Troubleshooting

### Debug Keystore Missing
If you receive an error: `Keystore file ... debug.keystore not found`, this means your local Android environment hasn’t generated a default debug key yet.

**Solution:**
* **Option A (Recommended):** Open the project in **Android Studio** and let it perform a Gradle sync. This will automatically generate the keystore.
* **Option B (Manual):** Run the following command to generate one:
```bash
keytool -genkey -v -keystore ~/.android/debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Android Debug,O=Android,C=US"
```
89 changes: 89 additions & 0 deletions client/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// Copyright 2026 Google Inc.
//
// 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.
//

plugins {
id 'com.android.application'
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}

android {
namespace 'com.example.maui'
compileSdk 34

defaultConfig {
applicationId "com.example.maui"
minSdk 26
targetSdk 34
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildFeatures {
buildConfig true
}

signingConfigs {
debug {
// Use the default debug keystore
storeFile file(System.getProperty("user.home") + "/.android/debug.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}

buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
signingConfig signingConfigs.debug
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
// Configure Java toolchain
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
}

kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}

dependencies {
implementation 'androidx.tracing:tracing-ktx:1.2.0'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'com.squareup.okhttp3:okhttp:5.3.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.google.android.libraries.mapsplatform.a2ui:GoogleMapsA2UI:0.1.0'
}
41 changes: 41 additions & 0 deletions client/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Google Inc.

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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Maui">
<profileable android:shell="true"/>
<activity
android:name=".MainActivity"
android:exported="true"
android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Show me 5 coffee shops near South Lake Union in Seattle": "prompt_1.json",
"Is the Edgewater Hotel in Seattle a good hotel?": "prompt_2.json",
"How long will it take to commute to Google Kirkland office from downtown Redmond during my morning rush hour commute?": "prompt_3.json",
"Show me 5 lunch restaurants with Salads in South Lake Union. Give me directions to the 2nd one (starting from the Google South Lake Union WLK building)": "prompt_4.json",
"Give me a 3 day itinerary for a family of 3 traveling to London": "prompt_5.json"
}
Loading
Loading