
简介围绕 macOS 开启 HiDPI 的实用脚本包面向使用旧款 Mac 或中低分辨率外接显示器的用户旨在绕过系统设置限制让字体、图标与窗口以更高像素密度渲染获得更清晰细腻的观感适合设计师、图像编辑者及希望改善日常办公显示效果的人群。压缩包共 14 个文件约 2.05MB包含可直接执行的 sh 与 command 脚本、plist 配置、icns 显示图标、jpg/gif 效果预览以及中英文 md 说明兼顾一键启用与操作参考目录组织紧凑便于按用途查找。已有 2054 人学习下载说明它在旧设备显示优化场景中具有一定参考价值。读者可借助脚本简化传统上需依赖 RDM 等图形工具或手动修改系统参数的流程并通过预览图与说明快速判断效果、理解配置思路同时应留意系统文件读写带来的风险操作前做好备份并理解部分应用对高分辨率适配有限。1. 先看清这套环境的底同一块 4K 屏Mac 只给两档macOS 开启 HiDPI 这件事在外接 4K 屏的机器上几乎是刚需。上周帮人调一台 M 芯片的机器27 寸 4K 面板插上去系统设置里只有 1920×1080 和 3840×2160 两个选项中间 2560×1440、3008×1692 那一大片全空着字看着发虚缩放又全是插值算出来的。问题不在显示器也不在线材是 macOS 对没有进过它内部白名单的面板默认不生成缩放模式。一套跟着系统版本走的显示覆盖文件就能补上代价是改错了得能退回来。这套流程适合手里有外接屏、被默认档位卡住的开发者也适合第一次碰显示覆盖文件、想先搞清原理再动手的人。2. 装前准备系统版本、面板 ID 与三条路线先对齐动手之前有三件事必须先定下来走哪条路线、系统版本落在哪一档、原始配置怎么留底。这三件没对齐就敲命令后面大概率是改完没效果或者有效果但重启就没了排查起来比装一遍还费时间。2.1 三条路线的取舍覆盖文件、虚拟屏、手写 plistmacOS 的缩放档位不是实时算出来的而是从一份「显示器覆盖文件」里读出来的。系统在/System/Library/Displays/Contents/Resources/Overrides/下按面板的 VendorID 和 ProductID 建目录目录里放一份 plistplist 里的scale-resolutions数组就是你在系统设置里看到的那几个档位。面板匹配不上系统就只按 EDID 里的原生分辨率给你生成两档这就是中间档位消失的直接原因。第一条路线是往/Library/Displays/Contents/Resources/Overrides/放一份同名的覆盖文件。这个目录的优先级高于系统目录不需要动系统卷也不需要关 SIP从 macOS 10.15 开始就是官方留给用户改的地方。优点是干净缺点是必须精确匹配 VendorID 和 ProductID写错一个字符就不生效。第二条路线是用 BetterDisplay 这类应用创建一块虚拟显示器。它不改系统文件而是在系统之上再叠一层把虚拟屏的画面输出到真实屏上。好处是随时可关、不怕系统更新坏处是多一层合成某些对刷新率和色彩管理敏感的场景要额外调。第三条路线是自己手写 plist。它和第一条其实是同一件事区别只在于你不用脚本、全部手敲。可控性最高也最容易在 data 编码上翻车。我一般的取舍是4K 外接屏、只想要几档常用分辨率走第一条机器经常换屏、或者要给不同面板分别调走第二条只有前面两条都失败了才回到第三条慢慢磨。2.2 环境清单与版本对照表版本这一块最大的分水岭是 macOS 10.15。在这之前覆盖文件只能放在系统卷里必须关掉 SIP 才有写权限10.15 之后/Library下的那份就生效了SIP 保持开启也能改。再往后到 Apple Silicon 时代启动卷是签名的改/System基本无望所以只能走/Library。系统版本区间覆盖文件目录是否需要关 SIP生效方式10.13 – 10.14/System/Library/Displays/Contents/Resources/Overrides需要重启10.15 – 11/Library/Displays/Contents/Resources/Overrides不需要注销或重启窗口服务12 – 13同上不需要注销或重启窗口服务14 及以上同上不需要多数情况注销即可个别机型要重启除了系统版本还要确认两件事。一是芯片类型Intel 机器上还有一些老命令能用Apple Silicon 上很多都不适用别照着几年前的帖子抄。二是显示器是内置屏还是外接屏内置屏的 VendorID 一般是610外接屏是面板厂商自己的编号两者要分开处理混在一起写会互相覆盖。# 查看系统版本与芯片架构决定后面走哪条路 sw_vers uname -m # 确认 SIP 状态Apple Silicon 上基本不用动它 csrutil status # 列出当前已连接的显示器信息包括分辨率和连接类型 system_profiler SPDisplaysDataTypesw_vers给出三个字段重点看ProductVersion它决定覆盖文件放哪儿。uname -m输出arm64还是x86_64决定后面重建缓存那一步要不要跳过。csrutil status只有在你确实要改系统卷时才需要关心走/Library路线的话看到enabled反而是好事不用去动它。system_profiler那一条用来确认显示器到底有没有被识别成外接屏如果这里压根没列出你的显示器先解决线材和接口的问题别急着写覆盖文件。2.3 留一份能一键回滚的备份这一步很多人跳过然后在改坏之后花两小时找原始文件。覆盖文件改错的表现不一定是黑屏更常见的是分辨率列表变成空白、外接屏直接不亮、或者内置屏亮度调节失效。有备份的话删掉自己加的那份就恢复了。# 建一个带时间戳的备份目录放在家目录下别放 /tmp mkdir -p ~/hidpi-backup/$(date %Y%m%d) # 备份 /Library 下已有的覆盖文件如果之前没改过这里可能是空的 sudo cp -R /Library/Displays/Contents/Resources/Overrides \ ~/hidpi-backup/$(date %Y%m%d)/library-overrides 2/dev/null # 记录一份当前可用分辨率的快照出问题时拿来对比 system_profiler SPDisplaysDataType ~/hidpi-backup/$(date %Y%m%d)/displays-before.txt第一段命令建目录日期戳是为了多次尝试时不互相覆盖。第二段的2/dev/null是有意加的因为没改过的机器上这个目录可能不存在cp会报错但那个报错没有意义屏蔽掉更清爽。第三段的快照很关键它记录的是「改之前系统认得的模式」改完之后再跑一次同样的命令做对比能立刻看出是多了档位还是整个显示器都掉了。备份做完还要确认一件事你有没有装过其他显示管理工具。如果之前装过类似的应用它可能已经在/Library下留了自己的覆盖文件这时候直接覆盖会把它顶掉。用ls -la看一眼目录里有什么心里有个数再动手。3. 脚本注入从 ioreg 抠出面板 ID再拼 base64这条路线做的事其实很朴素读出面板的 VendorID 和 ProductID按这两个值建目录和文件把想要的分辨率编码成 plist 认识的格式写进去最后让窗口服务重新加载。麻烦的地方全在编码那一步格式错一个字节系统就当这份文件不存在。3.1 用 ioreg 读出 VendorID 与 ProductID系统认显示器的依据是 IODisplayPrefsKey这个键里就带着两个十六进制 ID。网上很多帖子让你去「关于本机」里翻那里看不到必须从 ioreg 里取。# 从 IO 注册表里过滤出显示器的偏好键一行就能看到两个 ID ioreg -lw0 | grep -i IODisplayPrefsKey # 如果上面一条输出太多用这条只保留外接屏相关的部分 ioreg -rc AppleCLCD2 -l | grep -i DisplayProductID\|DisplayVendorID第一条命令的输出长这样IODisplayPrefsKey IOService:/AppleACPIPlatformExpert/PCI00/.../DisplayVendorID-10ac/DisplayProductID-a0e8。你要的就是最后两段10ac是 VendorIDa0e8是 ProductID都是十六进制转换的时候不要加0x前缀也不要去掉前导零。第二条命令是备用手段某些系统版本上第一条抓不到用AppleCLCD2这个类名能捞出来。两个 ID 必须成对使用只对上一个没用——目录名是DisplayVendorID-10ac文件名是DisplayProductID-a0e8两者拼起来才是完整的匹配路径。如果机器上接了多块屏ioreg 会输出多组键这时候要按顺序对应。分辨方法是看键路径里的端口编号或者干脆拔掉一块屏再跑一次看哪一组消失了。内置屏的 VendorID 固定是610看到这个值就知道对应的是笔记本自己的屏幕。3.2 把目标分辨率编码成 base64 的 dataplist 里的scale-resolutions不是一个简单的数字数组而是一组data每个data是 16 个字节按大端序拆成四段宽、高、标志位、像素格式。手算很容易错所以我一般用一段 Python 生成粘进去就行。# gen_scale.py生成 plist 里 scale-resolutions 需要的 base64 data import base64 import struct # 目标逻辑分辨率列表按你想要的档位改这里 # 4K 面板常见的几档1920x1080、2560x1440、3008x1692、3360x1890 RESOLUTIONS [ (1920, 1080), (2560, 1440), (3008, 1692), (3360, 1890), (3840, 2160), ] def make_entry(width, height): # IIII 表示四个大端 32 位无符号整数宽、高、标志位、像素格式 # 标志位填 1 表示该模式有效并标记为 HiDPI # 0x00200000 是 32 位 ARGB 像素格式基本是固定值 return struct.pack(IIII, width, height, 1, 0x00200000) for w, h in RESOLUTIONS: encoded base64.b64encode(make_entry(w, h)).decode() print(fdata{encoded}/data)跑python3 gen_scale.py会输出若干行data标签每行对应一个分辨率直接把这几行贴进 plist 的array里就行。参数上有两个点值得说清楚RESOLUTIONS里填的是逻辑分辨率也就是你在系统设置里看到的那串数字实际渲染会按两倍去算所以 1920×1080 这一档在 4K 面板上是像素级完美匹配而 2560×1440 需要超采样再降下来清晰度略逊但视野更大。0x00200000这个像素格式值不要乱改改成别的值系统可能认不出这个模式。标志位那个1也别省省掉之后模式会生成但不带 HiDPI 标记菜单里出现的还是普通分辨率。3.3 写文件、改权限、让窗口服务重新加载有了 base64剩下的就是把 plist 拼出来。下面这份是模板DisplayProductName决定菜单里显示的名字随便写但不要留空。?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyDisplayProductName/key stringExternal 4K/string keyDisplayProductID/key integer41216/integer keyDisplayVendorID/key integer4268/integer keyscale-resolutions/key array !-- 下面这几行由 gen_scale.py 输出逐行粘贴 -- dataAAAAB4AAAQ4AAAABACAAAA/data dataAAAACgAABaAAAAABACAAAA/data dataAAAAC8AABpgAAAABACAAAA/data /array /dict /plist两个整数字段要和文件名对得上但注意这里填的是十进制。前面拿到的10ac和a0e8要先转成十进制再填进来10ac是 4268a0e8是 41216。也有人干脆不写这两个 key系统只按文件名匹配两种写法都能生效我倾向于写上方便日后核对。文件放好之后权限必须改root:wheel加644普通用户权限的文件窗口服务读不到。# 按前面拿到的 ID 建目录注意全部小写 sudo mkdir -p /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac # 把拼好的 plist 拷进去文件名必须和 ProductID 完全一致 sudo cp ~/hidpi-work/DisplayProductID-a0e8 \ /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac/ # 权限和属主都要改这一步漏了就是白干 sudo chown -R root:wheel /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac sudo chmod 644 /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac/DisplayProductID-a0e8 # 先用 plutil 检查语法格式不对会直接报出来 plutil -lint /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac/DisplayProductID-a0e8 # 重启窗口服务让配置重新加载当前会话会被注销 sudo killall WindowServerplutil -lint那一步是必做的它会告诉你 plist 结构有没有问题比如少个闭合标签、data里混进了非法字符。这一步过了文件本身就没毛病后面不生效只能是 ID 匹配或缓存的问题。killall WindowServer会直接注销当前会话所有没保存的窗口都会关掉执行前先把手头的东西存一遍。有些机器上重启窗口服务不够需要完整重启一次这个差异和系统版本、面板类型都有关系不用纠结多试一次就行。4. 图形界面方案BetterDisplay 和 RDM 的用法差异不是所有场景都适合往系统目录里写文件。机器频繁换屏、或者你只是临时想试几个分辨率看效果用应用层方案更快反过来如果要求原生刷新率和色彩管理不受影响还是得回到覆盖文件那条路。4.1 BetterDisplay 的安装与关键开关这个工具走的是虚拟显示器路线不改系统覆盖文件。安装用 Homebrew 最省事版本更新也方便。# 通过 cask 安装首次运行需要在系统设置里授权屏幕录制权限 brew install --cask betterdisplay # 装完之后确认版本顺手看看有没有更新 brew list --cask --versions betterdisplay--cask是必须的它走的是 dmg 分发而不是源码编译。装完第一次启动系统会弹权限请求授予屏幕录制权限才能读到显示器信息这个权限在「隐私与安全性」里可以后续调整。打开之后真正要动的开关只有几个。第一个是「创建虚拟显示器」打开之后会多出一块虚拟屏把它的分辨率设成你想要的逻辑值然后把真实屏的画面镜像或扩展到它上面。第二个是「HiDPI 分辨率」开关位置在虚拟屏的详细设置里不开这个的话切出来的还是普通缩放。第三个是刷新率4K 屏在虚拟屏模式下有时会掉到 30Hz手动锁回 60Hz 就能解决。虚拟屏方案有一个坑要提前说它多了一层合成截屏和录屏拿到的是合成后的画面做像素级对比的时候会有细微偏差。这和覆盖文件方案的原生渲染是两回事选的时候心里要有数。4.2 RDM 的轻量用法与它现在的局限RDM 是很老的一类工具做的事情很简单——直接往系统里塞分辨率列表比写 plist 省事。它的定位是轻量装完就能在菜单栏切换不创建虚拟屏也不改覆盖文件。# 老版本需要关 SIP 才能写系统目录新系统上这条路基本走不通 csrutil status # 下载 dmg 后挂载并拷贝到应用目录这一步只能手动做 hdiutil attach ~/Downloads/RDM.app.dmg cp -R /Volumes/RDM/RDM.app /Applications/第一条命令只是确认状态不涉及修改。第二条的hdiutil attach把 dmg 挂到/Volumes下然后用cp -R拷进应用目录。这两步是标准的挂载安装流程没什么特别的。需要提醒的是它的适用范围。Apple Silicon 机器上系统卷是签名的RDM 依赖的写入路径改不了功能会残缺macOS 14 之后权限收紧部分分辨率切了也不生效。所以这个工具我现在只在内置屏上做临时切换用外接屏还是老实写覆盖文件。4.3 兜底方案手写 plist 的检查清单当脚本生成的 plist 不生效或者你拿到的是一份别人给的配置就得自己核对。手写 plist 最容易错的地方只有四个按顺序查一遍基本能定位。第一scale-resolutions必须写成array里面每一项是data不能写成string或者直接塞十六进制字符串。第二data里的内容必须是合法 base64长度对应 16 字节的话编码后是 24 个字符末尾带字符数不对说明字节数错了。第三文件名和目录名里的 ID 要用小写十六进制和 ioreg 输出保持一致大小写敏感。第四plist 顶部的 DOCTYPE 声明不能少少了之后plutil能过但系统可能不认。# 用 defaults 读一遍刚写进去的文件能读出来说明结构没问题 defaults read /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac/DisplayProductID-a0e8 # 转成 xml 格式输出肉眼核对 scale-resolutions 里的项数对不对 plutil -convert xml1 -o - \ /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac/DisplayProductID-a0e8defaults read读的是解析后的结果能正常输出字典就说明文件被系统正确识别了。plutil -convert xml1 -o -那个-o -表示输出到标准输出不写回文件纯粹用来核对内容不会破坏原文件。这两条命令组合起来基本能把「文件写对了但没生效」和「文件本身就有问题」区分开。5. 避坑与排查五条翻车记录下面这些是我在实际部署里真碰到的按现象、原因、解决三段写能对号入座就不用一条条试。5.1 加了档位却不出现或者出现后自己跳回去现象一plist 写进去了plutil也过了重启窗口服务之后系统设置里还是原来那两档一点变化都没有。原因绝大多数是 ID 匹配错了。要么 VendorID 和 ProductID 弄反了要么是从 ioreg 里抄的时候带了引号或者多了空格。还有一种情况是机器上接了扩展坞ioreg 里显示的是扩展坞的 ID不是面板本身的 ID。解决重新跑一遍ioreg -lw0 | grep -i IODisplayPrefsKey把输出原样复制下来逐字符比对目录名和文件名。如果用了扩展坞把显示器直接插到机器上再读一次两个结果对比一下就知道哪个是真实面板的 ID。现象二档位出现了选上去之后画面正常但过几秒自己跳回原来的分辨率反复几次都这样。原因生成的分辨率超过了面板能承载的范围。比如在 1080p 的面板上写了 3840×2160 的条目系统试了一下发现带不动就退回。超采样虽然允许但上限还是受限于面板的物理能力。解决把RESOLUTIONS里的目标值降到面板原生分辨率以下或者只保留原生分辨率一半的那一档作为起点确认能稳定之后再往上加。4K 面板上从 1920×1080 开始测最稳妥。现象三外接屏能出档位笔记本内置屏反而消失了或者两块屏只有一个生效。原因内置屏和外接屏的 VendorID 不同如果只建了外接屏的目录内置屏那份没动某些系统版本上会互相影响。另一种可能是两份 plist 用了同一个DisplayProductName菜单合并的时候出错。解决给两块屏分别建目录内置屏用DisplayVendorID-610外接屏用面板自己的 ID文件名各自独立。DisplayProductName也写成不一样的比如一个叫Built-in一个叫External 4K避免混淆。5.2 花屏、唤醒黑屏和系统更新后失效现象四改完之后合盖睡眠再打开外接屏闪几下或者直接黑掉要拔插线材才恢复。原因覆盖文件里的模式和系统睡眠唤醒时重新协商的 EDID 不一致。唤醒过程中系统会重新枚举显示模式如果 plist 里有一个它认不出的条目整个加载流程可能中断。解决把 plist 里的分辨率条目精简到只留确实会用的两三档并且全部低于面板原生值。改完重启一次而不是只重启窗口服务让系统完整走一遍枚举。如果还是不行把scale-resolutions整个删掉只保留DisplayProductName看看是不是条目本身的问题。现象五系统小版本更新之后之前好好的档位全部消失覆盖文件还在目录里但不起作用。原因系统更新会重置/Library下部分目录的权限和属主文件还在但窗口服务读不到。也有可能是新版本更换了覆盖文件的解析逻辑老的条目格式不再兼容。解决先用ls -la看权限是不是变回了普通用户是的话重新执行chown root:wheel和chmod 644再重启窗口服务。权限没问题的话用plutil -convert xml1把文件导出来看一眼结构有没有被改然后重新生成一份 plist 覆盖进去。我一般会在每次系统大版本更新之后主动重跑一遍这套流程不等它出问题再修。6. 装完怎么验证三条命令加一条回滚验证这件事不能只看系统设置里有没有多出一档那个界面会骗人——有时候档位显示了但选上去没反应有时候选上去了但实际渲染还是插值。我习惯用三条命令交叉确认。第一条还是system_profiler SPDisplaysDataType重点看Resolution那一行。真正生效的 HiDPI 会显示成类似1920 x 1080 (HiDPI)或者分辨率后面带Retina字样只有数字没有后缀的多半还是普通缩放。第二条是截屏测实际渲染尺寸。HiDPI 下逻辑 1920×1080 的屏幕全屏截图的像素尺寸应该是 3840×2160。用screencapture截一张再用sips读尺寸。# 截一张全屏图输出到临时目录 screencapture -x /tmp/hidpi-check.png # 读出图片的实际像素尺寸和预期值对比 sips -g pixelWidth -g pixelHeight /tmp/hidpi-check.png-x表示静音不播放快门声。sips那两个参数分别输出宽和高如果结果是 3840 和 2160说明系统确实按两倍在渲染这是最硬的证据。如果读到的是 1920 和 1080那档位只是个标签实际没生效。第三条是回滚验证也就是确认你的备份真的能用。这一步听着多余但我见过太多人备份了却不知道怎么还原出问题的时候照样抓瞎。# 删掉自己加的覆盖目录恢复到改之前的状态 sudo rm -rf /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-10ac # 重启窗口服务让系统重新读一遍原始配置 sudo killall WindowServer # 和之前的快照对比确认分辨率列表回到了原样 system_profiler SPDisplaysDataType /tmp/displays-after.txt diff ~/hidpi-backup/*/displays-before.txt /tmp/displays-after.txtrm -rf删的是整个目录因为目录里只有你加的那一份文件删掉等于完全恢复。diff那一步如果没有任何输出说明恢复得干干净净有输出的话逐行看通常只是连接状态或时间戳的差异不用紧张。三条都过了这套环境才算真正跑通。从那以后我每次改覆盖文件之前都会先把displays-before.txt存一份并且在改完之后立刻做一次回滚测试——不是因为不自信是因为显示配置坏掉的时候你连菜单都看不清那时候再找后悔药就晚了。希望帮到你。本文还有配套的精品资源点击获取