Cherry Studio 隐私政策确认机制技术解析:从版本号到数据收集开关的完整实现链路

发布时间:2026/11/11 10:14:46

Cherry Studio 隐私政策确认机制技术解析:从版本号到数据收集开关的完整实现链路 Cherry Studio 隐私政策确认机制技术解析从版本号到数据收集开关的完整实现链路【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio导读隐私政策确认Privacy Policy Acknowledgement是桌面应用合规体系中的关键一环当隐私政策更新后应用必须在不打断用户主流程的前提下引导用户重新阅读并确认最新版本同时尊重用户拒绝数据收集的权利。本文基于 Cherry Studio 当前仓库的真实源码完整剖析其隐私政策版本号 数据收集开关双偏好Preference驱动的确认机制覆盖从偏好存储、版本常量、更新门控组件、政策全文弹窗到首次启动引导Onboarding联动的全链路实现并给出每个环节对应的源码路径与可验证的配置键名帮助读者理解此类机制在 Electron React 架构中的落地范式。一、机制总览双偏好驱动的门控 弹窗设计Cherry Studio 的隐私政策确认机制并非简单的弹窗提示而是由两个偏好Preference键共同决定用户是否需要重新确认偏好键类型默认值语义app.privacy.policy_versionstring空字符串用户当前已确认的隐私政策版本号未确认过则为空app.privacy.data_collection.enabledboolean—由用户选择是否允许应用收集诊断数据遥测开关这两个键的 Schema 定义位于 src/shared/data/preference/preferenceSchemas.ts其中policy_version的类型注解为stringdata_collection.enabled为boolean。从源码结构看该键体系同时被渲染进程Renderer与主进程偏好服务共享是典型的共享层定义、双端消费模式。判断是否需要弹窗的核心逻辑封装在useIsPrivacyUpdateRequiredHook 中src/renderer/hooks/useIsPrivacyUpdateRequired.tsexport function useIsPrivacyUpdateRequired(): boolean { const [policyVersion] usePreference(app.privacy.policy_version) const [dataCollectionEnabled] usePreference(app.privacy.data_collection.enabled) return dataCollectionEnabled policyVersion ! LATEST_PRIVACY_POLICY_VERSION }该 Hook 的语义非常明确仅当数据收集开关为开启状态时才要求用户确认最新政策——如果用户此前已关闭数据收集则无需再次打扰仅当已确认版本号不等于最新版本号时才触发更新确认流程——已确认过最新版本的用户直接放行。配套的 Hook 测试位于 src/renderer/hooks/tests/useIsPrivacyUpdateRequired.test.ts可在仓库中直接查看其针对开关关闭不弹窗版本一致不弹窗两者同时满足才弹窗等分支的断言。二、版本号机制一个常量的作用与升级策略2.1 最新版本常量定义当前仓库中最新隐私政策版本号被定义为共享常量export const LATEST_PRIVACY_POLICY_VERSION 20260820见 src/shared/utils/constants.ts。该常量以日期字符串YYYYMMDD作为版本标识位于shared/utils/constants中可被主进程、预加载与渲染进程统一引用从机制上避免了主进程与渲染进程各存一份版本号导致不同步的经典问题。2.2 版本升级的工作流当团队更新隐私政策全文时需要同步做两件事更新政策全文资源替换打包资源中的privacy-en.html英文版与privacy-zh.html中文版文件更新LATEST_PRIVACY_POLICY_VERSION常量为新的日期字符串。由于useIsPrivacyUpdateRequired是已确认版本 ≠ 最新版本即触发弹窗因此每次递增版本号都会让所有已开启数据收集的老用户自动进入需重新确认状态无需任何迁移逻辑——这是该方案最优雅的一点确认状态天然具备版本感知能力。2.3 首次启动的特殊语义对于从未确认过政策的用户policy_version默认为空字符串。此时只要数据收集开关默认开启Onboarding 流程的默认行为详见第五节useIsPrivacyUpdateRequired同样返回true从而在首次启动时也能正确触发政策确认弹窗——新用户首次确认与老用户版本更新确认被同一套逻辑覆盖无需区分两条代码路径。三、更新门控组件PrivacyPolicyUpdateGate 的交互细节PrivacyPolicyUpdateGatesrc/renderer/windows/main/privacy/PrivacyPolicyUpdateGate.tsx是政策已更新但用户尚未确认场景下的门控组件挂在主窗口应用根组件附近负责在open即useIsPrivacyUpdateRequired()为真时拦截用户操作。3.1 两种用户选择与对应的状态写入组件提供两个按钮对应两条完全不同的偏好写入路径路径 A接受最新政策acknowledgeconst acknowledge useCallback(async () { setIsUpdatingPrivacy(true) try { await setPolicyVersion(LATEST_PRIVACY_POLICY_VERSION) } catch { toast.error(t(privacy_policy_update.acknowledge_failed)) } finally { setIsUpdatingPrivacy(false) } }, [setPolicyVersion, t])仅写入app.privacy.policy_version LATEST_PRIVACY_POLICY_VERSION保持数据收集开关不变若此前开启则继续开启。路径 B拒绝接受continueWithoutConsentconst continueWithoutConsent useCallback(async () { setIsUpdatingPrivacy(true) try { await setDataCollectionEnabled(false) setShowPolicy(false) } catch { toast.error(t(privacy_policy_update.acknowledge_failed)) } finally { setIsUpdatingPrivacy(false) } }, [setDataCollectionEnabled, t])关闭数据收集开关app.privacy.data_collection.enabled false不更新版本号。由于useIsPrivacyUpdateRequired的判定条件是开关开启 且 版本不一致关闭开关后门控条件自然解除用户可继续使用应用——拒绝确认政策的后果是放弃数据收集而不是被锁死在弹窗前。3.2 强制的模态交互从 JSX 细节可以看到该弹窗是不可绕过的强制模态showCloseButton{false}不显示关闭按钮closeOnOverlayClick{false}与onPointerDownOutside{(event) event.preventDefault()}点击遮罩层不关闭onEscapeKeyDown{(event) event.preventDefault()}按 Esc 键不关闭。这意味着用户只有接受并继续或拒绝关闭数据收集两条出路符合隐私合规场景下必须给出明确选择的要求。同时组件通过loading与disabled属性在写入偏好期间禁用按钮避免重复提交写入失败时通过toast提示无法保存确认状态请重试。3.3 乐观更新被显式关闭组件在读取偏好时特意传入了PESSIMISTIC_PREFERENCE_OPTIONS { optimistic: false }即使用悲观更新模式偏好写入必须等待持久化完成后再更新 UI 状态。这是有意的设计取舍——隐私确认状态属于敏感持久化数据若使用乐观更新先改 UI 再异步落盘一旦落盘失败会导致用户以为已确认、实际重启后再次弹窗的矛盾体验。四、政策全文弹窗PrivacyPolicyDialog 与资源加载链路PrivacyPolicyDialogsrc/renderer/windows/main/privacy/PrivacyPolicyDialog.tsx是展示政策全文的可复用弹窗组件同时服务于首次启动引导Onboarding与更新确认两个场景。4.1 多语言资源选择export function getPrivacyPolicyAsset(language: string): privacy-en.html | privacy-zh.html { return language.toLowerCase().startsWith(zh) ? privacy-zh.html : privacy-en.html }根据i18n.resolvedLanguage回退到i18n.language再回退到en-US判断语言前缀是否以zh开头选择privacy-zh.html或privacy-en.html。政策全文以独立 HTML 资源形式随应用打包而非硬编码在组件内便于后续迭代时仅替换资源文件即可完成政策更新。4.2 文件 URL 构建与主题注入export function buildPrivacyPolicyUrl(resourcesPath: string, language: string, theme: ThemeMode): string { const filePath AbsoluteFilePathSchema.parse( joinPath(resourcesPath, cherry-studio/${getPrivacyPolicyAsset(language)}) ) const themeName theme ThemeMode.dark ? dark : light return ${toFileUrl(filePath)}?theme${themeName} }加载链路为通过ipcApi.request(app.get_info)获取主进程返回的resourcesPath资源目录绝对路径拼接出政策 HTML 的绝对路径经AbsoluteFilePathSchema校验再通过toFileUrl转换为file://URL并附带?themedark|light查询参数——政策 HTML 可据此自行适配明暗主题保证弹窗内政策阅读体验与应用主题一致。该 URL 最终通过沙箱 iframe 加载iframe src{privacyUrl} title{t(privacy_policy.title)} sandboxallow-scripts ... /sandboxallow-scripts意味着政策页面仅允许执行脚本不授予同源、表单提交、弹窗等权限属于安全沙箱策略。加载失败如资源缺失时组件记录日志并展示privacy_policy.load_failed错误文案而不是白屏。4.3 关闭策略与确认回调与PrivacyPolicyUpdateGate一致该弹窗同样不可通过关闭按钮、遮罩点击或 Esc 键关闭只能通过底部的接受并继续acceptButtonText可定制或拒绝按钮完成交互。isPending状态控制按钮 loading 展示回调通过 props 注入onAccept/onDecline使同一组件可被门控与 Onboarding 两处复用。五、与首次启动引导Onboarding的联动首次启动时Onboarding 页面同样承担隐私政策的初始确认职责src/renderer/windows/main/onboarding/OnboardingPage.tsx页面读取app.privacy.data_collection.enabled与app.privacy.policy_version两个偏好对应源码第 63-64 行的偏好键映射通过privacyAccepted状态记录用户是否勾选同意隐私政策组件中第 96 行useState(true)的默认行为从源码看是可配置的初始值实际以页面内复选框交互为准当用户完成引导时若同意政策写入{ policyVersion: LATEST_PRIVACY_POLICY_VERSION }保持数据收集开关为用户选择的状态若拒绝政策写入{ dataCollectionEnabled: false, policyVersion: }即关闭数据收集且不记录版本号写入失败时提示onboarding.privacy.update_failed无法保存隐私协议同意状态请重试。由此Onboarding 与PrivacyPolicyUpdateGate形成了完整的覆盖闭环场景触发组件判定条件处理结果全新用户首次启动OnboardingpolicyVersion 且未勾选同意勾选同意→记录最新版本号拒绝→关闭数据收集老用户政策升级PrivacyPolicyUpdateGate数据收集开启 且 版本号 ≠ 最新接受→更新版本号拒绝→关闭数据收集已关闭数据收集的用户均不触发开关为 false直接放行不打扰六、偏好持久化与多语言文案6.1 偏好键与默认值app.privacy.*两个键被纳入共享偏好 Schemasrc/shared/data/preference/preferenceSchemas.ts其默认值在 Schema 对应的默认值映射中定义为policy_version: 同一文件的第 606 行附近即默认视为从未确认。该默认值保证任何未写过版本号的安装包括升级自旧版本的安装在数据收集开启时都会被视为需要确认最新政策。6.2 渲染层多语言文案更新确认弹窗与 Onboarding 的文案分布在渲染层各语言包中如 src/renderer/i18n/locales/en-us.json 与 zh-cn.json关键文案键包括privacy_policy_update.title中文隐私协议更新英文Privacy Policy Updatedprivacy_policy_update.description_before_link我们更新了隐私协议。请查看最新的…后接可点击的privacy_policy_update.policy链接按钮点击后打开政策全文弹窗privacy_policy_update.acknowledge_failed无法保存确认状态请重试onboarding.privacy.accept_and_continue同意并继续 / Accept and Continueonboarding.privacy.notice/onboarding.privacy.policyOnboarding 页面的我已阅读并同意 [隐私协议]复选框文案privacy_policy.title/privacy_policy.load_failed政策全文弹窗的标题与加载失败提示。值得注意的设计细节更新弹窗的描述文案刻意把政策链接做成行内按钮variantlink、下划线样式而不是让用户先读完 HTML 全文再回到门控弹窗确认——用户点击链接后门控弹窗保持打开状态政策全文弹窗叠层展示open{open showPolicy}接受/拒绝操作仍然落回门控弹窗底部按钮交互路径闭环且不易迷路。七、从源码看可复用的实现范式综合以上分析Cherry Studio 的隐私政策确认机制可以抽象为以下可复用的实现范式供其他 Electron/桌面应用参考版本号即状态用YYYYMMDD日期字符串作为政策版本与政策资源文件名解耦确认状态 用户已确认的版本号版本升级天然触发重新确认零迁移成本数据收集开关作为免打扰出口拒绝确认 ≠ 禁用应用而是优雅降级为关闭数据收集既满足合规又不损害核心功能可用性共享常量防漂移LATEST_PRIVACY_POLICY_VERSION放在shared/utils/constants双端主进程/渲染进程引用同一来源避免版本号不同步悲观更新保证一致性隐私类敏感偏好使用optimistic: false写入确保落盘成功后才更新 UI杜绝假确认强制模态 沙箱 iframe不可绕过的弹窗保证用户必须给出明确选择政策全文以sandboxallow-scripts的 iframe 加载本地 HTML 资源兼顾展示灵活性主题注入与安全性单一弹窗组件多场景复用PrivacyPolicyDialog同时服务 Onboarding 与更新门控通过 props 注入回调解耦业务。八、结语与延伸阅读隐私政策确认看似是弹个窗的小功能但 Cherry Studio 的实现将其落成了偏好键 共享常量 门控 Hook 强制模态 多语言资源的完整体系其版本号驱动与拒绝即关闭数据收集的设计尤其值得借鉴。读者可继续深入以下仓库路径进行验证与扩展门控与判定逻辑PrivacyPolicyUpdateGate.tsx、useIsPrivacyUpdateRequired.ts 及对应测试 useIsPrivacyUpdateRequired.test.ts政策全文弹窗与资源加载PrivacyPolicyDialog.tsx 及组件测试 PrivacyPolicyDialog.test.tsx、PrivacyPolicyUpdateGate.test.tsx偏好 Schema 与默认值preferenceSchemas.ts版本常量constants.tsOnboarding 联动OnboardingPage.tsx多语言文案en-us.json 与 zh-cn.json。【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/11 23:23:16

