如何检测Flutter应用是否全屏?含分屏/Stage Manager场景
检测Flutter应用是否处于全屏状态(防作弊场景)
核心思路
要判断应用是否处于全屏(排除Split View、iOS Stage Manager、窗口调整等作弊可能),关键是获取设备真实屏幕尺寸,并与当前应用窗口尺寸对比。同时覆盖初始化、尺寸变化、生命周期恢复等所有可能的场景,确保任何非全屏状态都能被检测到。
1. 获取设备真实屏幕尺寸
MediaQuery.of(context).size返回的是应用窗口的尺寸,而非设备完整屏幕尺寸。可以通过Flutter内置的平台调度器获取物理屏幕尺寸,再转换为逻辑像素:
Size getScreenRealSize(BuildContext context) { final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; final physicalSize = WidgetsBinding.instance.platformDispatcher.implicitView?.physicalSize; if (physicalSize == null) return Size.zero; // 转换为逻辑像素尺寸 return Size( physicalSize.width / devicePixelRatio, physicalSize.height / devicePixelRatio, ); }
2. 判断是否全屏
对比应用窗口尺寸与真实屏幕尺寸,允许1像素的误差(适配系统UI的细微差异):
bool isFullScreen(BuildContext context) { final appSize = MediaQuery.of(context).size; final screenSize = getScreenRealSize(context); final widthMatch = (appSize.width - screenSize.width).abs() < 1; final heightMatch = (appSize.height - screenSize.height).abs() < 1; return widthMatch && heightMatch; }
3. 覆盖所有检测场景
(1)测试场景初始化时检测
用户可能在非全屏状态进入测试,需在页面初始化时立即验证:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (!isFullScreen(context)) { _triggerAntiCheatLogic(); } }); }
(2)监听窗口尺寸变化
保留原有的didChangeMetrics回调,但补充全屏检测逻辑:
@override void didChangeMetrics() { super.didChangeMetrics(); WidgetsBinding.instance.addPostFrameCallback((_) { if (!isFullScreen(context)) { _triggerAntiCheatLogic(); } }); }
(3)修复生命周期监听的不足
原有的didChangeAppLifecycleState无法检测Stage Manager/Slide Over(这类状态下应用仍处于resumed状态),需在恢复前台时重新检测:
@override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); switch (state) { case AppLifecycleState.resumed: setState(() => inBackground = false); // 恢复前台后立即检测全屏 WidgetsBinding.instance.addPostFrameCallback((_) { if (!isFullScreen(context)) { _triggerAntiCheatLogic(); } }); break; case AppLifecycleState.inactive: case AppLifecycleState.paused: case AppLifecycleState.detached: setState(() => inBackground = true); break; } }
4. 防作弊逻辑示例
检测到非全屏状态时,执行对应的限制操作:
void _triggerAntiCheatLogic() { showDialog( context: context, barrierDismissible: false, builder: (ctx) => AlertDialog( title: const Text('测试环境要求'), content: const Text('请将应用切换为全屏状态,否则无法继续测试。'), actions: [ TextButton( onPressed: () { if (isFullScreen(context)) { Navigator.pop(ctx); } else { // 强制退出应用或终止测试流程 SystemNavigator.pop(); } }, child: const Text('确认'), ), ], ), ); }
注意事项
- 适配特殊设备:折叠屏、刘海屏等场景,通过1像素误差容忍可适配系统UI的细微差异;
- 性能优化:
didChangeMetrics会频繁触发,使用addPostFrameCallback确保在UI更新后再检测,避免获取旧尺寸; - 全平台覆盖:iOS Stage Manager/Slide Over、Android Split View等状态下,应用窗口尺寸必然小于屏幕尺寸,均可被检测到。
内容的提问来源于stack exchange,提问作者Jasper
相关产品推荐
相关产品推荐

