Highlight
Apple 设备管理团队的 Cyrus Daboo 全面介绍了声明式设备管理(Declarative Device Management)在 2022 年的扩展。去年 WWDC 21 首次引入时仅支持 iOS 的用户注册,今年扩展到所有 MDM 注册类型、所有平台(iOS、macOS、tvOS),并大幅增强了状态报告和谓词系统。
核心内容
移动设备管理(MDM)服务端过去经常要轮询设备。
一个典型例子是密码策略。服务端先下发密码策略,再不断查询设备,等待用户把密码改到合规状态。只有等到下一次轮询确认合规,服务端才敢下发 Wi-Fi 或 VPN 这类敏感配置。
声明式设备管理(Declarative Device Management)把这段业务逻辑放到设备上。设备根据自己的状态重新计算激活条件,主动上报变化,服务端变成更轻量的反应式系统。(00:37)
WWDC22 的更新集中在三件事:扩大平台和注册类型覆盖范围,增加状态报告项目,增强谓词(predicate)系统。(03:46)
详细内容
覆盖范围扩展到所有 MDM 平台
(04:02)声明式设备管理在 WWDC21 首次推出时,只支持 iOS 的用户注册。2022 年,它扩展到 MDM 支持的每一种注册类型:自动设备注册、基于描述文件的注册,以及基于描述文件和账户的用户注册。
它也来到 Shared iPad、macOS Ventura 和 tvOS 16。只要操作系统支持,同一套 declarations 和 status 模型可以用于 iOS、macOS 和 tvOS。
macOS 和 Shared iPad 各有 device channel 和 user channel。要在某个通道使用声明式管理,服务端必须在对应通道发送 DeclarativeManagement 命令。状态报告也按通道分别生成,服务端需要分别监听。
macOS / Shared iPad
├─ device channel -> send DeclarativeManagement -> monitor device status report
└─ user channel -> send DeclarativeManagement -> monitor user status report
关键点:
device channel管理设备级状态。user channel管理特定用户的状态。DeclarativeManagement要按通道分别启用。- status report 也按通道分别产生,不能只监听其中一个。
密码状态让 Wi-Fi 配置自动激活
(07:41)这场 session 增加了两个密码相关状态项:passcode.is-compliant 和 passcode.is-present。它们是布尔值,对应传统 MDM 查询中能拿到的密码状态。
{
"management": {
"client-capabilities": {
"supported-payloads": {
"status-items": [
"passcode.is-compliant",
"passcode.is-present"
]
}
}
}
}
关键点:
management.client-capabilities描述设备支持哪些声明式能力。supported-payloads.status-items列出可订阅的状态项。passcode.is-compliant表示当前密码是否符合 MDM profiles 或 configurations 下发的所有密码策略。passcode.is-present表示设备是否已有密码。
(08:05)Apple 给出的场景是安全网络配置。服务端可以同时发送强密码策略和 Wi-Fi 配置,把 Wi-Fi 配置绑定到一个依赖 passcode.is-compliant 的 activation predicate。
开始时,密码通常还不合规,谓词为 false,Wi-Fi 不会激活。用户改好密码后,设备重新计算 activations,谓词变成 true,Wi-Fi 自动激活。这个过程不需要服务端轮询,甚至可以在设备暂时离线时完成。
send passcode policy configuration
send Wi-Fi configuration with activation predicate
if passcode.is-compliant == false:
keep Wi-Fi inactive
when user updates passcode:
reevaluate activation predicates
activate Wi-Fi configuration
send status report to server
关键点:
- 这是概念流程,session 没有给出完整 Wi-Fi declaration JSON。
- 服务端一次性下发密码策略和 Wi-Fi 配置。
- 设备负责监听密码状态变化并重新计算谓词。
- 服务端通过状态报告知道配置何时激活。
账户状态用数组增量上报
(10:52)账户状态新增了八个 status items,覆盖 CalDAV、CardDAV、Exchange、Google、LDAP、incoming mail、outgoing mail 和 subscribed calendar。
{
"status-items": [
"account.list.caldav",
"account.list.carddav",
"account.list.exchange",
"account.list.google",
"account.list.ldap",
"account.list.mail.incoming",
"account.list.mail.outgoing",
"account.list.subscribed-calendar"
]
}
关键点:
account.list.*只报告由 configurations 安装的账户。- 手动创建的账户不会出现在这些状态里。
- 通过 MDM profiles 安装的账户也不会出现在这里。
- incoming mail 和 outgoing mail 分开报告。
(11:19)每个账户状态项返回对应账户类型的 JSON 对象。identifier 是数组对象内的唯一标识,declaration-identifier 对应安装该账户的 configuration identifier。
{
"identifier": "592D763E-C15B-44F8-A1FC-F88EB1901646",
"declaration-identifier": "BF8FD199-467B-4BA5-886D-D82B7849E517",
"hostname": "mail.example.com",
"port": 443,
"username": "user01",
"is-mail-enabled": true,
"are-notes-enabled": false
}
{
"identifier": "592D763E-C15B-44F8-A1FC-F88EB1901646",
"declaration-identifier": "BF8FD199-467B-4BA5-886D-D82B7849E517",
"calendar-url": "https://holidays.example.com/country/US.ics",
"username": "user01",
"is-enabled": true
}
关键点:
identifier用来在同一个状态数组里定位对象。declaration-identifier让服务端把状态对象关联回安装账户的 configuration。hostname、port、is-mail-enabled、are-notes-enabled是 mail 账户状态里的字段。calendar-url、is-enabled是 subscribed calendar 状态里的字段。- 服务端必须接受未来系统版本可能新增的未知 key。
(12:11)数组值按对象增量上报。第一次订阅时,设备发送完整账户列表;新增账户时,只报告新增对象;账户状态改变时,只报告变化对象;移除账户时,报告带有 removed: true 的对象。
{
"identifier": "592D763E-C15B-44F8-A1FC-F88EB1901646",
"removed": true
}
关键点:
identifier匹配服务端已有对象。removed: true表示服务端应删除本地保存的该对象状态。- 增量上报减少了服务端和设备之间传输的状态体积。
- 设备会聚合最多约一分钟内的状态变化,以避免性能问题。
MDM App 状态消除安装进度轮询
(17:13)MDM 服务端常常要知道 App 是否安装成功、是否被用户移除。过去可以用 InstalledApplicationList 或 ManagedApplicationList 命令轮询设备。新增的 mdm.app status item 让设备主动上报 MDM 安装的 App 状态。
{
"management": {
"client-capabilities": {
"supported-payloads": {
"status-items": [
"mdm.app"
]
}
}
}
}
关键点:
mdm.app是一个数组状态项。- 每个数组对象代表一个由 MDM server 安装的 App。
- 即使在 supervised devices 上,它也只报告由 MDM 安装的 App。
- 数组对象按前面账户状态同样的规则增量上报。
(17:35)App 状态报告里,identifier 是 bundle identifier,state 表示当前安装阶段。
{
"StatusItems": {
"mdm": {
"app": [
{
"identifier": "com.apple.Pages",
"name": "Pages",
"version": "7358.0.134",
"short-version": "12.0",
"external-version-id": "844362702",
"state": "managed"
}
]
}
},
"Errors": []
}
关键点:
StatusItems.mdm.app是 MDM App 状态数组。identifier在这个状态里使用 App 的 bundle identifier。name是 App 名称。version、short-version、external-version-id对应ManagedApplicationList响应里的版本信息。state表示安装阶段,例如 session 中提到的prompting、installing、managed、managed-but-uninstalled。Errors为空数组表示该状态报告没有错误。
(18:18)安装流程里,用户注册设备需要用户批准安装 App。设备可以先上报 prompting,用户点击安装后上报 installing,安装完成后上报 managed。如果用户手动删除 App,设备上报 managed-but-uninstalled。服务端随后可发送 RemoveApplication 移除内部维护的管理状态。
谓词可以查询数组状态项
(20:40)activation predicate 使用 NSPredicate 字符串。WWDC22 增加的新语法把状态项名称放进 @status(...),旧语法继续兼容,但已经被标记为 deprecated。
(22:15)当状态项是数组时,可以用 SUBQUERY 查找符合条件的元素。下面的例子检查设备上是否存在 bundle identifier 为 com.example.app 且状态为 managed 的 MDM App。
SUBQUERY(@status(mdm.app),
$app,
($app.@key(identifier) == "com.example.app") AND ($app.@key(state) == "managed")
).@count == 1
关键点:
@status(mdm.app)引用mdm.app状态数组。$app是SUBQUERY遍历数组时使用的变量。$app.@key(identifier)读取数组对象里的identifierkey。$app.@key(state)读取数组对象里的statekey。.@count == 1表示恰好找到一个符合条件的对象。- 访问数组对象中的 key 时要使用
@keyextension term。
Management properties 把服务器逻辑变成设备属性
(24:10)服务端有时需要直接控制谓词计算。比如学校按教师角色分发配置:低年级或高年级 Wi-Fi、IT 管理员共享邮箱、体育教练日历。传统 MDM 往往要在设备分配给教师后逐个安装或移除 profiles。
WWDC22 新增 com.apple.management.properties declaration。服务端可以把自定义 JSON 属性写到设备上,再让 activation predicate 读取这些属性。
{
"management": {
"client-capabilities": {
"supported-payloads": {
"declarations": {
"management": [
"com.apple.management.properties"
]
}
}
}
}
}
关键点:
supported-payloads.declarations.management列出设备支持的 management declaration 类型。com.apple.management.properties是这场 session 新增的 declaration 类型。- 它让服务端设置可被谓词读取的任意 JSON 属性。
(24:40)management properties declaration 的 Payload 是服务端定义的 JSON 对象。值可以是字符串、数字、数组或对象。
{
"Type": "com.apple.management.properties",
"Identifier": "AAE09D73-6EF6-4F3B-9E15-11B0F86D5591",
"ServerToken": "AB4C5B91-3E08-4D4E-A9FF-1E44FE5BFDD4",
"Payload": {
"name": "Student One",
"age": 7,
"roles": ["grade1", "spanish"]
}
}
关键点:
Type指定 declaration 类型。Identifier是该 declaration 的标识。ServerToken用于服务端标识自己发送的版本。Payload.name、Payload.age、Payload.roles都由服务端定义。- 多个 management properties declarations 可以同时存在,但 key 应该保持唯一;重复 key 会导致谓词取值不可预测。
(24:53)activation predicate 用 @property(...) 读取这些属性。
{
"Type": "com.apple.activation.simple",
"Identifier": "076F928B-9D8E-4BA2-AD34-5655805C82D7",
"ServerToken": "4FFA91BF-85AE-4053-B8FE-B1C3E507A9CB",
"Payload": {
"StandardConfigurations": [
"3BBB4407-238A-44B1-ABB1-5E7AB95160E0"
]
},
"Predicate": "(@property(age) >= 18) AND (\"Grade12\" IN @property(roles))"
}
关键点:
Type表示这是一个 simple activation。Payload.StandardConfigurations指向要被激活的配置。Predicate读取 management properties。@property(age) >= 18检查age属性。"Grade12" IN @property(roles)检查roles数组里是否包含指定角色。
(27:24)学校场景的做法是先把完整 declarations 预置到设备上。设备分配给教师当天,服务端只发送一个包含教师角色的 management properties declaration。设备重新计算 activations,自动启用对应 Wi-Fi、邮箱或日历配置。
before assignment:
preload Wi-Fi, mail, calendar declarations
predicates are false on unassigned devices
on assignment day:
send one management properties declaration with teacher roles
reevaluate activations on device
activate matching configurations
when role changes:
update one management properties declaration
reevaluate activations again
关键点:
- 这是 session 描述的流程摘要,不是新的协议 API。
- 预加载 declarations 减少了高峰期逐个下发 profiles 的压力。
- 角色变化时,服务端只需要更新属性 declaration。
- 复杂服务器逻辑被压缩成设备上的简单状态变化。
核心启发
1. 做一个密码合规驱动的网络配置开关
- 做什么:把企业 Wi-Fi 或 VPN 配置绑定到密码合规状态。
- 为什么值得做:session 明确说明
passcode.is-compliant可以触发 activation predicate,避免服务端轮询。 - 怎么开始:订阅
passcode.is-compliant,把敏感网络配置放进依赖该状态的 activation,观察配置激活后的 status report。
2. 做一个账户安装状态面板
- 做什么:在 MDM 控制台展示由 configurations 安装的 mail、calendar、LDAP、Exchange 等账户状态。
- 为什么值得做:账户状态对象带有
declaration-identifier,服务端可以把状态直接关联到下发的 configuration。 - 怎么开始:订阅
account.list.mail.incoming、account.list.mail.outgoing、account.list.subscribed-calendar等状态项,按identifier合并增量报告。
3. 做一个 App 安装进度流
- 做什么:把 App 安装过程展示为
prompting、installing、managed、managed-but-uninstalled等状态变化。 - 为什么值得做:
mdm.app让设备主动上报 MDM 安装的 App 状态,减少InstalledApplicationList或ManagedApplicationList轮询。 - 怎么开始:启用声明式管理后订阅
mdm.app,用 bundle identifier 合并数组对象,把state映射成控制台状态。
4. 做一个角色驱动的学校设备分配流程
- 做什么:预加载配置,再用教师角色属性激活对应 Wi-Fi、邮箱和日历。
- 为什么值得做:
com.apple.management.properties可以把服务端角色逻辑变成设备上的 predicate 输入,适合开学日这类高峰场景。 - 怎么开始:设计唯一的
roles属性 key,用@property(roles)写 activation predicate,分配设备时只更新 management properties declaration。
5. 做一个状态数组增量同步器
- 做什么:为账户状态和 MDM App 状态实现通用的数组对象合并逻辑。
- 为什么值得做:session 说明数组值会按对象增量报告,新增、更新、删除都依赖
identifier。 - 怎么开始:以
identifier建索引;收到未知 identifier 时插入;收到已知 identifier 时更新;收到removed: true时删除。
关联 Session
- Meet declarative device management — WWDC21 首次介绍声明式设备管理的数据模型、声明、状态和设备主动管理思路。
- What’s new in managing Apple devices — WWDC22 设备管理总览,覆盖 Apple Configurator、identity 技术和 MDM protocol 更新。
- Explore Apple Business Essentials — 介绍面向小型企业的设备管理、支持、云存储、collections、apps 和 settings 工作流。
评论
GitHub Issues · utterances