拆解2007年ASP档案系统:IIS部署、上传与数据库迁移

简介:这份毕业设计资料包提供完整的ASP档案管理系统源代码与配套论文,面向计算机相关专业学生及需要快速搭建档案管理类项目的开发者。系统基于ASP与Access/SQL Server数据库,覆盖用户登录与权限管理、档案上传与检索、分类标签、日志记录、安…

2026/11/9 18:50:22

Python分形艺术:从数学原理到算法实现

1. Python艺术创作:分形与算法绘图入门分形艺术作为数学与计算机科学的完美结合,近年来在数字艺术领域掀起热潮。作为一名长期使用Python进行创意编程的开发者,我发现利用Python生成分形图案不仅能培养编程思维,更能创造出令人惊叹…

2026/11/12 3:24:16

建筑电工证及格分数你知道多少?内部消息帮你避开培训陷阱

建筑电工证及格分数你知道多少?内部消息帮你避开培训陷阱 怕考不过白交培训费?很多在工地干活的兄弟都遇到过这个问题,尤其是那些想考建筑电工证的劳务班组负责人。建筑电工证及格分数到底多少?考试难度大不大?能不能提前知道题型?今天就来聊一聊这些你…

2026/11/12 3:24:16

南昌电工证报考条件:上岗必备,实操考试心里没底怕挂科

