Flutter实现禁止录屏但允许截图的解决方案咨询
实现Flutter应用禁止录屏但允许截图的可行方案
针对你的需求,需要分Android和iOS平台分别处理,下面是具体的实现思路和代码示例:
Android 平台实现
Android系统的FLAG_SECURE会同时禁止录屏和系统截图,但我们可以通过临时移除该标记实现APP内主动截图,同时保留对录屏的禁止:
- 设置FLAG_SECURE禁止录屏
在Android原生的MainActivity中添加以下代码,启动时锁定屏幕内容,阻止系统录屏:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 启用FLAG_SECURE,禁止录屏和系统截图 window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) }
- 实现APP内主动截图功能
通过MethodChannel给Flutter提供截图能力,临时移除FLAG_SECURE完成截图后再恢复:
// 初始化MethodChannel,与Flutter通信 private val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "app_screenshot_channel") override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) channel.setMethodCallHandler { call, result -> if (call.method == "captureScreen") { // 临时移除FLAG_SECURE window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) val rootView = window.decorView.rootView rootView.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(rootView.drawingCache) rootView.isDrawingCacheEnabled = false // 恢复FLAG_SECURE window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) // 将Bitmap转为字节数组返回给Flutter val stream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream) val byteArray = stream.toByteArray() result.success(byteArray) } else { result.notImplemented() } } }
- Flutter侧调用截图
通过MethodChannel调用原生方法,拿到截图后处理上传:
final MethodChannel _screenshotChannel = MethodChannel('app_screenshot_channel'); Future<Uint8List?> captureScreen() async { try { return await _screenshotChannel.invokeMethod('captureScreen'); } on PlatformException catch (e) { print("截图失败: ${e.message}"); return null; } } // 在合规模块的按钮点击时调用 void onUploadScreenshot() async { Uint8List? imageBytes = await captureScreen(); if (imageBytes != null) { // 处理上传逻辑 } }
iOS 平台实现
iOS系统中,屏幕录制会触发UIScreen.capturedDidChangeNotification通知,但系统截图不会触发该通知,我们可以利用这个差异实现需求:
- 监听屏幕录制状态
在iOS原生的ViewController中注册通知,检测到录屏时通知Flutter隐藏视频内容:
private let channel = FlutterMethodChannel(name: "screen_capture_channel", binaryMessenger: flutterEngine.binaryMessenger) override func viewDidLoad() { super.viewDidLoad() // 监听屏幕录制状态变化 NotificationCenter.default.addObserver( self, selector: #selector(onScreenCaptureChanged), name: UIScreen.capturedDidChangeNotification, object: nil ) } @objc private func onScreenCaptureChanged() { let isCaptured = UIScreen.main.isCaptured // 通知Flutter侧当前录屏状态 channel.invokeMethod("updateCaptureState", arguments: isCaptured) } // 页面销毁时移除通知 deinit { NotificationCenter.default.removeObserver(self) }
- Flutter侧处理录屏状态
接收原生通知,当检测到录屏时显示占位层,隐藏视频内容;录屏结束后恢复:
final MethodChannel _captureChannel = MethodChannel('screen_capture_channel'); bool _isRecording = false; @override void initState() { super.initState(); _captureChannel.setMethodCallHandler((call) async { if (call.method == "updateCaptureState") { setState(() { _isRecording = call.arguments as bool; }); } }); } @override Widget build(BuildContext context) { return Stack( children: [ // 你的视频流播放器组件 VideoStreamPlayer(), // 录屏时显示的占位层 if (_isRecording) Container( color: Colors.black, child: const Center( child: Text("禁止录屏", style: TextStyle(color: Colors.white, fontSize: 18)), ), ), ], ); }
注意事项
- Android的
FLAG_SECURE在部分定制ROM上可能存在兼容性问题,需要多机型测试 - iOS的监听逻辑要确保在页面生命周期内正确注册和移除通知,避免内存泄漏
- 两种方案都保留了系统截图(iOS)或APP内主动截图(Android)的能力,满足合规模块的上传需求
内容的提问来源于stack exchange,提问作者Ebrahim Mansur
相关产品推荐
相关产品推荐

