# How Bluesky draws its logo on screenshots

> 来源：[HackerNews](https://timmarinin.net/2026/bluesky-screenshots/)

## 背景与概述

在社交媒体的视觉传播中，截图早已成为信息流转的核心载体。无论是产品演示、Bug 报告，还是社群里的趣味分享，一张截图往往比千言万语更直观。然而，对于平台方而言，截图也意味着“内容出域”——用户将站内信息带走，平台品牌标识随之消失，传播链条就此断裂。如何在不打扰用户体验的前提下，让每一张流出平台的截图都自带“身份证明”，成了许多产品团队暗自较劲的设计课题。

Bluesky 作为去中心化社交网络的新锐代表，近期在其客户端中引入了一个颇为巧妙的细节：当用户截取屏幕时，应用会自动在截图角落绘制一个精致的 Bluesky  Logo。这个看似简单的功能，背后却涉及从系统事件监听、图形合成到品牌策略的一整套工程决策。它既不是粗暴的水印，也不是强制弹窗，而是一种“润物细无声”的视觉签名。

本文将基于 Bluesky 官方工程师 Tim Marinin 的分享，拆解这一功能的设计思路、技术实现路径，并探讨它对国内开发者社区在品牌传播与用户体验平衡上的启示。

## 核心内容

### 1. 不是水印，是“签名���

传统的水印往往是半透明的大号 Logo 平铺在画面中央，或者以低透明度文字铺满四角，其目的更偏向于“防盗用”。而 Bluesky 的做法截然不同：Logo 只出现在截图的固定角落，尺寸小巧，色彩与界面风格高度统一，甚至在某些主题下会自适应明暗模式。它更像是一枚“数字签名”——告诉观看者“这张图来自 Bluesky”，而不是“这张图归 Bluesky 所有”。

### 2. 监听截屏事件的两种路径

在移动端实现“截图后自动绘制”的核心，在于如何感知截屏动作。Bluesky 的工程师在文章中提到了两条主流路径：

- **iOS 路径**：利用 `UIApplication.userDidTakeScreenshotNotification` 通知。该通知在用户按下物理按键完成截图后立即触发，应用可以在此回调中获取当前屏幕的 `UIView` 快照，然后进行二次绘制。
- **Android 路径**：使用 `ContentObserver` 监听媒体库中新增的图片文件，或者通过 `FileObserver` 监听截图目录的变化。由于 Android 碎片化严重，不同厂商的截图路径并不统一，因此需要维护一个常见路径列表，并配合 `MediaStore` 的查询来兜底。

### 3. 绘制 Logo 的时机与性能考量

一个容易被忽略的细节是：**Logo ��应该在截图完成后再“贴”上去，而应该在截图发生前的瞬间就“预埋”在界面上**。Bluesky 的做法是：在收到截屏通知后，立即创建一个覆盖全屏的透明 `UIView`，在其中绘制 Logo，然后调用系统的截图 API 重新截取当前屏幕。这样生成的图片中，Logo 是像素级融合的，而不是后期叠加的，避免了二次压缩带来的模糊或色差。

```swift
// 伪代码示意：iOS 端截屏后重绘
NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: .main) { _ in
    let overlay = LogoOverlayView(frame: UIScreen.main.bounds)
    window?.addSubview(overlay)
    // 延迟一帧，确保 overlay 被渲染到帧缓冲区
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        let image = window?.snapshotView(afterScreenUpdates: true)
        // 将 image 写入相册或分享
        overlay.removeFromSuperview()
    }
}
```

### 4. 用户隐私与可关闭性

Bluesky 并没有将这个功能做成强制性的。在设置中，用户可以选择关闭“截图添加 Logo”的选项。这一设计体现了对用户自主权的尊重——毕竟，截图是用户自己的行为，平台不应在未经许可的情��下永久改变用户生成的内容。这种“默认开启、可一键关闭”的策略，既保证了品牌传播的覆盖率，又规避了“侵犯用户创作权”的舆论风险。

## 技术分析

从架构层面看，这个功能可以抽象为三个模块的协作：

- **事件感知层**：负责监听系统截屏事件，并向上层抛出带有时间戳和屏幕尺寸的事件对象。
- **绘制合成层**：接收事件后，根据当前主题（深色/浅色）、屏幕方向、安全区位置，计算出 Logo 的绘制坐标。该层需要与主线程的渲染树解耦，避免阻塞 UI 更新。
- **输出分发层**：将合成后的图片写入系统相册，或直接传递给分享面板。这里需要处理的一个细节是：如果用户截图后立即打开相册，系统相册中可能同时存在“原始截图”和“带 Logo 的截图”两份文件，因此需要在绘制完成后主动删除原始截图（仅当应用处于前台时）。

在性能上，由于截图合成涉及全屏位图的读取与重绘，内存峰值会短暂上升。Bluesky 的优化策略是：**只在用户主动截屏时触发重绘，而不是常驻后台监听**。同时，利用 `UIGraphicsImageRenderer` 替代传统的 `UIGraphicsBeginImageContext`，以利用 Metal 加速渲染，减少 CPU 占用。

## 实践建议

对于想在自家产品中实现类似功能的开发者，以下几点建议值��参考：

1. **优先使用系统通知而非轮询**：iOS 的 `userDidTakeScreenshotNotification` 是最高效的入口；Android 上则建议结合 `DatumObserver` 与 `FileObserver`，但务必做好厂商适配。
2. **Logo 绘制要“轻”**：不要使用全屏半透明遮罩，那会遮挡内容。建议将 Logo 放在右下角或左下角，尺寸控制在 40-60pt 之间，并添加 10% 左右的透明度，既不影响阅读，又能起到标识作用。
3. **提供开关选项**：在设置页中增加“截图添加品牌标识”的开关，默认开启。这不仅是合规要求，也是产品温度的体现。
4. **处理多线程与内存**：截图合成操作应在后台线程完成，避免在主线程进行大位图操作导致卡顿。同时，注意在低内存警告时取消未完成的合成任务。
5. **测试覆盖多机型**：特别是 Android 上，不同厂商的截图路径、屏幕圆角、刘海屏安全区都会影响 Logo 位置，建议使用云测平台覆盖主流机型。

## 总结

Bluesky 在截图角落绘制 Logo 的这个小功能，看似微不足道，却折射出产品团队对“品牌传播”与“用户体验”之间微妙平衡的深刻理解。它没有采用激进的强制水印，而是用一种近乎优雅的方式，让用户自发地成为品牌传播的节点。对于国内开发者而言��这个案例的价值不仅在于技术实现上的参考，更在于一种产品思维的启发：**最好的品牌露出，是让用户感觉不到它的存在，却又无法忽视它的存在**。在信息过载的时代，这种“轻量化”的品牌策略，或许比任何弹窗广告都更具穿透力。