# 消息 (/zh-CN/api-reference/rtm/swift/message)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

收发消息是 RTM 服务的基础功能之一，任何使用 RTM 服务发送的消息将会在 100 ms 以内送达到任何一个在线订阅用户端上，你可以一次只给一个人发消息，也可以一次给多人广播消息，这取决于你的使用方式。

RTM 有 3 种频道类型，分别是 Message Channel、User Channel 和 Stream Channel。3 种频道类型的主要区别如下：

- Message Channel：实时频道，消息通过频道传递，可扩展性强。本地用户可以调用 `publish` 方法，将 `channelType` 参数设为 `message`，并将 `channelName` 参数设为频道名称，即可在频道中发送消息。远端用户可以调用 `subscribe` 方法订阅频道并接收消息。
- User Channel：向指定用户发送点对点消息。本地用户可以调用 `publish` 方法，将 `channelType` 参数设为 `user`，并将 `channelName` 参数设为对方的 `userId`，即可向指定用户发送消息。指定用户可以通过 `didReceiveMessageEvent` 事件通知来接收消息。
- Stream Channel：流传输频道，用户需要先加入频道，然后加入 Topic，消息通过 Topic 传递。本地用户可以调用 `publishTopicMessage` 方法在 Topic 中发送消息，远端用户可以调用 `subscribeTopic` 方法订阅 Topic 并接收消息。

本文介绍如何在 Message Channel 和 User Channel 中收发消息。

## publish [#publish]

### 接口描述 [#接口描述]

你可以直接调用 `publish` 方法向订阅该频道的所有在线用户发送消息。即使没有订阅频道，也能在频道中发送消息。

:::info[信息]
以下做法可有效提升消息收发的可靠性：

- 消息负载限制在 32 KB 以内，否则发送会失败。
- 向单个频道发送消息的速率上限为 60 QPS。如果发送速率超限，将会有部分消息被丢弃。在满足要求的情况下，速率越低越好。
:::

成功调用该方法后，订阅了该频道并开启了事件监听的其他用户会通过 `didReceiveMessageEvent` 收到这条消息，详见[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)。

### 接口方法 [#接口方法]

你可以通过以下方式调用 `publish` 方法：

- 发送字符串消息：

  ```swift
  publish(
      channelName: String,
      message: String,
      option publishOption: AgoraRtmPublishOptions?
  )   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
  ```

  ```swift
  publish(
      channelName: String,
      message: String,
      option publishOption: AgoraRtmPublishOptions?,
      completion completionBlock: AgoraRtmOperationBlock? = nil
  )
  ```

