Flutter如何在Android与iOS端仅禁用录屏而非截屏?
问题原因
flutter_window_manager 类的权限管控包,核心是调用安卓系统的FLAG_SECURE窗口标记、iOS系统的secureTextEntry窗口属性实现内容保护,这两个系统级API的设计就是同时拦截截屏与录屏行为,无法拆分控制,因此无法满足仅屏蔽录屏的需求。
双端实现方案
整体逻辑不需要依赖现有第三方Flutter包,通过原生能力分别适配安卓、iOS端,再通过MethodChannel对接Flutter层即可,所有逻辑均不会拦截用户正常截屏操作。
Android端实现
- Android 14(API 34)及以上:使用官方新增的专属录屏拦截私有窗口标记,系统级支持仅拦截录屏,完全不影响截屏,核心代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_BLOCK_SCREEN_RECORDING) }
- Android 13及以下版本:系统未提供单独拦截录屏的公开API,可通过
MediaProjectionManager监听全局录屏会话状态:检测到录屏启动时,在应用窗口上层添加仅对录屏捕获流生效的纯色遮罩,录屏结束后自动移除遮罩。该逻辑不会响应用户瞬时触发的截屏操作,截屏可正常获取应用显示内容。
iOS端实现
iOS 11及以上系统原生提供录屏状态监听能力,不需要申请特殊权限,也不会影响截屏功能:
- 监听
UIScreen.capturedDidChangeNotification系统通知,实时获取录屏状态 - 检测到录屏启动时,在应用KeyWindow上添加录屏遮罩层,录屏结束后移除
核心代码如下(写在AppDelegate中即可):
NotificationCenter.default.addObserver( forName: UIScreen.capturedDidChangeNotification, object: nil, queue: .main ) { _ in guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return } if UIScreen.main.isCaptured { let maskView = UIView(frame: window.bounds) maskView.tag = 9999 maskView.backgroundColor = .black maskView.isUserInteractionEnabled = false window.addSubview(maskView) } else { window.viewWithTag(9999)?.removeFromSuperview() } }
注:不要给iOS窗口设置isSecureTextEntry = true属性,该属性会同时拦截截屏与录屏,不符合需求。
Flutter层对接
在Flutter层通过MethodChannel和原生逻辑通信,可根据业务需求灵活开关录屏拦截,示例代码:
const screenProtectChannel = MethodChannel('com.yourdomain.app/screen_protect'); // 开启仅拦截录屏模式 Future<void> enableRecordBlock() async { await screenProtectChannel.invokeMethod('enableBlockRecord'); } // 关闭录屏拦截 Future<void> disableRecordBlock() async { await screenProtectChannel.invokeMethod('disableBlockRecord'); }
注意事项
- Android 14+的专属拦截标记是系统级能力,录屏时应用内容会直接被系统替换为黑屏,本地显示、截屏完全不受影响
- Android低版本的录屏检测逻辑不需要申请特殊敏感权限,仅需识别系统录屏服务的活跃状态即可
- iOS端的录屏遮罩仅会出现在录屏捕获的视频流中,本地用户无感知,截屏操作不会捕获到该遮罩层
- 所有实现逻辑均不会触发系统截屏拦截,用户可正常使用系统截屏功能获取应用页面内容
内容的提问来源于stack exchange,提问作者Eywin Apps
相关产品推荐
相关产品推荐

