Flutter开发:bubble_overlay包已停用,求Android端气泡悬浮窗替代方案
Flutter Android气泡悬浮窗替代方案与实现方式
一、替代包推荐
- flutter_windowmanager:支持Android端窗口管理,可实现悬浮窗功能,维护状态相对活跃,能处理权限请求与基础悬浮视图交互。
- system_alert_window:专注于创建系统级悬浮窗口,支持自定义布局,适配点击、拖动等交互逻辑,兼容较新Android版本。
- flutter_float_widget:轻量级悬浮窗实现包,提供基础的悬浮视图创建、拖动及生命周期管理,适合简单场景需求。
二、原生Android自定义实现(MethodChannel通信)
若不想依赖第三方包,可通过Flutter与原生Android通信自行实现:
- 申请权限
在AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
针对Android 6.0+动态请求权限,检查并跳转至设置页面:
if (!Settings.canDrawOverlays(context)) { val intent = Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.packageName) ) startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE) }
- 创建悬浮窗Service
在原生端编写Service构建悬浮窗布局与交互逻辑:
class FloatWindowService : Service() { private lateinit var windowManager: WindowManager private lateinit var floatView: View override fun onCreate() { super.onCreate() windowManager = getSystemService(WINDOW_SERVICE) as WindowManager floatView = LayoutInflater.from(this).inflate(R.layout.float_window, null) val params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY else WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT ) params.gravity = Gravity.TOP or Gravity.LEFT params.x = 100 params.y = 100 // 实现拖动功能 floatView.setOnTouchListener(object : View.OnTouchListener { private var lastX = 0 private var lastY = 0 private var initialX = 0 private var initialY = 0 private var isDragging = false override fun onTouch(v: View, event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { lastX = event.rawX.toInt() lastY = event.rawY.toInt() initialX = params.x initialY = params.y isDragging = false } MotionEvent.ACTION_MOVE -> { val dx = event.rawX.toInt() - lastX val dy = event.rawY.toInt() - lastY params.x = initialX + dx params.y = initialY + dy windowManager.updateViewLayout(floatView, params) isDragging = true } MotionEvent.ACTION_UP -> { if (!isDragging) { // 通过MethodChannel通知Flutter点击事件 methodChannel.invokeMethod("onFloatWindowClick", null) } } } return true } }) windowManager.addView(floatView, params) } override fun onDestroy() { super.onDestroy() windowManager.removeView(floatView) } override fun onBind(intent: Intent): IBinder? = null }
- Flutter与原生通信
Flutter端通过MethodChannel调用原生方法并监听事件:
static const MethodChannel _channel = MethodChannel('float_window_channel'); // 启动悬浮窗 Future<void> startFloatWindow() async { await _channel.invokeMethod('startFloatWindow'); } // 关闭悬浮窗 Future<void> stopFloatWindow() async { await _channel.invokeMethod('stopFloatWindow'); } // 监听悬浮窗点击 void _setupListener() { _channel.setMethodCallHandler((call) async { if (call.method == 'onFloatWindowClick') { // 处理点击逻辑 print('悬浮窗被点击'); } }); }
原生端初始化MethodChannel并处理Flutter调用:
private val methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "float_window_channel") methodChannel.setMethodCallHandler { call, result -> when (call.method) { "startFloatWindow" -> { startService(Intent(this, FloatWindowService::class.java)) result.success(null) } "stopFloatWindow" -> { stopService(Intent(this, FloatWindowService::class.java)) result.success(null) } else -> result.notImplemented() } }
三、注意事项
- Android 10及以上版本需使用
TYPE_APPLICATION_OVERLAY窗口类型,旧版本用TYPE_PHONE。 - 悬浮窗默认设置
FLAG_NOT_FOCUSABLE,若需输入功能需调整窗口参数。 - 后台启动悬浮窗可能受厂商后台限制,需适配不同品牌设备的策略。
内容的提问来源于stack exchange,提问作者Rishigesan
相关产品推荐
相关产品推荐