- 发送二进制消息：

  ```swift
  publish(
      channelName: String,
      data: Data,
      option publishOption: AgoraRtmPublishOptions?
  )   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
  ```

  ```swift
  publish(
      channelName: String,
      data: Data,
      option publishOption: AgoraRtmPublishOptions?,
      completion completionBlock: AgoraRtmOperationBlock? = nil
  )
  ```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `channelName` | String | 必填 | - | [message-swift-html-0-1-4 details](#table-slot-message-swift-html-0-1-4) |
| `message` | String | 必填 | - | 在 `publish`[1/2] 方法中发布 String 型消息负载。 |
| `data` | Data | 必填 | - | 在 `publish`[2/2] 方法中发布 Byte 型消息负载。 |
| `publishOption` | `AgoraRtmPublishOptions` | 选填 | - | 消息选项。 |
| `completion` | `AgoraRtmOperationBlock` | 选填 | - | [message-swift-html-0-5-4 details](#table-slot-message-swift-html-0-5-4) |

<a id="table-slot-message-swift-html-0-1-4"></a>

**message-swift-html-0-1-4 details**

- 如需向 Message Channel 发送消息，填写频道名称。
- 如需向 User Channel 发送消息，填写用户 ID。

<a id="table-slot-message-swift-html-0-5-4"></a>

**message-swift-html-0-5-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmCommonResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

<a id="options"></a>
`AgoraRtmPublishOptions` 数据类型包含以下属性：

| 属性 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `channelType` | `AgoraRtmChannelType` | 必填 | - | 频道类型。详见 [`AgoraRtmChannelType`](/zh-CN/api-reference/rtm/swift/enumv#channeltype)。 |
| `customType` | String | 必填 | - | 用户自定义字段。仅支持 String 型。 |
| `storeInHistory` | Bool | 选填 | `false` | [message-swift-html-1-3-4 details](#table-slot-message-swift-html-1-3-4) |

<a id="table-slot-message-swift-html-1-3-4"></a>

**message-swift-html-1-3-4 details**

是否开启历史消息存储。开启后，消息在发送的同时会被存储到云端，便于用户在进入频道后可以查询到历史消息记录。

:::info[信息]
历史消息功能目前处于 Public Beta 阶段。如需使用，需要前往[控制台](https://console.shengwang.cn/product/RTM2?tab=config)开通。
:::

### 基本用法 [#基本用法]

示例 1：向指定 Message Channel 发送 String 消息

```swift tab="async-await"
// async-await
let publishOptions = AgoraRtmPublishOptions()
publishOptions.channelType = .message     // 选择频道类型，Which channel type, .user or .message
publishOptions.customType = "PlaintText"  // 自定义类型为 "PlaintText"
publishOptions.storeInHistory = YES
let (response, error) = await rtmClient.publish(
    channelName: "exampleChannel",
    message: "Hello, Agora!",
    option: publishOptions)
if let errorInfo = error {
    // 处理错误情况
    print("Failed to publish message with error: \(errorInfo.reason)")
} else if let publishResponse = response {
    // 处理成功情况
    print("Message published successfully.")
} else {
    // 处理未知错误
    print("Unknown error occurred while publishing the message.")
}
```

```swift tab="callback"
// callback
let publishOptions = AgoraRtmPublishOptions()
publishOptions.channelType = .message        // Set the channel type to .message
publishOptions.customType = "PlainText"      // Set a custom type to "PlainText"
publishOptions.storeInHistory = YES

rtmClient.publish(
    channelName: "exampleChannel",
    message: "Hello, Agora!",
    option: publishOptions
) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to publish message with error: \(errorInfo.reason)")
    } else if let publishResponse = response {
        // Handle success
        print("Message published successfully.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while publishing the message.")
    }
}
```

示例 2：向指定 Message Channel 发送 Byte 消息

```swift tab="async-await"
// async-await
let publishOptions = AgoraRtmPublishOptions()
publishOptions.channelType = .message     // 选择频道类型，Which channel type, .user or .message
publishOptions.customType = "BinaryData"  // 自定义类型为 "BinaryData"
publishOptions.storeInHistory = YES
let byteArray: [UInt8] = [0x00, 0x01, 0x02, 0x03]
let binaryData = Data(byteArray)

let (response, error) = await rtmClient.publish(
    channelName: "exampleChannel",
    data: binaryData,
    option: publishOptions)
if let errorInfo = error {
    // 处理错误情况
    print("Failed to publish message with error: \(errorInfo.reason)")
} else if let publishResponse = response {
    // 处理成功情况
    print("Message published successfully.")
} else {
    // 处理未知错误
    print("Unknown error occurred while publishing the message.")
}
```

```swift tab="callback"
// callback
let publishOptions = AgoraRtmPublishOptions()
publishOptions.channelType = .message      // Set the channel type to .message
publishOptions.customType = "BinaryData"    // Set a custom type to "BinaryData"
publishOptions.storeInHistory = YES
let byteArray: [UInt8] = [0x00, 0x01, 0x02, 0x03]
let binaryData = Data(byteArray)

rtmClient.publish(
    channelName: "exampleChannel",
    data: binaryData,
    option: publishOptions
) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to publish message with error: \(errorInfo.reason)")
    } else if let publishResponse = response {
        // Handle success
        print("Message published successfully.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while publishing the message.")
    }
}
```

示例 3：向指定 User Channel 发送消息

```swift tab="设置频道类型"
let publishOptions = AgoraRtmPublishOptions()
// 设置频道类型
publishOptions.channelType = .user
// 自定义类型为 "PlaintText"
publishOptions.customType = "PlaintText"
publishOptions.storeInHistory = YES

let (response, error) = await rtmClient.publish(
    channelName: "exampleChannel",
    message: "Hello, Agora!",
    option: publishOptions)
if let errorInfo = error {
    // 处理错误情况
    print("Failed to publish message with error: \(errorInfo.reason)")
} else if let publishResponse = response {
    // 处理成功情况
    print("Message published successfully.")
} else {
    // 处理未知错误
    print("Unknown error occurred while publishing the message.")
}
```

```swift tab="callback"
// callback
let publishOptions = AgoraRtmPublishOptions()
// 设置频道类型
publishOptions.channelType = .user
// 自定义类型为 "PlaintText"
publishOptions.customType = "PlainText"
publishOptions.storeInHistory = YES

rtmClient.publish(
    channelName: "exampleChannel",
    message: "Hello, Agora!",
    option: publishOptions
) { (response, error) in
    if let errorInfo = error {
        // 处理错误情况
        print("Failed to publish message with error: \(errorInfo.reason)")
    } else if let publishResponse = response {
        // 处理成功情况
        print("Message published successfully.")
    } else {
        // 处理未知错误
        print("Unknown error occurred while publishing the message.")
    }
}
```

:::info[信息]
成功调用该方法后，SDK 会触发 `didReceiveMessageEvent` 事件通知。订阅了该频道并且开启了事件监听的用户将会收到该事件通知，详见[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)。
:::

## getMessages [#getmessages]

### 接口描述 [#接口描述-1]

如果你需要从指定频道中获取历史消息，在客户端调用 `getMessages` 方法。

### 接口方法 [#接口方法-1]

你可以通过以下方式调用 `getMessages` 方法：

```swift
getMessages(channelName: String,
            channelType: AgoraRtmChannelType,
            options: AgoraRtmGetHistoryMessagesOptions?
) async -> (AgoraRtmGetHistoryMessagesResponse?, AgoraRtmErrorInfo)
```

```swift
getMessages(channelName: String,
            channelType: AgoraRtmChannelType,
            options: AgoraRtmGetHistoryMessagesOptions?,
            completion completionBlock: AgoraRtmGetHistoryMessagesBlock? = nil
)
```

| 参数 | 类型 | 是否必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `channelName` | String | 必填 | - | 频道名称。 |
| `channelType` | `AgoraRtmChannelType` | 必填 | - | 频道类型。详见 [`AgoraRtmChannelType`](/zh-CN/api-reference/rtm/swift/enumv#channeltype)。 |
| `options` | `AgoraRtmGetHistoryMessagesOptions` | 必填 | - | 查询选项。 |
| `completion` | `AgoraRtmGetHistoryMessagesBlock` | 选填 | - | [message-swift-html-2-4-4 details](#table-slot-message-swift-html-2-4-4) |

<a id="table-slot-message-swift-html-2-4-4"></a>

**message-swift-html-2-4-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmGetHistoryMessagesResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

`AgoraRtmGetHistoryMessagesOptions` 数据类型包含以下属性：

|     属性     |  类型  | 是否必填 | 默认值 | 描述          |
| --------- | --- | ----- | --- | -------- |
| `messageCount`  | int |   选填   |  `100`   | 单次查询的最大消息数。如果单次查询的时间范围内消息数大于该值，则需多次调用 `getMessages` 方法进行查询。 |
|   `start`   |  unsigned long long  |   选填   |  `0`   | 历史消息开始的时间戳。 |
| `end` | unsigned long long |   选填   |   `0`    | 历史消息结束的时间戳。   |

:::info[信息]
RTM SDK 提供 `start` 和 `end` 参数，你可以根据实际需求进行设置：

- `start` 和 `end` 为 UTC 时间戳，且两者间隔不能超过 24 小时（取 `event` 事件中返回的 `timestamp` 值）。
- 如果你只设置了 `start` 参数，则你会获得比 `start` 时间戳更早的历史消息。
- 如果你只设置了 `end` 参数，则你会获得当前时间戳到 `end` 时间戳（包含）之间的历史消息。
- 如果你同时设置了 `start` 和 `end` 参数，则你会获得 `start` 和 `end` 时间戳（包含）之间的历史消息。
:::

`AgoraRtmGetHistoryMessagesResponse` 数据类型包含以下属性：

|  属性  |  类型  | 描述      |
| ---- | ----- | --------- |
| `newStart`         |         unsigned long long         | 下一条历史消息的发送时间戳。如果该参数为 `0`，则表示没有下一条历史消息。               |
| `messageList`    | `NSArray <AgoraRtmHistoryMessage *>`  | 历史消息列表。   |

`AgoraRtmHistoryMessage` 数据类型包含以下属性：

|  属性  |  类型  | 描述      |
| ---- | ----- | --------- |
| `message`                | `AgoraRtmMessage`                |  消息。   |
| `publisher`              | String                |  消息发布者 ID。   |
| `customType` | String | 用户自定义字段。仅支持 String 型。                |
| `timestamp` | unsigned long long | 消息发送的时间戳。                |

### 基本用法 [#基本用法-1]

```swift tab="async-await"
// async-await
let options = AgoraRtmGetHistoryMessagesOptions()
options.messageCount = 10

let (response, error) = await rtmClient.getHistory()?.getMessages(
  channelName: "channel",
  channelType: .message,
  options: options)
if let errorInfo = error {
    // 处理错误情况
    print("Failed to get history message with error: \(errorInfo.reason)")
} else if let response = response {
    // 处理历史消息
    let messageList = response.messageList
} else {
    // 处理未知错误
    print("Unknown error occurred while get history message the message.")
}
```

```swift tab="callback"
// callback
 let options = AgoraRtmGetHistoryMessagesOptions()
 options.messageCount = 10

rtmClient.getHistory()?.getMessages(channelName: "channel", channelType: .message, options: options) { (response, errorInfo) in
  if let errorInfo = errorInfo {
    print("获取历史消息失败，错误代码: \(errorInfo.errorCode)，原因: \(errorInfo.reason)")
  } else if let response = response {
    // 处理历史消息
    let messageList = response.messageList
  }
}
```

<a id="接收消息"></a>
## 接收消息 [#接收消息]

RTM 提供消息、状态、事件变更等信息的事件通知。通过设置事件监听，你可以接收已订阅频道中的消息和事件。

```swift
// message event handler
class MessageHandler: NSObject, AgoraRtmClientDelegate {
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
        print("Message received from \(event.channelName): \(event.message)")
    }
}
let messageDelegate = MessageHandler()
rtmClient.addDelegate(messageDelegate)
```

关于如何添加和设置事件监听，详见[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)章节。
