docs-matrix-spec/locales/zh-Hans/client-server-api/modules/push.md
2025-04-20 16:13:37 +08:00

916 lines
No EOL
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 推送通知
```
+--------------------+ +-------------------+
Matrix HTTP | | | |
Notification Protocol | 应用开发者 | | 设备厂商 |
| | | |
+-------------------+ | +----------------+ | | +---------------+ |
| | | | | | | | | |
| Matrix 主服务器 +-----> 推送网关(Gateway)+------> 推送供应商 | |
| | | | | | | | | |
+-^-----------------+ | +----------------+ | | +----+----------+ |
| | | | | |
Matrix | | | | | |
客户端/服务器API + | | | | |
| | +--------------------+ +-------------------+
| +--+-+ |
| | <-------------------------------------------+
+---+ |
| | 供应商推送协议
+----+
移动设备或客户端
```
本模块增加了对推送通知的支持。主服务器会将事件的通知发送到用户配置的 HTTP 端点。用户也可以自定义多条规则,决定哪些事件会生成通知。这些规则全部存储并由用户的主服务器管理。这允许用户专属的推送设置在不同客户端应用之间复用。
上述图示显示了推送通知发送到手机时的流程,通知通过手机厂商(例如 Apple 的 APNS 或 Google 的 GCM进行提交。具体流程如下
1. 客户端应用登录到主服务器。
2. 客户端应用在其厂商的推送供应商处注册,并获得某种路由令牌。
3. 移动应用通过客户端/服务器 API 添加一个“推送者pusher并提供为该应用配置的特定推送网关的 URL同时提供从推送供应商获得的路由令牌。
4. 主服务器使用提供的 URL 向推送网关发送 HTTP 请求。推送网关将该通知中继给推送供应商,并附带发送推送通知所需的路由令牌及相关私密凭证。
5. 推送供应商将通知发送至设备。
本节相关术语定义如下:
推送供应商Push Provider
: 推送供应商是由设备厂商管理的服务,可以直接将通知发送到设备。例如 Google Cloud MessagingGCM和 Apple Push Notification ServiceAPNS都是推送供应商的例子。
推送网关Push Gateway
: 推送网关是接收主服务器 HTTP 事件通知并将其转发给其他协议(如 iOS 设备的 APNS 或 Android 设备的 GCM的服务器。客户端在设置 Pusher 时,会告知主服务器该将通知发送至哪个推送网关。
推送者Pusher
: Pusher 是主服务器上负责管理并发送 HTTP 通知给用户的工作进程。每个用户可以有多个 pusher每组装置对应一个。
推送规则Push Rule
: 推送规则是一条声明了在什么*条件*下事件会被发送到推送网关,以及通知应该如何呈现的规则。这些规则储存在用户的主服务器上。用户可通过客户端/服务器 API 手动配置、创建与查看这些规则。
推送规则集Push Ruleset
: 推送规则集*根据某些标准限定某组规则的作用范围*。比如,某些规则只针对来自特定发信人的消息、特定聊天室、或作为默认规则。推送规则集包含了全部作用域与规则集合。
#### 推送规则
推送规则是一条声明了在什么*条件*下事件会被发送到推送网关以及通知该如何呈现的规则。推送规则有多种“类型kind每条规则都有相应的优先级。每条推送规则必须包含 `kind``rule_id``rule_id` 是在该类型和作用域内部唯一的字符串:同种类型但属于不同设备的规则之间,`rule_id` 并不要求全局唯一。依据 `kind` 类型,规则可以具有额外的键。
不同的 `kind` 类型按如下顺序检查:
1. **Override 规则 (`override`)。**
最高优先级的规则,由用户配置作为覆盖项。
2. **内容专属规则 (`content`)。**
针对匹配某些模式的消息配置行为。内容规则包含一个参数 —— `pattern`,提供待匹配的[glob 风格模式](/appendices#glob-style-matching)。
该匹配大小写不敏感,必须匹配消息内容的 `content.body` 属性中任何以单词边界起止的子串。单词边界指文本的起始或结尾,或者非 `[A-Z]`, `[a-z]`, `[0-9]`, `_` 集合中的任意字符。大小写不敏感的具体实现由主服务器定义。
3. **房间专属规则 (`room`)。**
更改某个房间内所有消息的通知行为。房间规则的 `rule_id` 总为其作用房间的 ID。
4. **发信人专属规则 (`sender`)。**
针对某个 Matrix 用户 ID 发出的消息配置通知行为。发信人规则的 `rule_id` 总为该用户的 Matrix ID。
5. **Underride 规则 (`underride`)。**
`override` 规则作用相同,但其优先级低于 `content``room``sender` 规则。
同一 `kind` 的规则可以指定顺序优先级,用于确定在多条规则命中时选择哪一条。例如,规则 A 匹配“tea”规则 B 匹配“time”则消息 “It's time for tea” 会被两条规则匹配,随后按顺序决定实际生效的规则。只有优先级最高的规则的 `actions` 会被发送给推送网关。
每条规则可以启用或禁用。被禁用的规则永不匹配。如果没有任何规则匹配某事件,主服务器不得为该事件通知推送网关。主服务器也不得为用户自己发送的事件通知推送网关。
##### 动作Actions
所有规则都有一个关联的 `actions` 动作列表。动作决定对于匹配的事件,通知是否被送达及如何送达。定义如下:
`notify`
: 为每个匹配事件产生推送通知。
`set_tweak`
: 设置发送通知请求给推送网关时 `tweaks` 字典键中的一项。格式为字典对象,`set_tweak` 为要设置的调整项名,如果需要还可带有 `value` 指定其值。
已定义以下调整项:
`sound`
: 字符串,表示此通知到达时播放的声音。`default` 表示播放默认提示音。设备也可根据实际选择如振动等其他告警方式。
`highlight`
: 布尔值,是否应在界面中高亮展示这条消息。通常会以不同颜色/样式突出消息,或调整 UI 以特别提示发生消息的房间。如果给定了没有显式值的 `highlight` 调整项,其值视为 `true`。若未指定则为 `false`
调整项会透明地通过主服务器传递,客户端应用与推送网关可约定自定义调整项。例如,可指定在移动设备上如何闪烁通知灯。
无参数的动作用字符串表示,否则用以动作名为键、相关参数为其他键的字典表示,例如:`{ "set_tweak": "sound", "value": "default" }`
###### 历史动作说明
早期 Matrix 规范包含 `dont_notify``coalesce` 动作。客户端和主服务器必须忽略这些动作,比如遇到时应从动作数组中剔除。因此,包含 `["dont_notify"]` 的规则应等效于动作数组为空的规则。
##### 条件Conditions
`override``underride` 规则可以有“条件”列表。事件必须满足所有条件,该规则才会匹配。若规则无任何条件,则总是匹配。
无法识别的条件不得匹配任何事件,相当于禁用该规则。
`room``sender``content` 规则不以条件列表的方式定义,而是有预定义条件。房间和发信人规则中,`rule_id` 的内容决定其行为。
以下条件类型已定义:
**`event_match`**
对事件某属性用 glob 模式匹配。参数:
- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`
- `pattern`[glob 风格模式](/appendices#glob-style-matching)。
匹配大小写不敏感,必须匹配 `key` 指定属性的整个值(但 `content.body` 见下文)。大小写不敏感的实现由主服务器定义。
如事件中 `key` 指定属性完全不存在或不是字符串,即便 `pattern``*`,条件也不匹配。
{{% boxes/note %}}
例如,若 `key``content.topic``pattern``lunc?*`,其事件如下将会匹配:
```json
{
"content": {
"topic": "Lunch plans",
},
"event_id": "$143273582443PhrSn:example.org",
"room_id": "!636q39766251:example.com",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.topic"
}
```
其它能匹配的 `topic` 值有:
* `"LUNCH"`(大小写不敏感,`*` 可匹配零个字符)
以下 `topic` 不匹配:
* `" lunch"`(前导空格)
* `"lunc"``?` 必须匹配一个字符)
* `null`(不是字符串)
{{% /boxes/note %}}
特殊情况:若 `key``content.body``pattern` 必须匹配属性值任一单词边界起止的子串。单词边界指值的起止或非 `[A-Z]``[a-z]``[0-9]``_` 集合的字符。
{{% boxes/note %}}
例如,`key` 若为 `content.body``pattern``ex*ple`,则如下消息会匹配:
```json
{
"content": {
"body": "An example event."
},
"event_id": "$143273976499sgjks:example.org",
"room_id": "!636q39766251:example.com",
"sender": "@example:example.org",
"type": "m.room.message"
}
```
其它匹配 `body` 值有:
* `"exple"`(模式可匹配 body 起止)
* `"An exciting triple-whammy"`(模式可跨多单词,且 `-` 被视为分隔符)
{{% /boxes/note %}}
{{% boxes/warning %}}
注意,`state_key` 没有默认隐式条件。即,针对只匹配状态事件的推送规则,必须明确指定对 `state_key` 的条件。
例如,见下方默认规则
[`.m.rule.tombstone`](#mruletombstone)。
{{% /boxes/warning %}}
**`event_property_is`**
对事件属性值进行精确匹配。参数:
- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`
- `value`:要匹配的值。
匹配为精确等值仅支持非复合canonical JSON类型字符串、区间 `[-(2**53)+1, (2**53)-1]` 内的整数、布尔值和 `null`
`key` 指定属性不存在,或类型不是字符串、整数、布尔或 `null`,条件不匹配。
{{% boxes/note %}}
例如,若 `key``content.m\.federate``value``true`,事件如下匹配:
```json
{
"content": {
"creator": "@example:example.org",
"m.federate": true,
"predecessor": {
"event_id": "$something:example.org",
"room_id": "!oldroom:example.org"
},
"room_version": "1"
},
"event_id": "$143273582443PhrSn:example.org",
"room_id": "!636q39766251:example.com",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.create"
}
```
下列 `m.federate` 值不匹配:
* `"true"`(类型不同,字符串)
* `1`(不进行类型转换)
{{% /boxes/note %}}
**`event_property_contains`**
如事件某数组属性*精确包含*特定值则匹配。参数:
- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`
- `value`:要匹配的值。
仅当数组元素为非复合 canonical JSON 类型(字符串、上述区间内整数、布尔、`null`)时有效。其他类型将被忽略。
`key` 指定属性不存在,或不是数组,则条件不匹配。
{{% boxes/note %}}
例如,若 `key``content.alt_aliases``value``"#myroom:example.com"`,如下事件会匹配:
```json
{
"content": {
"alias": "#somewhere:localhost",
"alt_aliases": [
"#somewhere:example.org",
"#myroom:example.com"
]
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.canonical_alias",
"unsigned": {
"age": 1234
}
}
```
下列 `alt_aliases` 值不匹配:
* `":example.com"`(部分匹配不通过)
{{% /boxes/note %}}
**`contains_display_name`**
匹配 `content.body` 含有房间内该用户当前显示昵称的消息。因显示昵称可能变化,维护对应规则较难,故单独为此设一条件。该条件无参数。
**`room_member_count`**
匹配房间当前成员数。参数:
- `is`:一个支持可选前缀的十进制整数,前缀包括 `==``<``>``>=``<=` 。如 `<` 匹配成员数*小于*给定数字,依此类推。缺省无前缀时为 `==`
**`sender_notification_permission`**
结合房内当前权限设置,确保事件发送者权限足够以触发通知。
参数:
- `key`:字符串,指定需触发何种类型通知时发信人需具备的权限级别,如 `room`。详见
[m.room.power\_levels](#mroompower_levels) 事件结构。该 `key` 用于根据 power level 对象内容查找通知类型对应权限级别。
#### 预定义规则
主服务器可指定“服务器默认规则”。该类规则优先级低于“用户自定义规则”,唯一例外是 `.m.rule.master`,它总是所有规则中最高的。所有服务器默认规则的 `rule_id` 必须以点(".")开头以便区分。以下为规定的服务器默认规则:
##### 默认 Override 规则
**`.m.rule.master`**
匹配所有事件。启用后可关闭所有推送通知。不同于其它服务器默认规则,此规则始终优先级最高,连用户自定义规则都排在其后。默认禁用。
定义:
```json
{
"rule_id": ".m.rule.master",
"default": true,
"enabled": false,
"conditions": [],
"actions": []
}
```
**`.m.rule.suppress_notices`**
匹配 `msgtype``notice` 的消息。
定义:
```json
{
"rule_id": ".m.rule.suppress_notices",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.msgtype",
"pattern": "m.notice"
}
],
"actions": []
}
```
**`.m.rule.invite_for_me`**
匹配针对该用户的新房间邀请。
定义:
```json
{
"rule_id": ".m.rule.invite_for_me",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "[the user's Matrix ID]"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
```
**`.m.rule.member_event`**
匹配任意 `m.room.member_event`
定义:
```json
{
"rule_id": ".m.rule.member_event",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
}
],
"actions": []
}
```
<a id="_m_rule_is_user_mention"></a> **`.m.rule.is_user_mention`**
{{% added-in v="1.7" %}}
匹配在 `m.mentions` 属性下 `user_ids` 包含用户 Matrix ID 的任意消息。
定义:
```json
{
"rule_id": ".m.rule.is_user_mention",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_property_contains",
"key": "content.m\\.mentions.user_ids",
"value": "[the user's Matrix ID]"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
```
<a id="_m_rule_contains_display_name"></a> **`.m.rule.contains_display_name`**
{{% changed-in v="1.7" %}}
`v1.7` 起,该规则已废弃,**仅在事件未含 [`m.mentions` 属性](#definition-mmentions) 时启用**。
匹配内容含有用户当前房间显示昵称的消息。
定义:
```json
{
"rule_id": ".m.rule.contains_display_name",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "contains_display_name"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
```
<a id="_m_rule_is_room_mention"></a> **`.m.rule.is_room_mention`**
{{% added-in v="1.7" %}}
匹配拥有相应权限、`m.mentions` 属性中的 `room` 字段为 `true` 的发信人消息。
定义:
```json
{
"rule_id": ".m.rule.is_room_mention",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_property_is",
"key": "content.m\\.mentions.room",
"value": true
},
{
"kind": "sender_notification_permission",
"key": "room"
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
```
<a id="_m_rule_roomnotif"></a> **`.m.rule.roomnotif`**
{{% changed-in v="1.7" %}}
自 v1.7 起,该规则已废弃,**仅在事件未含 [`m.mentions` 属性](#definition-mmentions) 时启用**。
匹配拥有权限且内容含有 `@room` 字符串(需全房通知)的消息。
定义:
```json
{
"rule_id": ".m.rule.roomnotif",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.body",
"pattern": "@room"
},
{
"kind": "sender_notification_permission",
"key": "room"
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
```
**<a id="mruletombstone"></a>`.m.rule.tombstone`**
匹配所有类型为 `m.room.tombstone` 的状态事件。用于通知房间升级,效果类似于 `@room` 通知。
定义:
```json
{
"rule_id": ".m.rule.tombstone",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.tombstone"
},
{
"kind": "event_match",
"key": "state_key",
"pattern": ""
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
```
**<a id="mrulereaction"></a>`.m.rule.reaction`**
{{% added-in v="1.7" %}}
匹配所有类型为 `m.reaction` 的事件。用于抑制 [`m.reaction`](#mreaction) 事件的通知。
定义:
```json
{
"rule_id": ".m.rule.reaction",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.reaction"
}
],
"actions": []
}
```
**`.m.rule.room.server_acl`**
{{% added-in v="1.4" %}}
抑制对 [`m.room.server_acl`](#mroomserver_acl) 事件的通知。
定义:
```json
{
"rule_id": ".m.rule.room.server_acl",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.server_acl"
},
{
"kind": "event_match",
"key": "state_key",
"pattern": ""
}
],
"actions": []
}
```
**`.m.rule.suppress_edits`**
{{% added-in v="1.9" %}}
抑制与[事件替换](#event-replacements)相关的通知。
定义:
```json
{
"rule_id": ".m.rule.suppress_edits",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_property_is",
"key": "content.m\\.relates_to.rel_type",
"value": "m.replace"
}
],
"actions": []
}
```
##### 默认 Content 规则
<a id="_m_rule_contains_user_name"></a> **`.m.rule.contains_user_name`**
{{% changed-in v="1.7" %}}
自 v1.7 起,该规则已废弃,**仅当事件无 [`m.mentions` 属性](#definition-mmentions) 时启用**。
匹配内容包含用户 Matrix ID 本地部分(以单词边界分隔)的消息。
定义(作为 `content` 规则):
```json
{
"rule_id": ".m.rule.contains_user_name",
"default": true,
"enabled": true,
"pattern": "[the local part of the user's Matrix ID]",
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
```
##### 默认 Underride 规则
**`.m.rule.call`**
匹配所有传入 VOIP 呼叫事件。
定义:
```json
{
"rule_id": ".m.rule.call",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.call.invite"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "ring"
}
]
}
```
**`.m.rule.encrypted_room_one_to_one`**
匹配发送至仅有两名成员的加密房间内的任意加密事件。不同于普通推送规则,加密后事件无法基于内容匹配,故此规则表现为“全匹配”或“不匹配” —— 若为 1:1 房间内所有加密事件都匹配,否则全不匹配。
定义:
```json
{
"rule_id": ".m.rule.encrypted_room_one_to_one",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "room_member_count",
"is": "2"
},
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
```
**`.m.rule.room_one_to_one`**
匹配仅有两名成员的房间内任意消息。
定义:
```json
{
"rule_id": ".m.rule.room_one_to_one",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "room_member_count",
"is": "2"
},
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.message"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
```
**`.m.rule.message`**
匹配所有聊天消息。
定义:
```json
{
"rule_id": ".m.rule.message",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.message"
}
],
"actions": [
"notify"
]
}
```
**`.m.rule.encrypted`**
匹配所有加密事件。由于加密,事件内容不能被常规匹配,本规则表现为组房内所有加密事件全匹配或全不匹配。
定义:
```json
{
"rule_id": ".m.rule.encrypted",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify"
]
}
```
#### 推送规则API
客户端可通过以下 API 全局或针对各设备获取、添加、修改、删除推送规则。
{{% http-api spec="client-server" api="pushrules" %}}
#### 推送规则:事件
当用户更改推送规则,会向所有客户端在下次 [`/sync`](#get_matrixclientv3sync) 请求的 `account_data` 部分发送 `m.push_rules` 事件。
事件内容为用户当前的全部推送规则。
{{% event event="m.push_rules" %}}
##### 示例
为 ID 为 `!dj234r78wl45Gh4D:matrix.org` 的房间创建禁止通知的规则:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \
'{
"actions" : []
}'
禁止为用户名为 `@spambot:matrix.org` 的用户发送通知:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \
'{
"actions" : []
}'
为所有消息内容含 “cake” 的消息始终通知,并设置专用提示音(规则 ID 为 `SSByZWFsbHkgbGlrZSBjYWtl`
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \
'{
"pattern": "cake",
"actions" : ["notify", {"set_tweak":"sound", "value":"cakealarm.wav"}]
}'
添加规则:禁止通知以 “cake” 开头、“lie” 结尾的消息,并优先级高于上一条规则:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \
'{
"pattern": "cake*lie",
"actions" : ["notify"]
}'
为成员数不超过 10 的房间内含有 “beer” 的消息添加自定义通知音(优先级高于 room, sender, content 规则):
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \
'{
"conditions": [
{"kind": "event_match", "key": "content.body", "pattern": "beer" },
{"kind": "room_member_count", "is": "<=10"}
],
"actions" : [
"notify",
{"set_tweak":"sound", "value":"beeroclock.wav"}
]
}'
#### 客户端行为
客户端必须先配置 Pusher才能接收推送通知。具体 API 如下所述。
{{% http-api spec="client-server" api="pusher" %}}
##### 列出通知
客户端可获取已收到通知的事件列表,帮助用户查看收到的重要消息摘要。
{{% http-api spec="client-server" api="notifications" %}}
##### 接收通知
服务器必须在客户端的 [`/sync`](#get_matrixclientv3sync) 流中包含未读通知数,并随计数变化更新。通知判定依赖于事件适用的推送规则。
对于加密事件,主服务器仅有限访问事件内容,推送规则需由客户端在*解密后*处理,客户端收到每条事件都需执行推送规则。这可能导致需修正从主服务器收到的未读通知数。
##### 标记通知为已读
当用户更新已读回执(无论使用 API 还是通过发送事件),在该事件之前(含自身)的通知必须被标记为已读。具体被影响的事件取决于是否使用了[线程已读回执](#threaded-read-receipts)。用户可同时发送 `m.read``m.read.private` 回执,两者都可清除通知。
如同一房间内用户同时拥有 `m.read``m.read.private`,应取更“新”或“更靠前”的回执为判断依据。例如,若事件 A、B、C、D 按时间升序排列,`m.read` 回执在事件 C`m.read.private` 在事件 A则用户已读至 C。如果 `m.read.private` 更新为 B 或 C通知状态不变`m.read` 回执仍领先);如 `m.read.private` 更新为 D则用户已读到 D`m.read` 落后于 `m.read.private`)。
{{% added-in v="1.4" %}} 处理线程已读回执时,服务器需将通知数分配至各线程(主时间线看作一条线程)。判定事件属于哪个线程,服务器应按[event 关系](#forming-relationships-between-events)查找,直到遇到 `m.thread` 关系定义的根事件(详见[线程模块](#threading)),但不建议无限遍历。建议实现时至多跳 3 层,未找到线程即视为事件不属于线程。主要确保后续事件如 `m.reaction` 被正确划分为某线程。
#### 服务器行为
主服务器收到新事件时,为房间内每位本地用户(不含发信人)处理推送规则,结果可能为:
* 生成新的未读通知数;
* 向配置的推送网关发起请求。
新事件导致的未读通知数必须与事件本身一起在同一次 [`/sync`](#get_matrixclientv3sync) 响应中返回。
#### 推送网关行为
##### APNS 推荐
APNS 推送通知的具体格式灵活,由客户端应用与其推送网关约定。由于 APNS 需求发送者具有应用开发者的私钥,每个应用需有专属推送网关。推荐如下:
- APNS Token 基于 base64 编码,直接用于 pushkey。
- 正式环境和沙箱环境使用不同的 app_id 。
- APNS 推送网关不必等待 APNS 网关返回错误再响应;可记录失败,并在下次推送相同 pushkey 时返回 'rejected'。
#### 安全性注意事项
客户端需指定用于发送事件通知的推送网关 URL 。此 URL 必须为 HTTPS*绝不能*是 HTTP。
推送通知会经过推送供应商,消息内容应尽量不随推送本体一起发送。推送网关应发送 "sync" 指令,指导客户端直接向主服务器获取新事件。