南昌电工证报考条件:上岗必备,实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。很多准备考南昌电工证的小伙伴都担心实操考试过不了,影响工作机会。但别慌,只要掌握好报考条件和备考方法,拿下证书不是问题。下面我来给你说说南昌电工证报…

2026/11/12 3:24:16

临沂电工证复审流程官方回应来了,过期了别慌

临沂电工证复审流程官方回应来了,过期了别慌 证书过期了不知道怎么复审延期?临沂电工证复审流程是很多特种作业人员最头疼的问题,尤其是像周口劳务班组这样的施工团队,一旦电工证过期,不仅影响项目进度,还可能面临停工整顿甚至法律责任。 官方回应…

2026/11/12 3:24:16

电工证要不要18岁?办理门槛、多少钱和实操指南全解析

电工证要不要18岁?办理门槛、多少钱和实操指南全解析 之前考的证在外省能不能转过来?你是不是也遇到过这样的问题?其实,关于电工证的年龄限制、考试费用、报考流程,很多同行在操作时都踩过坑。本文以商丘水利工程从业者为视角,手把手带你了解电工证要…

2026/11/12 3:19:16

土建工程特种工有哪些?外省证怎么转?含金量全解析

土建工程特种工有哪些?外省证怎么转?含金量全解析 之前考的证在外省能不能转过来?你肯定不是第一个问这个问题的人,也不是最后一个。现在全国一体化平台推行,证件跨省转移不再难,但具体怎么操作、转过来的证有没有 含金量…

2026/11/11 12:42:59

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/12 0:04:01

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘 工地太忙根本没时间复习考试?你不是一个人。作为一名在南阳卧龙区干了七八年市政公用工程的电工,我深知这个问题的现实性。电工证不仅是工作的“入场券”,更是职业发展的“通行证”,但备考过程…

2026/11/12 0:04:01

双流电工证考别怕挂科!郑州报考避坑指南全攻略

双流电工证考别怕挂科!郑州报考避坑指南全攻略 实操考试心里没底怕挂科?双流电工证考在郑州报名,很多人因为不了解流程、准备不充分,白白浪费时间和金钱。作为三门峡应届工程类毕业生,我也曾经历过这样的焦虑。今天就从零开始,手把手教你如何避开郑州报…

2026/11/12 0:04:01

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少 之前考的证在外省能不能转过来?这个问题确实让不少准备换城市工作的朋友犯了难,尤其像电工证这种实操性很强的证书,很多人担心跨省后证书能不能继续用。其实,只要符合相关流程,是可以顺利转…

2026/11/11 20:27:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