# 初始配置 (/zh-CN/api-reference/rtm/flutter/configuration)

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

RTM SDK API 参考介绍了实时消息相关 API 的接口描述、接口方法、基本用法示例代码和返回值。

想要了解详细的初始配置步骤，可以查看：

- [应用配置](/zh-CN/realtime-media/rtm/build/rtm-initialization/application-setup)

## RtmConfig [#rtmconfig]

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

`RtmConfig` 用于设置 RTM 初始化时配置其他额外属性，这些配置属性会在整个 RTM 客户端的生命周期中生效，影响 RTM 客户端的行为。

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

你可以通过以下方式创建 `RtmConfig` 实例：

```dart
RtmConfig({
    int heartbeatInterval,
    int presenceTimeout,
    int reconnectTimeout,
    bool useStringUserId,
    bool ispPolicyEnabled,
    RtmProtocolType protocolType,
    RtmLogConfig logConfig,
    RtmProxyConfig proxyConfig,
    RtmEncryptionConfig encryptionConfig,
    RtmPrivateConfig privateConfig,
    Set<RtmAreaCode> areaCode
})
```

| 属性 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `areaCode` | `RtmAreaCode` | 选填 | `glob` | 服务区域代码，你可以根据自己业务部署的区域进行选择，详见 [`RtmAreaCode`](/zh-CN/api-reference/rtm/flutter/enumv#areacode)。 |
| `protocolType` | `RtmProtocolType` | 选填 | `tcpUdp` | 消息传输协议类型。RTM 默认使用一路 TCP 和一路 UDP 协议进行传输，你可以根据需要修改协议类型。详见 [`RtmProtocolType`](/zh-CN/api-reference/rtm/flutter/enumv#protocoltype)。 |
| `presenceTimeout` | int | 选填 | `300` | Presence 的超时时间。单位为秒，取值范围为 [5,300]。即 RTM 服务器在判定客户端超时后，延迟多久向其他用户发送 `remoteTimeout` 事件通知。如果客户端在该参数设置的时间内重新建立连接并返回频道，则 RTM 服务器不会向频道中其他人发送 `remoteTimeout` 事件通知，也不会删除该用户的临时用户数据。 |
| `heartbeatInterval` | int | 选填 | `5` | [configuration-flutter-html-0-4-4 details](#table-slot-configuration-flutter-html-0-4-4) |
| `reconnectTimeout` | int | 选填 | `0` | [configuration-flutter-html-0-5-4 details](#table-slot-configuration-flutter-html-0-5-4) |
| `useStringUserId` | bool | 选填 | `true` | [configuration-flutter-html-0-6-4 details](#table-slot-configuration-flutter-html-0-6-4) |
| `ispPolicyEnabled` | bool | 选填 | `false` | [configuration-flutter-html-0-7-4 details](#table-slot-configuration-flutter-html-0-7-4) |
| `logConfig` | `RtmLogConfig` | 选填 | - | 本地日志存储的大小、位置和日志等级等配置属性。 |
| `proxyConfig` | `RtmProxyConfig` | 选填 | - | 当使用 RTM 的 Proxy 功能时，需要配置此参数。 |
| `encryptionConfig` | `RtmEncryptionConfig` | 选填 | - | 当使用 RTM 端侧加密功能时，需要配置此项参数。 |
| `privateConfig` | `RtmPrivateConfig` | 选填 | - | 当使用 RTM 的私有化部署功能时，需要配置此项参数。 |

<a id="table-slot-configuration-flutter-html-0-4-4"></a>

**configuration-flutter-html-0-4-4 details**

SDK 心跳时间。单位为秒，取值范围为 [5,1800]。即客户端向 RTM 服务器发送心跳包的时间间隔。如果客户端在该参数设置的时间内没有向 RTM 服务器发送心跳包，则 RTM 服务器会判定客户端超时。

:::info[信息]
该参数会影响 PCU 计数，从而影响计费。
:::

<a id="table-slot-configuration-flutter-html-0-5-4"></a>

**configuration-flutter-html-0-5-4 details**

SDK 连接超时时间。单位为秒，取值范围为 [15,3600]。默认值 `0` 表示从不超时，SDK 会一直尝试重连，直到成功。

该参数对初次登录 RTM 服务和断线重连均有效：

- 如果初次登录超时，SDK 在返回的 `RtmStatus` 中会报告 `errorCode` 为 `loginTimeout`；同时触发 `linkstate` 事件，其中 `currentState` 为 `failed`，`reason` 为 `loginTimeout`；
- 如果断线重连超时，SDK 会触发 `linkstate` 事件，其中 `currentState` 为 `failed`，`reason` 为 `reconnectTimeout`。

<a id="table-slot-configuration-flutter-html-0-6-4"></a>

**configuration-flutter-html-0-6-4 details**

是否使用 String 类型的用户 ID：

- `true`: 使用 String 类型的用户 ID。
- `false`: 使用 Int 类型的用户 ID，SDK 会自动将 String 类型的 `userId` 属性转换为 Int 类型。该设置下，你需要在 `userId` 属性中传入内容为数值的字符串（例如 `"1234567"`），否则方法会调用失败。

当同时使用声网 RTC 和 RTM 产品时，需要确保 `userId` 一致。

<a id="table-slot-configuration-flutter-html-0-7-4"></a>

**configuration-flutter-html-0-7-4 details**

是否开启 ISP 域名策略限制。在 IoT 场景下，设备可能受限于互联网服务提供商 (ISP)，你可以通过该字段设置 SDK 的连接模式，连接到已向运营商报备的域名或 IP 白名单中的服务器：

- `true`: 开启 ISP 域名策略限制。该设置适用于 IoT 设备使用物联网卡进行网络访问的场景。SDK 会仅连接到已向运营商报备的域名或 IP 白名单中的服务器。
- `false`: （默认）关闭 ISP 域名策略限制。该设置适用于大部分普通场景。

#### RtmLogConfig [#rtmlogconfig]

```dart
RtmLogConfig({
    String filePath,
    int fileSizeInKB,
    RtmLogLevel level
})
```

`RtmLogConfig` 实例用来设置和存储本地日志文件 `agora.log`。在调试阶段，通过日志保存和跟踪 App 运行状态，你可以极大的提升效率。如果遇到复杂问题并需要声网技术人员协助调查，你需要提供该日志信息。`RtmLogConfig` 包含以下属性：

| 属性 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `filePath` | String | 选填 | - | 日志存储路径。 |
| `fileSizeInKB` | int | 选填 | `1024` | [configuration-flutter-html-1-2-4 details](#table-slot-configuration-flutter-html-1-2-4) |
| `level` | `RtmLogLevel` | 选填 | `info` | 日志信息的输出等级，详见 [`RtmLogLevel`](/zh-CN/api-reference/rtm/flutter/enumv#loglevel)。 |

<a id="table-slot-configuration-flutter-html-1-2-4"></a>

**configuration-flutter-html-1-2-4 details**

日志文件大小，单位为 KB，取值范围为 [128,1024]。

- 如果你填入的值小于 128，则 SDK 按照 128 设置。
- 如果你填入的值大于 1024，则 SDK 按照 1024 设置。

#### RtmProxyConfig [#rtmproxyconfig]

<span className="index-desc-proxy">`RtmProxyConfig` 实例用来设置客户端 Proxy 服务代理等相关属性。在一些网络服务受限的环境下，你可能需要使用此功能。</span>

```dart
RtmProxyConfig({
    RtmProxyType proxyType,
    String server,
    int port,
    String account,
    String password
})
```

:::info[信息]
你需要妥善保管好你的 Proxy 用户名和密码。RTM 不会以任何方式解析、存储、转发你的用户名和密码。此外，如果你在 App 运行过程中修改 Proxy 的设置，该设置要重启 RTM Client 后才能生效。
:::

`RtmProxyConfig` 包含以下属性：

| 属性        | 类型                 | 必填 |     默认值      | 描述      |
| ---------- | --------------- | ------ | ---- | ----------- |
| `proxyType` | `RtmProxyType` |   选填   | `none` | Proxy 协议类型。详见 [`RtmProxyType`](/zh-CN/api-reference/rtm/flutter/enumv#proxytype)。 |
| `server`    | String               |   选填   |        -        | Proxy 服务器域名或 IP 地址。    |
| `port`      | int                  |   选填   |        -        | Proxy 监听端口。                |
| `account`   | String               |   选填   |        -        | Proxy 登录账号。                |
| `password`  | String               |   选填   |        -        | Proxy 登录密码。                |

#### RtmEncryptionConfig [#rtmencryptionconfig]

`RtmEncryptionConfig` 实例用来设置客户端加密所需要的属性。成功设置加密方式、加密密钥等属性后，用户发送的所有消息或者设置的所有状态都会在客户端自动加密和解密。

```dart
RtmEncryptionConfig({
    RtmEncryptionMode encryptionMode,
    String encryptionKey,
    Uint8List encryptionSalt
})
```

:::info[信息]
一旦设置了加密，所有用户必须使用相同的加密模式和密钥，否则数据无法互通。
:::

`RtmEncryptionConfig` 包含以下属性：

| 属性                | 类型  | 必填 |        默认值        | 描述          |
| ---- | ------ | -- | ------ | --------------- |
| `encryptionMode`    | `RtmEncryptionMode` | 选填 | `none` | 加密方式。详见 [`RtmEncryptionMode`](/zh-CN/api-reference/rtm/flutter/enumv#encryptionmode)。 |
| `encryptionKey`     | String     | 选填 |    -   | 用户自定义加密密钥，长度无限制。声网推荐使用 32 字节的密钥。                     |
| `encryptionKdfSalt` | Uint8List  | 选填 | `null`  | 用户自定义加密盐，长度为 32 字节。声网推荐你在服务端使用 OpenSSL 生成盐。        |

#### RtmPrivateConfig [#rtmprivateconfig]

`RtmPrivateConfig` 实例用来设置私有化部署所需要的属性。

```dart
RtmPrivateConfig({
    Set<RtmServiceType> serviceType,
    List<String> accessPointHosts
})
```

`RtmPrivateConfig` 包含以下属性：

|        属性        |       类型       | 必填 | 默认值 | 描述          |
| ---------------- | ----- | ------ | ---- | --------------- |
|   `serviceType`    | `Set<RtmServiceType>` |   选填   |   -    | 服务类型。详见 [`RtmServiceType`](/zh-CN/api-reference/rtm/flutter/enumv#rtmservicetype)。 |
| `accessPointHosts` |  `List<String>`  |   选填   |   -    | 服务器的地址数组，数组中支持填写域名或 IP 地址。             |

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

```dart
final proxyConfig = RtmProxyConfig(
      protocolType : RtmProxyType.http,
      server : "x.x.x.x",
      port : 8080,
      account : "Tony",
      password : "pwd" );

final logConfig = RtmLogConfig(
      filePath : "xxxx",
      fileSizeInKB : 1024;
      leave : RtmLogLevel.info );

final encryptionConfig = RtmEncryptionConfig(
      encryptionMode : RtmEncryptionMode.aes256Gcm,
      encryptionKey : "XXXXX",
      encryptionSalt : [1,2,3,4,5]);

final rtmConfig = RtmConfig(
      heartbeatInterval : 10,
      presenceTimeout : 5,
      proxyConfig : proxyConfig,
      logConfig : logConfig,
      areaCode : {RtmAreaCode.cn, RtmAreaCode.na},
      encryptionConfig : encryptionConfig );

```

<a id="create"></a>

<a id="初始化"></a>
## 初始化 [#初始化]

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

调用 `RTM()` 方法创建并初始化 RTM Client 实例。

:::info[信息]
- 创建并初始化客户端实例需要在调用 RTM 的其他 API 之前进行。
- 为区分各用户和设备，你需要确保 `userId` 全局唯一，并且在用户或设备的生命周期内保持不变。
:::

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

你可以通过以下方式创建并初始化实例：

```dart
Future<(RtmStatus,RtmClient)> RTM(
    String appId,
    String userId,
    {
        RtmConfig rtmConfig
    }
)
```

| 参数        | 类型            | 必填 | 默认值 | 描述          |
| ---------- | ---------- | -- | ---- | --------------- |
| `appId`     | String          |  是  |   -    | 你在声网控制台创建项目时获得的 App ID。                      |
| `userId`    | String          |  是  |   -    | 用户 ID，用于标识用户或设备。为区分各用户和设备，你需要确保 `userId` 全局唯一，并且在用户或设备的生命周期内保持不变。 |
| `rtmConfig` | `RtmConfig` | 选填 |   -    | 初始化 RTM Client 的配置参数。详见 `RtmConfig`。       |

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

```dart
final proxyConfig = RtmProxyConfig(
      protocolType : RtmProxyType.http,
      server : "x.x.x.x",
      port : 8080,
      account : "Tony",
      password : "pwd" );

final logConfig = RtmLogConfig(
      filePath : "xxxx",
      fileSizeInKB : 1024,
      leave : RtmLogLevel.info );

final encryptionConfig = RtmEncryptionConfig(
      encryptionMode : RtmEncryptionMode.aes256gcm,
      encryptionKey : "XXXXX",
      encryptionSalt : [1,2,3,4,5]);

final rtmConfig = RtmConfig(
      heartbeatInterval : 10,
      presenceTimeout : 5,
      proxyConfig : proxyConfig,
      logConfig : logConfig,
      areaCode : {RtmAreaCode.cn, RtmAreaCode.na},
      encryptionConfig : encryptionConfig );

var (status,rtmClient) = await RTM("myAppId", "Tony", rtmConfig:rtmConfig);
if (status.error == true) {
    print(status);
} else {
    print(response);
}
```

### 返回值 [#返回值]

调用该方法，会返回 `Future<(RtmStatus,RtmClient)>` 类型的元组数据。

- 无论该方法是否调用成功，元组的第一项都会返回一个 `RtmStatus` 类型的数据，其中字段定义如下：

  ```dart
  class RtmStatus {
      bool error;                   // 本次操作是否出错。
      String errorCode;             // 本次操作错误码。
      String operation;             // 本次操作的 API。
      String reason;                // 本次操作错误原因简述。
  }
  ```

  你可以通过检索 `errorCode` 字段的[错误码](/zh-CN/realtime-media/rtm/build/troubleshooting)了解错误原因，并找到对应的解决方法。

- 如果该方法调用成功，元组的第二项将返回一个 RTM 客户端实例，用以后续调用其他 API。

<a id="事件监听"></a>
## 事件监听 [#事件监听]

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

RTM 总共有 7 种事件通知类型，如下表所示：

| 事件类型                 | 描述       |
| ------- | ------- |
| <code className="index-api-onmessageevent" id="message">message</code>          | <span className="index-desc-onmessageevent">接收用户所订阅的 Message Channel 及 Topic 中的所有消息事件通知。详见 [`MessageEvent`](#messageevent)。</span>            |
| <code className="index-api-onpresenceevent" id="presence">presence</code>       | <span className="index-desc-onpresenceevent">接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Presence 事件通知。详见 [`PresenceEvent`](#presenceevent)。</span>        |
| <code className="index-api-ontopicevent" id="topic">topic</code>                | <span className="index-desc-ontopicevent">接收用户所加入的 Stream Channel 中所有 Topic 变更事件通知。详见 [`TopicEvent`](#topicevent)。</span>                       |
| <code className="index-api-onstorageevent" id="storage">storage</code>          | <span className="index-desc-onstorageevent">接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，及订阅用户的 User Metadata 事件通知。详见 [`StorageEvent`](#storageevent)。</span> |
| <code className="index-api-onlockevent" id="lock">lock</code>                   | <span className="index-desc-onlockevent">接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。详见 [`LockEvent`](#lockevent)。</span>    |
| <code className="index-api-onlinkstateevent" id="linkState">linkState</code>    | <span className="index-desc-onlinkstateevent">接收客户端网络连接状态变更的事件通知。详见 [`LinkStateEvent`](#linkstateevent)。</span>       |
| <code className="index-api-ontokenwillexpire" id="token">token</code> | <span className="index-desc-ontokenwillexpire">接收客户端 Token 将要过期的事件通知。</span>    |

<a id="添加监听"></a>
### 添加监听 [#添加监听]

你可以在 App 生命周期的任意时间调用 `addListener` 方法添加一个或多个事件监听对象。

```dart
rtmClient.addListener({
    Function(MessageEvent event)? message = null,
    Function(PresenceEvent event)? presence = null,
    Function(TopicEvent event)? topic = null,
    Function(StorageEvent event)? storage = null,
    Function(LockEvent event)? lock = null,
    Function(LinkStateEvent event)? linkState = null,
    Function(TokenEvent event)? token = null,
})
```

<a id="删除监听"></a>
### 删除监听 [#删除监听]

如果你不再需要关注某个事件监听对象，但仍需关注其他时间监听对象，你可以调用 `removeListener` 方法删除指定的事件监听对象。

```dart
rtmClient.removeListener({
    Function(MessageEvent event) message = null,
})
```

#### MessageEvent [#messageevent]

消息事件。

`MessageEvent` 包含以下属性：

| 属性            | 类型                   | 描述    |
| -------------- | ----------------- | --------- |
| `channelType`   | `RtmChannelType` | 频道类型。详见 [`RtmChannelType`](/zh-CN/api-reference/rtm/flutter/enumv#channeltype)。 |
| `messageType`   | `RtmMessageType` | 消息类型。详见 [`RtmMessageType`](/zh-CN/api-reference/rtm/flutter/enumv#messagetype)。 |
| `channelName`   | String                 | 频道名称。                    |
| `channelTopic`  | String                 | Topic 名称。                  |
| `message`       | Uint8List              | 消息。  |
| `messageLength` | int                    | 消息长度。                    |
| `publisher`     | String                 | 消息发布者 ID。               |
| `customType`    | String                 | 用户自定义字段。仅支持 String 型。                     |
| `timestamp`     | int                    | 事件发生的时间戳。            |

#### PresenceEvent [#presenceevent]

用户 Presence 事件。

`PresenceEvent` 包含以下属性：

| 属性       |  类型  |   描述                                                                                                                         |
|-------|--------| ---------- |
| `type`            | `RtmPresenceEventType`    |   Presence 事件类型。详见 [`RtmPresenceEventType`](/zh-CN/api-reference/rtm/flutter/enumv#presencetype)。  |
| `channelType`            | `RtmChannelType`    |  频道类型。详见 [`RtmChannelType`](/zh-CN/api-reference/rtm/flutter/enumv#channeltype)。   |
| `channelName`            | String                |  事件发生的频道名称。   |
| `publisher`              | String                |  触发此事件的用户 ID。   |
| `stateItems`            | `List<StateItem>`    |  标识用户临时状态的键值对。  |
| `interval`            | `IntervalInfo`               |  Interval 状态下，当前频道在上一个周期内用户加入、离开、超时、状态变更等事件通知的聚合增量信息。  |
| `snapshot`              | `SnapshotInfo`               |  当前频道的内所有用户及其状态的快照数据。只要用户在频道内，该事件可能会多次触发。   |
| `timestamp` | int | 事件发生的时间戳。                |

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

|  属性  |  类型  | 描述                            |
| ------ | ------- | ------ |
| `key`         |         String        | 用户状态的键。如果指定的键已经存在，则该键的值会被新值覆盖；如果指定的键不存在，则 SDK 会新增该键/值对。     |
| `value` | String | 用户状态的值。 |

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

| 属性              | 类型              | 描述  |
| ---------------- | ---------------- | ------ |
| `joinUserList`    | `UserList`        | 在上一个周期内加入频道的用户列表。     |
| `leaveUserList`   | `UserList`        | 在上一个周期内离开频道的用户列表。     |
| `timeoutUserList` | `UserList`        | 在上一个周期内加入频道超时的用户列表。                       |
| `userStateList`   | `List<UserState>` | 在上一个周期内状态变更的用户列表。包含用户 ID 和状态键值对。 |

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

| 属性            | 类型              | 描述                    |
| -------------- | ---------------- | ---- |
| `userStateList` | `List<UserState>` | 用户第一次加入频道时的快照信息，包含用户 ID 和状态键值对。 |

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

| 属性    | 类型           |    描述    |
| ------ | ------------- | -------- |
| `users` | `List<String>` | 用户列表。 |

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

| 属性     | 类型              |                描述                |
| ------- | ---------------- | ---- |
| `userId` | String            |             用户 ID。              |
| `states` | `List<StateItem>` | 频道在线用户及其临时状态信息列表。 |

#### TopicEvent [#topicevent]

Topic 事件。

`TopicEvent` 包含以下属性：

| 属性        |  类型  |   描述               |
|-----|------| ---------- |
| `type`            | `RtmTopicEventType`    |  Topic 事件类型。详见 [`RtmTopicEventType`](/zh-CN/api-reference/rtm/flutter/enumv#topictype)。  |
| `channelName`            | String                |  事件发生的频道名称。   |
| `publisher`              | String                |  触发此事件的用户 ID。   |
| `topicInfos`            | `List<TopicInfo>`               |  Topic 的详细信息数组，包含 Topic 名称、Topic 发布者等信息。   |
| `timestamp` | int | 事件发生的时间戳。                |

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

| 属性         | 类型                  | 描述             |
| ----------- | ------ | ---------------- |
| `topic`      | String                | Topic 名称。     |
| `publishers` | `List<PublisherInfo>` | 消息发布者数组。 |

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

| 属性              | 类型   | 描述                  |
| ---------------- | ----- | ------- |
| `publisherUserId` | String | 消息发布者的用户 ID。 |
| `publisherMeta`   | String | 消息发布者的元数据。  |

#### StorageEvent [#storageevent]

Storage 事件。

`StorageEvent` 包含以下属性：

| 属性         |  类型  |   描述                  |
|-----|------| ---------- |
| `channelType`            | `RtmChannelType`    |  频道类型。详见 [`RtmChannelType`](/zh-CN/api-reference/rtm/flutter/enumv#channeltype)。   |
| `storageType`            | `RtmStorageType`    |  Storage 类型。详见 [`RtmStorageType`](/zh-CN/api-reference/rtm/flutter/enumv#storagetype)。  |
| `eventType`            | `RtmStorageEventType`    |  Storage 事件类型。详见 [`RtmStorageEventType`](/zh-CN/api-reference/rtm/flutter/enumv#storageeventtype)。  |
| `target`              | String                |  用户 ID 或频道名称。   |
| `data`            | `Metadata`               |   Metadata Item。详见 [`Metadata`](/zh-CN/api-reference/rtm/flutter/storage#metadata)。   |
| `timestamp` | int | 事件发生的时间戳。                |

#### LockEvent [#lockevent]

Lock 事件。

`LockEvent` 包含以下属性：

| 属性             | 类型                   | 描述    |
| --------------- | ----------------- | --------- |
| `channelType`    | `RtmChannelType` | 频道类型。详见 [`RtmChannelType`](/zh-CN/api-reference/rtm/flutter/enumv#channeltype)。 |
| `eventType`      | `RtmLockEventType`    | Lock 事件类型。详见 [`RtmLockEventType`](/zh-CN/api-reference/rtm/flutter/enumv#locktype)。  |
| `channelName`    | String                 | 频道名称。                    |
| `lockDetailList` | `List<LockDetail>`     | Lock 的详情。                 |
| `timestamp`      | int                    | 事件发生的时间戳。            |

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

| 属性       | 类型   | 描述               |
| --------- | ----- | ---------- |
| `lockName` | String | Lock 的名称。      |
| `owner`    | String | 拥有锁的用户 ID。  |
| `ttl`      | int    | 锁的过期时间。单位为秒，取值范围为 [10,300]。当使用这把锁的用户掉线时，如果用户在过期时间之内重新回到频道，则该用户依旧可以使用锁；否则，该用户的锁会被释放，监听了 `lock` 事件通知的用户会收到 `lockReleased` 事件。 |

#### LinkStateEvent [#linkstateevent]

SDK 连接状态事件。

`LinkStateEvent` 包含以下属性：

| 属性        |  类型  |   描述               |
|-----|------| ---------- |
| `currentState`            | `RtmLinkState`    |  当前的连接状态。详见 [`RtmLinkState`](/zh-CN/api-reference/rtm/flutter/enumv#linkstate)。   |
| `previousState`            | `RtmLinkState`    |  之前的连接状态。详见 [`RtmLinkState`](/zh-CN/api-reference/rtm/flutter/enumv#linkstate)。   |
| `serviceType`    | `RtmServiceType` | 网络连接类型。详见 [`RtmServiceType`](/zh-CN/api-reference/rtm/flutter/enumv#rtmservicetype)。 |
| `operation`    | `RtmLinkOperation` | 触发本次状态迁移的操作。详见 [`RtmLinkOperation`](/zh-CN/api-reference/rtm/flutter/enumv#linkoperation)。 |
| `reason`    | String | 本次状态迁移的原因。 详见 [`RtmLinkStateChangeReason`](/zh-CN/api-reference/rtm/flutter/enumv#linkstatechangereason)。 |
| `affectedChannels`    | `List<String>` | 本次状态迁移影响的频道。 |
| `unrestoredChannels`    | `List<String>` | 未恢复订阅或加入的频道信息，包含频道名、频道类型和频道中的临时状态数据。一般情况下为空。 |
| `isResumed`    | bool | 在连接断开的 2 分钟内，是否从 `rtmLinkStateDisconnected` 状态恢复成 `rtmLinkStateConnected` 状态。`true` 表示已恢复。 |
| `timestamp`    | int | 本次事件通知发送的时间戳。 |

## login [#login]

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

创建并初始化 RTM 实例之后，你需要执行 `login` 操作以登录 RTM 服务。登录成功将使客户端与 RTM 服务器建立起长连接，之后客户端才能正常访问 RTM 资源。

:::info[信息]
用户成功登录 RTM 服务后，应用的 PCU 会增加，这将影响你的账单数据。
:::

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

你可以通过以下方法登录 RTM 系统：

```dart
Future<(RtmStatus, LoginResult?)> login(String token);
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `token` | String | 必填 | - | [configuration-flutter-html-2-1-4 details](#table-slot-configuration-flutter-html-2-1-4) |

<a id="table-slot-configuration-flutter-html-2-1-4"></a>

**configuration-flutter-html-2-1-4 details**

登录 RTM 系统的 Token。

- 如果你的项目开启了 Token 鉴权，你可以填入 [RTM 临时 Token](/zh-CN/realtime-media/rtm/build/rtm-initialization/enable-service#5-获取临时-token) 或 Token 服务器生成的 RTM 正式 Token。详见[客户端鉴权](/zh-CN/realtime-media/rtm/build/authentication-and-connection/user-authentication)和[部署 RTM Token 服务器](/zh-CN/realtime-media/rtm/build/authentication-and-connection/token-generation)。
- 如果你的项目未开启 Token 鉴权，你可以填入空字符串或开通了 RTM 服务的项目 App ID。

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

```dart
var (status,response) = await rtmClient.login('your_token');
if (status.error == true) {
    print(status);
} else {
    print(response);
}
```

### 返回值 [#返回值-1]

调用该方法，会返回 `Future<(RtmStatus, LoginResult?)>` 类型的元组数据。

- 无论该方法是否调用成功，元组的第一项都会返回一个 `RtmStatus` 类型的数据，其中字段定义如下：

  ```dart
  class RtmStatus {
      bool error;                   // 本次操作是否出错。
      String errorCode;             // 本次操作错误码。
      String operation;             // 本次操作的 API。
      String reason;                // 本次操作错误原因简述。
  }
  ```

  你可以通过检索 `errorCode` 字段的[错误码](/zh-CN/realtime-media/rtm/build/troubleshooting)了解错误原因，并找到对应的解决方法。

- 如果该方法调用成功，元组的第二项将返回一个 `LoginResult` 类型的数据，当前不包含任何字段。

## logout [#logout]

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

当你不再需要操作后，可以登出系统。本操作会影响你账单中的 PCU 计费项。

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

你可以通过以下接口退出登录：

```dart
Future<(RtmStatus, LogoutResult?)> logout();
```

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

```dart
var (status,response) = await rtmClient.logout();
if (status.error == true) {
    print(status);
} else {
    print(response);
}
```

### 返回值 [#返回值-2]

调用此方法，会返回 `Future<(RtmStatus, LogoutResult?)>` 类型的元组数据。

- 无论该方法是否调用成功，元组的第一项都会返回一个 `RtmStatus` 类型的数据，其中字段定义如下：

  ```dart
  class RtmStatus {
      bool error;                   // 本次操作是否出错。
      String errorCode;             // 本次操作错误码。
      String operation;             // 本次操作的 API。
      String reason;                // 本次操作错误原因简述。
  }
  ```

  你可以通过检索 `errorCode` 字段的[错误码](/zh-CN/realtime-media/rtm/build/troubleshooting)了解错误原因，并找到对应的解决方法。

- 如果该方法调用成功，元组的第二项将返回一个 `LogoutResult` 类型的数据，当前不包含任何字段。

## release [#release]

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

一旦不再需要 RTM 服务，最好销毁 `RtmClient` 实例。这样做将使你免受内存泄漏甚至错误和异常引起的性能下降的影响。

:::info[信息]
`release` 需要在非回调内的子线程调用，避免在回调中执行。
:::

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

你可以通过以下方法销毁 `RtmClient` 实例：

```dart
Future<RtmStatus> release();
```

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

```dart
var status = await rtmClient.release();
```

### 返回值 [#返回值-3]

无论该方法是否调用成功，都会返回一个 `RtmStatus` 类型的数据，其中字段定义如下：

```dart
class RtmStatus {
    bool error;                   // 本次操作是否出错。
    String errorCode;             // 本次操作错误码。
    String operation;             // 本次操作的 API。
    String reason;                // 本次操作错误原因简述。
}
```

你可以通过检索 `errorCode` 字段的[错误码](/zh-CN/realtime-media/rtm/build/troubleshooting)了解错误原因，并找到对应的解决方法。
