You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS含状态栏视图截图问题:模拟器有效真机无效求助

解决物理设备上无法截取含状态栏的屏幕快照问题

嘿,我来帮你搞定这个困扰!你的代码在模拟器能正常运行,但物理设备上失效,主要有两个核心问题:

  • 你调用drawHierarchy(in:afterScreenUpdates:)时,错误地把view实例传给了in参数——这个参数需要的是一个CGRect(也就是视图的边界),模拟器对这种错误兼容性比较宽松,但物理设备会直接卡壳。
  • snapshotView再转图像的方式,在物理设备(尤其是带刘海的全面屏机型)上可能没法完整捕获状态栏内容,因为真机上状态栏的渲染层级和模拟器有差异。

先给你修正原代码的版本

把参数错误改掉,同时优化上下文创建的方式,适配物理设备:

extension UIScreen {
    class func screenshot() -> UIImage? {
        guard let screenSnapshotView = UIScreen.main.snapshotView(afterScreenUpdates: false) else {
            return nil
        }
        // 用带透明度和缩放参数的上下文创建方法,更适配不同设备
        UIGraphicsBeginImageContextWithOptions(screenSnapshotView.bounds.size, screenSnapshotView.isOpaque, UIScreen.main.scale)
        defer { UIGraphicsEndImageContext() } // 确保上下文一定会被释放
        screenSnapshotView.drawHierarchy(in: screenSnapshotView.bounds, afterScreenUpdates: true)
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

更推荐的现代写法(iOS 10+)

苹果在iOS 10推出了UIGraphicsImageRenderer,比旧的绘图上下文更简洁,兼容性也更好,能完美捕获包括状态栏在内的整个屏幕:

extension UIScreen {
    class func screenshot() -> UIImage {
        let screenBounds = UIScreen.main.bounds
        let renderer = UIGraphicsImageRenderer(bounds: screenBounds)
        return renderer.image { renderContext in
            // 直接让当前主窗口绘制层级,这样能完整捕获状态栏
            UIApplication.shared.windows.first?.drawHierarchy(in: screenBounds, afterScreenUpdates: true)
        }
    }
}

针对iOS 13+的适配补充

如果你的App要适配iOS 13及以上的多场景模式,UIApplication.shared.windows可能拿不到正确的窗口,改成下面的写法更稳妥:

extension UIScreen {
    class func screenshot() -> UIImage {
        let screenBounds = UIScreen.main.bounds
        let renderer = UIGraphicsImageRenderer(bounds: screenBounds)
        
        return renderer.image { _ in
            guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                  let mainWindow = windowScene.windows.first(where: { $0.isKeyWindow }) else {
                return
            }
            mainWindow.drawHierarchy(in: screenBounds, afterScreenUpdates: true)
        }
    }
}

最后提醒下:如果是在后台尝试截图,可能需要额外的权限,但前台截图的话,上面的代码在所有物理设备上都能正常工作啦。

内容的提问来源于stack exchange,提问作者Forsan Sharabati

火山引擎 最新活动