用 PlistCS
读取 XML 和二进制 PList 最省事
直接上结论:C# 没有原生 PList 支持,
PlistCS是目前最轻量、兼容性最好、能同时处理 XML 和二进制格式的开源库。它不依赖 macOS 或 .NET Core 特定运行时,.NET Framework 4.6+ 和 .NET 5/6/7/8 都能跑。
常见错误是硬啃 Apple 官方文档自己解析二进制格式——
NSKeyedArchiver生成的不是标准 PList,而
CFBinaryPlist格式又没公开完整规范,极易在字节对齐、浮点编码、日期偏移上翻车。 安装:
dotnet add package PlistCS(NuGet) 它自动识别文件头:
bplist00→ 二进制;
<?xml或
/code> → XML不支持
NSKeyedArchiver序列化产物(那种带
$class、
$classes的),那是另一套序列化机制,不是 PList
PlistParser.Parse
怎么用才不崩
别直接传路径字符串进去——
PlistParser.Parse接收的是
Stream或
byte[],传错类型会抛
NullReferenceException或静默返回空字典。
典型场景:读取 macOS 的
Info.plist或 iOS 导出的
Manifest.plist。这些文件可能带 BOM、换行不一致,但
PlistParser.Parse内部已处理,你只需确保流可读且未被释放。 正确写法:
var dict = PlistParser.Parse(File.OpenRead("Info.plist"));
错误写法:PlistParser.Parse("Info.plist")(编译不过)或 PlistParser.Parse(File.ReadAllText(...))(类型不匹配) 返回值是
IDictionary<string object></string>,嵌套结构里
object可能是
string、
DateTime、
long、
bool、
IDictionary<string object></string>或
IList<object></object>,需运行时判断
遇到 Invalid binary plist header
错误怎么办
这通常不是文件损坏,而是你把非 PList 文件当 PList 读了——比如误读了
embedded.mobileprovision(那是 PKCS#7 签名数据)或
AppIcon20x20@2x.png(图片),它们开头也可能是乱码,但根本不是 PList。
更隐蔽的情况:某些工具导出的“PList”其实是 JSON 伪装的(比如部分配置管理平台),或者用了 UTF-16 编码但没写 BOM,XML 解析器会卡在第一个字符。
先用命令行确认:file Info.plist(macOS/Linux)或看十六进制头:
bplist00(二进制)、
3C 3F 78 6D 6C(<?xml ) 如果头是
6A 73 6F 6E(json),别用
PlistParser,换
System.Text.Json二进制 PList 若含自定义类型(如
CFTypeRef子类),
PlistCS会跳过并记录警告,不会崩溃,但对应 key 的 value 为
null
从 IDictionary<string object></string>
安全取值的坑
很多人写
dict["CFBundleIdentifier"].ToString()就跑,结果遇到 key 不存在、值为
null、或值其实是
NSNumber映射的
long却强转
string,直接
NullReferenceException或格式错乱。
特别是
CFBundleVersion可能是整数(iOS 早期)或字符串(现代),
UIBackgroundModes是数组,
NSLocationWhenInUseUsageDescription是字符串——类型不统一是常态。 安全取字符串:
dict.TryGetValue("CFBundleIdentifier", out var idObj) && idObj is string id ? id : null
取整数版本号:dict.TryGetValue("CFBundleVersion", out var vObj) && int.TryParse(vObj?.ToString(), out var ver) ? ver : 0
取数组并遍历:if (dict.TryGetValue("UIBackgroundModes", out var modesObj) && modesObj is IList<object> modes)</object>
二进制 PList 里的日期会被自动转成
DateTime(UTC),但 XML PList 里是 ISO 8601 字符串,
PlistCS统一做了转换,这点不用额外处理——但如果你手动改过源码或用了旧版,就得自己 parse。
