u2_flutter 🚀
u2_flutter is a lightweight Python plugin for uiautomator2 designed to inspect, locate, and interact with Flutter widgets in Android applications.
It connects directly to the Dart VM Service over a WebSocket connection using ADB port forwarding, sending JSON-RPC commands directly to Flutter's Driver extension (ext.flutter.driver).
✨ Key Features
- Direct WebSocket Connection: Bypasses heavy HTTP/Node.js middleware (e.g., Appium) by communicating directly with the Dart VM Service over WebSocket.
- Fluent Element API: Easily locate widgets by Key, Type, Text, or Value and perform actions like
tap(),enter_text(), andtext. - Automatic Bridge Lifecycle: Managed
@with_flutterdecorator handles dynamic logcat scanning, port forwarding, and connection lifecycle automatically. - Fast Diagnostics Tree Inspection: Supports fetching and caching the Flutter widget diagnostics tree (
get_diagnostics_tree()) for fast offline or precondition checks (<1ms). - Hybrid App Compatibility: Works seamlessly alongside standard
uiautomator2native Android interactions (self.dfor native,self.flutterfor Flutter).
🛠️ How it Works
graph TD
A[Python Test Script / uiautomator2] -->|1. @with_flutter| B(FlutterBridge)
B -->|2. scans logcat| C{Find VM Port & Auth Token}
C -->|3. adb forward| D[Local Port tcp:8181]
D -->|4. WebSocket Handshake| E[Dart VM Service WebSocket]
A -->|5. self.flutter.find_by_key| F(FlutterDriver)
F -->|6. JSON-RPC ext.flutter.driver| E
E -->|7. Executes action| G[Running Flutter Application]
- Service Registration: The Flutter app is built in debug mode with
enableFlutterDriverExtension()insidelib/main.dart. - Dynamic Handshake:
u2_flutterscanslogcatfor the active Dart VM Service port and security authentication token. - Port Forwarding: Automatically sets up
adb forward tcp:8181 tcp:<vm_port>. - WebSocket Communication: Establishes a WebSocket connection (
ws://127.0.0.1:8181/<token>/ws) to execute driver commands directly on the running isolate.
📦 Installation
pip install u2-flutter
🚀 Quick Start (Basic Usage with uiautomator2)
1. Enable Flutter Driver Extension in your App
Inside your Flutter app's lib/main.dart:
import 'package:flutter/material.dart';
import 'package:flutter_driver/driver_extension.dart';
void main() {
enableFlutterDriverExtension(); // Registers ext.flutter.driver
runApp(const MyApp());
}
Add flutter_driver to pubspec.yaml:
dev_dependencies:
flutter_driver:
sdk: flutter
Build the debug APK:
flutter build apk --debug
2. Write Python Automation Script
import unittest
import uiautomator2 as u2
from u2_flutter import with_flutter
class FlutterAppTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.d = u2.connect() # Connect uiautomator2 device instance
@with_flutter
def test_login_flow(self):
# 1. Native uiautomator2 interaction
self.d(text="OPEN FLUTTER").click()
# 2. u2_flutter widget interactions
self.flutter.find_by_key("username_input").enter_text("testuser")
self.flutter.find_by_key("submit_btn").tap()
# 3. Read updated widget state
greeting = self.flutter.find_by_key("greeting_text").text
self.assertEqual(greeting, "Hello, testuser!")
if __name__ == "__main__":
unittest.main()
🔌 Using with Kea2 Fuzzing Framework
u2_flutter also serves as the official Flutter interaction plugin for Kea2 (property-based fuzzing testing for Android).
Example Property Test
import unittest
import logging
from kea2 import precondition, prob
from u2_flutter import with_flutter
logger = logging.getLogger(__name__)
class TestHybridApp(unittest.TestCase):
@with_flutter
@prob(1.0)
@precondition(lambda self: self.d(text="OPEN FLUTTER").exists)
def test_native_to_flutter_flow(self):
# Native click
self.d(text="OPEN FLUTTER").click()
# Flutter widget checks & actions
assert self.flutter.find_by_key("HomeListView").exists
before_text = self.flutter.find_by_key("statusText").text
before_count = int(before_text.split(":")[1].strip())
self.flutter.find_by_key("actionButton").tap()
after_text = self.flutter.find_by_key("statusText").text
after_count = int(after_text.split(":")[1].strip())
assert after_count == before_count + 1
⚡ Performance & Comparison
Compared to Appium Flutter Driver, u2_flutter follows the lean uiautomator2 design philosophy:
| Metric | Appium Flutter Driver | u2_flutter |
|---|---|---|
| Transport | HTTP → WebDriver → Node.js → ADB → Dart VM | Direct WebSocket over ADB Forward |
| Network Hops | 4+ hops | 1 hop (Local WebSocket) |
| Middleware | Appium Server (Node.js) required | None (pure Python) |
| Widget Query Latency | >150ms per request | <1ms (cached diagnostics tree) |
| Setup Complexity | High (npm, appium server, drivers) | Minimal (pip install u2-flutter) |
🤝 Acknowledgments
- openatx/uiautomator2 — The Android UI automation framework.
- u2_webview — The plugin pattern architecture that inspired this project.
📜 License
MIT License © Muhammad Assad Ullah
Metadata
Release files for u2-flutter 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| u2_flutter-0.1.0.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| u2_flutter-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.5 kB
Release files / u2_flutter-0.1.0.tar.gz
| Download URL | u2_flutter-0.1.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8754116f727e907e0a210d7e6aa3b08318b327169f017e9295f3c536dce1a1e7
|
|
BLAKE2b-256 checksum How to use checksums |
8f933b5cbf98fa83285ce80ec2469c12ee2a9341d27b3c85dad1b7daf375fe2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.0rc2
|
Release files / u2_flutter-0.1.0-py3-none-any.whl
| Download URL | u2_flutter-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
88fb28c2258fa601940126eac7d80df7ca610ce432076dfea272552d76932b7c
|
|
BLAKE2b-256 checksum How to use checksums |
3e7e8ab2e3445f0a7b9316b954fbf06b3fc116ee09bd65e02b1cb47c33a04746
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.0rc2
|