Flutter应用移除后台后“显示在其他应用上层”功能3-4小时后失效问题求助
兄弟,我之前也踩过类似的Android后台保活+悬浮窗失效的坑,你这个情况大概率是系统的后台进程回收和省电机制在搞事情,咱们一步步来排查解决:
先把承载悬浮窗的服务改成前台服务
现在Android对后台进程管控特别严,普通后台Service很容易被系统回收,哪怕你有悬浮窗权限。你得把显示悬浮窗的Service设为前台服务,而且Android 8.0+要求必须绑定一个可见的通知(不能是静默的),这样系统会把进程优先级拉高,不容易被干掉。
具体操作需要用Flutter的MethodChannel调用原生Android代码:在Service的onCreate或者onStartCommand方法里调用startForeground(NOTIFICATION_ID, notification),提前创建好对应的通知渠道,通知内容可以写“XX悬浮窗服务运行中”之类的,让用户知道你的应用在后台干活。把应用加入电池优化白名单
不管是原生Android还是国产ROM(小米、华为、OPPO这些),电池优化功能都会杀掉后台进程来省电,3-4小时的存活时间刚好符合系统进入Doze模式(空闲省电模式)的时间点。
你可以在代码里请求忽略电池优化的权限:首先在AndroidManifest.xml里加权限声明:<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />然后在合适的时机(比如用户开启悬浮窗功能时)弹出请求:
Intent intent = new Intent(); String packageName = getPackageName(); PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); if (!pm.isIgnoringBatteryOptimizations(packageName)) { intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); startActivity(intent); }记得要跟用户说明为什么要开这个权限,比如“为了保证悬浮窗持续运行,需要关闭电池优化”,别让用户觉得你在偷电。
检查ROM的后台自启动权限
很多国产ROM有自己的后台管控逻辑,比如小米的“自启动管理”、华为的“后台活动限制”,如果没开自启动,系统回收进程后就没法自动拉起。你可以在应用的设置页里加个引导,告诉用户去系统设置里开启你的应用的自启动权限,这个是硬需求,不然光靠代码很难绕过。给Service设置重启策略
在Service的onStartCommand方法里返回START_STICKY或者START_REDELIVER_INTENT,这样当Service被系统回收后,系统会尝试重新启动它:@Override public int onStartCommand(Intent intent, int flags, int startId) { // 这里初始化悬浮窗的逻辑 return START_STICKY; }不过要注意,
START_STICKY在Doze模式下可能不会生效,所以还是要结合前面的前台服务和电池优化白名单一起用。兜底检查悬浮窗权限
虽然你已经获取了SYSTEM_ALERT_WINDOW权限,但偶尔系统可能会因为某些原因重置权限状态?(概率不大,但可以做兜底)每次尝试显示悬浮窗前,先检查权限是否存在:if (!Settings.canDrawOverlays(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivity(intent); }
总结一下,你这个问题的核心就是系统的省电机制把你的后台进程干掉了,优先搞定前台服务和电池优化白名单,再配合自启动权限,应该就能解决3-4小时后悬浮窗失效的问题了。
内容来源于stack exchange




