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 | Provenance | Actions |
|---|---|---|---|---|
| u2_flutter-0.1.0.tar.gz | 16.9 kB | Without provenance | Details for u2_flutter-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| u2_flutter-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for u2_flutter-0.1.0-py3-none-any.whl |
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
|
Security for u2-flutter 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.