- 桌面应用
- 系统编程
【免费下载链接】mac-mouse-fix
Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad!
导读
XCStringsDummyApp 是 Mac Mouse Fix 仓库中一个特殊的“哑元”工程 Target:它本身没有任何业务功能,存在的唯一目的,是让 Xcode 的本地化导出流程(Product > Export Localizations...与xcodebuild -exportLocalizations)能够导出那些被团队手动维护、又不想编译进任何 .app bundle的.xcstrings文件。阅读本文后,你将理解 Xcode 导出本地化的成员规则、这个哑元 Target 的完整搭建思路与关键构建设置,并能把同样的技巧复用到自己的多 Target 项目中。
一、为什么需要 XCStringsDummyApp:一个被 Xcode 规则逼出来的工程技巧
在 Mac Mouse Fix 项目中,本地化资源的管理方式很特别:开发团队手动维护.xcstrings文件(而非依赖 Xcode 自动抽取),这些文件统一存放在 Localization/Strings/ 下,例如Readme.xcstrings、Shared.xcstrings、Acknowledgements.xcstrings、Support/Support.xcstrings等。
问题出在 Xcode 的导出规则上。正如 XCStringsDummyApp/Readme.md 所记载的:
When exporting .xcstrings files into an .xcloc file using
Product > Export Localizations...orxcodebuild -exportLocalizations, Xcode will only export .xcstrings files that are members of at least one target.
也就是说,Xcode 导出本地化(生成.xcloc本地化包)时,只会导出“至少属于一个 target 成员”的.xcstrings文件。一个没有被任何 target 引用的.xcstrings,即使躺在工程目录里,也会在导出时被静默忽略。
由此产生了两难:
- 如果把这些
.xcstrings添加为某个正常 App Target(如 Mac Mouse Fix 主应用)的成员,它们确实会被导出,但同时也会被编译进最终的.appbundle(Readme 中原话是 “It will be included in the compiled .app bundle (I think)”); - 但对其中一部分
.xcstrings(例如用于生成 Markdown 帮助文档、由脚本或工具消费的字符串表),团队明确不希望它们出现在任何已编译的 App bundle里。
XCStringsDummyApp 正是为打破这个两难而存在的:把这类.xcstrings挂到 XCStringsDummyApp 这个专用 Target 名下,从而“骗过”Xcode 的成员检查,让它们可以被导出,却不会被装进任何真实产品 bundle。
二、XCStringsDummyApp 的组成:一个最小化的哑元工程
XCStringsDummyApp 目录下的文件全部是标准 macOS App 工程的最小骨架,逐一看一眼就知道它有多“空”:
| 文件 | 作用 |
|---|---|
| main.m | 仅调用NSApplicationMain(argc, argv),空白的@autoreleasepool占位,不初始化任何逻辑 |
| AppDelegate.h | 空壳的NSApplicationDelegate协议实现声明 |
| AppDelegate.m | applicationDidFinishLaunching:与applicationWillTerminate:均为空实现,仅返回YES支持安全恢复状态 |
| MainMenu.xib | 承载NSMainNibFile所需的主菜单界面文件 |
| XCStringsDummyApp-Info.plist | 手写的 Info.plist,只保留启动必需键 |
| xcstrings_dummy_app.entitlements | 极简沙盒权限,仅开启 App Sandbox 与用户选择的只读文件访问 |
从 Mouse Fix.xcodeproj/project.pbxproj 可以看到这个 Target 的产品标识为com.nuebling.xcstrings-dummy-app(PRODUCT_BUNDLE_IDENTIFIER),产物为XCStringsDummyApp.app,部署目标MACOSX_DEPLOYMENT_TARGET = 15.0。
整个工程没有任何可运行的行为——它从不被用户真正使用,只是为了“挂载”字符串表而存在。
三、关键构建设置:两个开关决定导出行为的成败
哑元 Target 能否正常工作,取决于 pbxproj 中 Debug/Release 两套构建配置里的几个开关(见 project.pbxproj 的 XCStringsDummyApp 构建配置段):
1.LOCALIZATION_EXPORT_SUPPORTED = NO
这是最核心的开关。置为NO后,Xcode 在导出本地化时不会把这个 Target 的常规界面本地化资源(如MainMenu.xib对应的 strings)纳入.xcloc,从而保证哑元 Target 只贡献我们想导出的.xcstrings,不会夹带无关的本地化内容。
2.SWIFT_EMIT_LOC_STRINGS = YES
保留这个开关可以让 Xcode 在导出时仍然扫描并导出该 Target 名下挂载的字符串资源。它与LOCALIZATION_EXPORT_SUPPORTED = NO配合,形成“参与导出、但不导出界面资源”的精确行为。
此外该 Target 还启用了ENABLE_HARDENED_RUNTIME = YES、自动签名(CODE_SIGN_STYLE = Automatic)等常规设置,保证它在任何 scheme 下都能被正常编译——因为导出前 Xcode 会对涉及的 Target 执行构建。
四、为什么要用 Objective-C 写:构建时间是第一考量
Readme 中明确写道:
We made this objc for hopefully faster build times.
从源码看,这个结论很直观:main.m 与 AppDelegate.m 全部是纯 Objective-C 的空实现,不包含任何 Swift 代码。因为本地化导出通常要先构建参与导出的 Target,Swift 工程的编译(类型检查、模块生成、SwiftUI 预览编译等)成本远高于同规模的 ObjC 工程;用 ObjC 写一个“什么都不做”的哑元 App,能把导出前的构建时间压到最低。
对照整个仓库——Mac Mouse Fix 主应用和 Helper 都是 Swift/ObjC 混编的大型 Target(参见 App/ 与 Helper/ 目录),导出时若不得不构建它们,代价显然可观。哑元 Target 用纯 ObjC 就是针对这一开销的刻意优化。
五、注意事项:构建哑元 Target 时的三个坑
Readme 还记录了搭建过程中的实战经验(源自 mac-mouse-fix-website 仓库中同用途的xcode-dummy-target的教训,可参看 Various Notes/Localization Notes.md 了解本项目本地化工作流的更多背景):
- 必须禁用
MainMenu.xib的本地化:否则该 nib 的本地化变体会作为资源被导出进.xcloc,污染导出产物; - 必须手动添加 Info.plist:Readme 强调需要“manually add an Info.plist file and remove the localizable keys”。本项目正是这样做的——XCStringsDummyApp-Info.plist 只保留了
CFBundleIdentifier、NSMainNibFile、NSPrincipalClass、CFBundleExecutable、CFBundlePackageType等启动必需键,并全部用$(...)构建设置变量取值,完全没有CFBundleDisplayName、CFBundleName这类可本地化键; - 默认的本地化键会泄漏进
.xcloc:若不按上面两步处理,Xcode 生成的本地化键会出现在.xcloc文件中,需要事后清理,不如一开始就规避。
六、已知问题:为什么导出时总是构建 Mac Mouse Fix 主 Target?
Readme 在 “Questions” 一节记录了一个截至 2025 年 9 月仍未解决的疑惑:
Product > Export Localizations...always builds the Mac Mouse Fix target, which is probably slowest part of the export. But why does it do that? Why not the other targets? Is there a build-setting to turn this off? Mysterious.
即:执行导出命令时,Xcode总是会构建 Mac Mouse Fix 主应用 Target——这通常是整个导出流程中最慢的部分。而哑元 Target 本身设计为纯 ObjC 空壳,恰恰是为了让“导出必须构建的 Target”尽量轻量。主 Target 被无故构建、而其他 Target(如 Helper)却不被构建的现象,从源码结构看暂时没有明显的构建设置可以解释,Readme 将其定性为 “Mysterious”。如果你在自建哑元 Target 时也遇到类似的“多余构建”,这属于 Xcode 行为层面的已知坑,值得单独排查。
七、总结:哑元 Target 模式的价值
XCStringsDummyApp 为 macOS 工程提供了一种可复制的本地化工程模式:
- 把需要被 Xcode 导出、但不应进入产品 bundle的
.xcstrings集中挂载到一个专用哑元 Target; - 用
LOCALIZATION_EXPORT_SUPPORTED = NO屏蔽界面资源导出,用纯 ObjC 实现压缩构建成本; - 通过
xcodebuild -exportLocalizations或 Xcode 菜单的Export Localizations...一次性产出包含这些字符串表的.xcloc。
对任何多 Target、且同时维护“编译型”与“非编译型”字符串表的 macOS 项目,这一模式都能直接迁移使用。相关源码与配置均可在仓库中按路径查阅:XCStringsDummyApp/Readme.md、XCStringsDummyApp/main.m、XCStringsDummyApp/XCStringsDummyApp-Info.plist、Mouse Fix.xcodeproj/project.pbxproj,以及被挂载导出的字符串表目录 Localization/Strings/。
- 桌面应用
- 系统编程
【免费下载链接】mac-mouse-fix
Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad!
相关推荐
4-ZERO-3工具完全指南:从入门到精通的403/401绕过技术
4 ZERO 3工具完全指南:从入门到精通的403/401绕过技术 4 ZERO 3是一款功能强大的403/401绕过工具,通过自动化的Bash脚本集成了多种绕
Parallelformers基准测试报告:在不同硬件配置下的性能表现对比
Parallelformers基准测试报告:在不同硬件配置下的性能表现对比 Parallelformers作为一款高效的模型并行化工具包,专为大规模语言模型的部
彻底解决Mac Mouse Fix设备配置冲突:让你的鼠标设置不再"打架"
彻底解决Mac Mouse Fix设备配置冲突:让你的鼠标设置不再"打架" 你是否遇到过这样的情况:在Mac上安装了Mac Mouse Fix后,鼠标设置时而正
桌面应用系统编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考