Flutter Floating Window
A Flutter plugin for creating and managing floating overlay windows on Android. This plugin allows you to create draggable, resizable floating windows that can stay on top of other applications.
Features
- ✅ Create multiple floating windows
- ✅ Draggable windows with touch support
- ✅ Customizable window size and position
- ✅ Window visibility control
- ✅ Data communication between main app and floating windows
- ✅ Event handling (window created, moved, closed, etc.)
- ✅ Permission management for overlay access
- ✅ Works when main app is closed
- ✅ Customizable window appearance
Requirements
- Flutter SDK: >=3.0.0
- Android SDK: API level 23 (Android 6.0) or higher
- Kotlin: 1.7.10 or higher
Installation
Add this to your package's pubspec.yaml file:
dependencies:
flutter_floating_window:
path: ../ # Use appropriate path or pub.dev when published
Then run:
flutter pub get
Android Setup
1. Permissions
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2. Service Declaration
Add the floating window service and boot receiver to your AndroidManifest.xml inside the <application> tag:
<service
android:name="com.example.flutter_floating_window.FloatingWindowService"
android:enabled="true"
android:exported="false" />
<receiver
android:name="com.example.flutter_floating_window.BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
3. Queries (Android 11+)
For Android 11 and above, add package visibility queries:
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>
Usage
Basic Example
import 'package:flutter/material.dart';
import 'package:flutter_floating_window/flutter_floating_window.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_initializeFloatingWindow();
}
Future<void> _initializeFloatingWindow() async {
// Listen to floating window events
FloatingWindowManager.eventStream.listen((event) {
print('Floating window event: ${event.type}');
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Floating Window Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _checkPermission,
child: Text('Check Permission'),
),
ElevatedButton(
onPressed: _requestPermission,
child: Text('Request Permission'),
),
ElevatedButton(
onPressed: _createFloatingWindow,
child: Text('Create Floating Window'),
),
],
),
),
),
);
}
Future<void> _checkPermission() async {
final hasPermission = await FloatingWindowManager.hasOverlayPermission();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Overlay permission: ${hasPermission ? "Granted" : "Denied"}'),
),
);
}
Future<void> _requestPermission() async {
final granted = await FloatingWindowManager.requestOverlayPermission();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Permission ${granted ? "granted" : "denied"}'),
),
);
}
Future<void> _createFloatingWindow() async {
final config = FloatingWindowConfig(
width: 300,
height: 200,
title: 'My Floating Window',
isDraggable: true,
showCloseButton: true,
);
final windowId = await FloatingWindowManager.createWindow(config);
if (windowId != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Window created: $windowId')),
);
}
}
}
Advanced Configuration
final config = FloatingWindowConfig(
width: 400,
height: 300,
initialX: 100,
initialY: 200,
isDraggable: true,
isResizable: false,
stayOnTop: true,
backgroundColor: Colors.blue.value,
cornerRadius: 12.0,
title: 'Advanced Window',
showCloseButton: true,
focusable: true,
opacity: 0.9,
);
final windowId = await FloatingWindowManager.createWindow(config);
Window Management
// Move window
await FloatingWindowManager.moveWindow(windowId, 150, 250);
// Resize window
await FloatingWindowManager.resizeWindow(windowId, 350, 250);
// Hide/Show window
await FloatingWindowManager.setWindowVisibility(windowId, false);
// Send data to window
await FloatingWindowManager.sendDataToWindow(windowId, {
'title': 'Updated Title',
'content': 'New content for the window'
});
// Close window
await FloatingWindowManager.closeWindow(windowId);
// Close all windows
await FloatingWindowManager.closeAllWindows();
Event Handling
FloatingWindowManager.eventStream.listen((event) {
switch (event.type) {
case FloatingWindowEventType.windowCreated:
print('Window created: ${event.windowId}');
break;
case FloatingWindowEventType.windowClosed:
print('Window closed: ${event.windowId}');
break;
case FloatingWindowEventType.windowMoved:
print('Window moved: ${event.data}');
break;
case FloatingWindowEventType.windowClicked:
print('Window clicked: ${event.windowId}');
break;
case FloatingWindowEventType.error:
print('Error: ${event.data?['errorMessage']}');
break;
}
});
API Reference
FloatingWindowManager
Methods
hasOverlayPermission()→Future<bool>requestOverlayPermission()→Future<bool>createWindow(FloatingWindowConfig config)→Future<String?>closeWindow(String windowId)→Future<bool>updateWindow(String windowId, FloatingWindowConfig config)→Future<bool>moveWindow(String windowId, int x, int y)→Future<bool>resizeWindow(String windowId, int width, int height)→Future<bool>setWindowVisibility(String windowId, bool visible)→Future<bool>getActiveWindows()→Future<List<String>>getWindowConfig(String windowId)→Future<FloatingWindowConfig?>sendDataToWindow(String windowId, Map<String, dynamic> data)→Future<bool>closeAllWindows()→Future<void>windowExists(String windowId)→Future<bool>
Properties
eventStream→Stream<FloatingWindowEvent>
FloatingWindowConfig
Properties
width(int): Window width in pixelsheight(int): Window height in pixelsinitialX(int?): Initial X positioninitialY(int?): Initial Y positionisDraggable(bool): Enable drag functionalityisResizable(bool): Enable resize functionalitystayOnTop(bool): Keep window on topbackgroundColor(int?): Background colorcornerRadius(double): Corner radius for rounded cornerstitle(String?): Window titleshowCloseButton(bool): Show close buttonfocusable(bool): Window can receive focusopacity(double): Window opacity (0.0 to 1.0)
FloatingWindowEvent
Properties
type(FloatingWindowEventType): Event typewindowId(String): Window identifiertimestamp(DateTime): Event timestampdata(Map<String, dynamic>?): Additional event data
Troubleshooting
Common Issues
-
Permission Denied Error
- Ensure
SYSTEM_ALERT_WINDOWpermission is declared in AndroidManifest.xml - Request overlay permission before creating windows
- Check if permission is granted using
hasOverlayPermission()
- Ensure
-
Window Not Appearing
- Verify overlay permission is granted
- Check if window dimensions are valid (> 0)
- Ensure the device supports overlay windows
-
Build Errors
- Make sure Android SDK version is 23 or higher
- Verify Kotlin version compatibility
- Clean and rebuild the project
-
Service Not Starting
- Ensure service is declared in AndroidManifest.xml
- Check if FOREGROUND_SERVICE permission is granted
- Verify service class path is correct
Debug Tips
- Enable debug logging to see detailed error messages
- Use
flutter logsto monitor plugin activity - Test on different Android versions and devices
- Check system settings for overlay permissions
Limitations
- Android only (iOS does not support system overlay windows)
- Requires API level 23 (Android 6.0) or higher
- Maximum of 10 concurrent floating windows
- Limited customization options for window content
- Performance may vary on different devices
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you encounter any issues or have questions, please file an issue on our GitHub repository.