This is an example iOS application demonstrating the Maps Agentic UI Toolkit. It leverages the GoogleMapsA2UI module to parse backend A2A payloads and render A2UI messages natively.
This application relies on the core GoogleMapsA2UI module. To set up this dependency for the sample app, add it as a local Swift Package:
- Open the sample project in Xcode.
- Follow the [How to Integrate] steps from the
GoogleMapsA2UIREADME.- Note: When prompted for the package location, use the local path to the
a2ui/client/ios/GoogleMapsA2UIfolder.
- Note: When prompted for the package location, use the local path to the
ChatApp.swift: The main application entry point.ChatView.swift: The main chat UI, displaying message history, the input bar, and toggles to switch between different agent modes (e.g., Vertex AI Maps Grounding vs. MCP Lite vs. Template).ChatViewModel.swift: Handles all networking with the backend protocols, maintains state, and routes A2A responses to theGoogleMapsA2UIlibrary parser.Models.swift: Basic data structures for chat messages and agent mode configurations.GoogleMapsA2UI: A Swift package dependency pulled in from thea2uimodule. It provides theA2UIViewSwiftUI component to render the dynamic maps components and parses the A2A payload into a list ofParsedA2AEventobjects. (See the Library Dependency section above for integration details).
Before running the application, you must configure your API keys and endpoints in ChatViewModel.swift.
- Open
ChatViewModel.swift. - Locate the following variables at the top of the file and replace them with your actual values:
private let googleMapsApiKey = "YOUR_API_KEY" // --- CONFIGURATION --- private let activeServer: ServerType = .remote private let remoteEndpoint = "REQUIRED_REMOTE_ENDPOINT" private let apiKey = "REQUIRED_REMOTE_API_KEY" // ---------------------
- You can create a Google Maps API Key in the Google Cloud Console.
The app is configured to connect to two types of servers by setting the activeServer property in ChatViewModel.swift:
.demo(Local Demo Server): The default A2UI server provided in this repository, usually running onhttp://localhost:10002..remote(Remote Gateway): Connects to the cloud-hosted agent gateway using your providedremoteEndpointandapiKey.
Open the project in Xcode (or use your preferred build system) and run the app.
Connecting to a Local Server (Simulator vs. Physical Device):
If your activeServer is set to .demo (This means the server is running on your Mac):
- Simulator: You can leave the URL in
baseUrlashttp://localhost:10002(or127.0.0.1). - Physical Device:
localhostresolves to the iPhone itself, not your Mac. You must find your Mac's Wi-Fi IP address (e.g., runipconfig getifaddr en0). Then, inChatViewModel.swift, update the string returned bybaseUrlto use this IP (e.g., change"http://localhost:10002"to"http://192.168.68.93:10002"). - Binding to
0.0.0.0: By default, your Mac's server will block connections from outside devices. To allow your physical iPhone to connect, you must start your python server with the--host 0.0.0.0flag (e.g.,python server.py --host 0.0.0.0 --port 10002). This tells the server to listen to the Wi-Fi network instead of justlocalhost.
(Note: If you are using .remote, you do not need to change IPs or host bindings since the gateway is cloud-hosted).
Once the app is running:
- Toggle Streaming vs. Non-Streaming (
useStreaming): Streaming (message/stream) is enabled by default (ChatService.defaultUseStreaming = trueinChatService.swift). You can switch between incremental SSE streaming (message/stream) and single-response non-streaming (message/send) at runtime using the Streaming toggle above the agent selector inChatView.swift, or change the defaultdefaultUseStreamingboolean inChatService.swift. - Select agent Mode: Use the radio buttons above the chat bar to toggle between Grounding Lite (MCP), Grounding with Google Maps (Vertex) and Template.
- Use Canned Prompts: Tap the Flask or List icons next to the text input for a menu of pre-written test scenarios.
- Send Custom Prompts: Type a query into the text box (e.g., "Show me 3 Chinese restaurants in Seattle") and hit send.
- Interact with Maps: Wait for the A2UI components to load. You can interact with the rendered maps and place cards (like tapping
Get Directions) to trigger native Swift callbacks.
You can execute the UI tests directly from Xcode:
- Open the project in Xcode.
- Open
client/ios/A2UI-ExampleUITests/A2UI_ExampleUITests.swift. - Run the tests by pressing
Cmd + Uor clicking the play button next to the test class (A2UIExampleUITests) or individual test methods.
Note: The UI tests rely on a backend server to process the test prompts, and agent responses can sometimes take more than 30 seconds. If your tests are failing due to a timeout, you can increase the timeout value on line 96 of
A2UI_ExampleUITests.swift:waitForExpectations(timeout: 30, handler: nil) // Increase this value if the server is slow
The A2UIView component from the GoogleMapsA2UI library is a native wrapper around a WKWebView. It does not draw the actual map cards using Swift. Instead, it loads a local index.html bundle that compiles the core A2UI web components together with the iOS platform-specific shell logic at a2ui/client/ios/web_build/.
What can you customize?
By modifying the web components directly within a2ui/client/ios/web_build/, you can alter the A2UIView's visual specifications. For example:
- Styling & Layout: Change background colors, sizes, fonts, or padding of the rendering surface.
- Component Behavior: Inject CSS transforms or resizing logic (e.g., our existing hack that forces
<gmp-place-details-compact>to render image thumbnails even inside narrow iOS chat bubbles). - Native Bridge Integration: Add or modify JavaScript callbacks that communicate with the native Swift layer.
Why do you need to rebuild index.html?
Because the iOS GoogleMapsA2UI library relies entirely on the local index.html bundle to define its visual rendering spec, any changes you make in the web codebase must be re-compiled into a new, minified bundle and copied into the native iOS wrapper project.
To update the iOS app with your web customizations:
- Navigate to the iOS web build directory:
cd client/ios/web_build - Install the dependencies and run the build script:
npm install npm run build
- This script triggers Vite to compile a newly minified payload and automatically copies it into
GoogleMapsA2UI/Sources/GoogleMapsA2UI/Resources/index.html. - Re-build the iOS sample app from Xcode to view your updated components.