# 消息负载序列化 (/zh-CN/realtime-media/rtm/build/message-design-and-history/serialized)

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

当你为消息负载构建结构化的格式后，还需要将消息数据进行序列化转换成字符串类型或二进制类型，以满足 RTM 中发送消息的格式要求。你可以自己实现或使用第三方的插件，我们有以下两种推荐做法：

- 使用 Json.Net
- 使用 Protocol Buffers

## 使用 Json.Net [#使用-jsonnet]

Json.Net 是 .NET 平台上一个强大、灵活、易用和高性能的 JSON 框架，可用于序列化和反序列化 JSON 数据，支持多种数据格式和数据类型。

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
### 安装步骤 [#安装步骤]

1. 在 Unity 中打开 **Package Manager**。
2. 在 **Add package by name** 中输入包名 **com.unity.nuget.newtonsoft-json**，点击确定后安装这个包。
3. 在你的程序中通过 `using Newtonsoft.Json` 语句引用 Json.Net。

安装完成后，你可以使用自定义类或者 JSON Object 序列化消息。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

### 使用自定义类 [#使用自定义类]

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `publish` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `publish` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `PublishAsync` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `publish` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `publish` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
以下步骤展示了如何使用自定义类把包含问题和答案选项的投票消息序列化为 JSON 格式，并通过 `publish` 方法发布到指定的消息通道中。
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

1. 定义一个 `PollMessage` 类，该类包含了投票消息的所有属性，包括 `type`（消息类型）、`question`（问题内容）、`answer`（答案选项）和 `sender`（消息发送者）。
2. 使用 `Dictionary<string, string>` 类型的 `answer` 变量定义答案选项，并将其赋值给 `PollMessage` 对象的 `answer` 属性。
3. 使用 `Newtonsoft.Json` 包中的 `JsonConvert.SerializeObject` 方法将 `PollMessage` 对象序列化为 JSON 格式的字符串，并赋值给 `payload` 变量。
4. 使用 `customType` 来标识数据结构是自定义的 `PollMessage` 数据类型。
5. 调用 `PublishAsync` 方法将 payload 字符串发布到指定的频道中。

示例代码如下：

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
```java
PollMessage message = new PollMessage();
// ...
// 序列化对象
String payload = message.serialize(); // 自定义类型的序列化

PublishOptions options = new PublishOptions();
options.customType = "PollMessage";

mRtmClient.publish(msChannelName, payload, options, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        log(CALLBACK, "send message to channel success");
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        log(ERROR, errorInfo.toString());
    }
});
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
```objc
PollMessage* message = [[PollMessage alloc] init];
// ...
// 序列化对象
NSString* payload = [message serialize]; // 自定义类型的序列化
[rtm publish:channel message:payload option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
    if (errorInfo == nil) {
        NSLog(@"publish success!!");
    } else {
        NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
    }
}];

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
```csharp
using Newtonsoft.Json;
using Agora.Rtm;

// 定义投票消息 PollMessage 类
public class PollMessage
{
    public string type { set; get; }
    public string question { set; get; }
    public Dictionary<string, string> answer { set; get; }
    public string sender { set; get; }
}

// 定义答案选项
Dictionary<string, string> answer = new Dictionary<string, string>()
{
    { "A","Spring" },
    { "B","Summer" },
    { "C","Fall" },
    { "D","Winter" }
};

// 将定义好的答案选项赋值给 PollMessage 类中的 answer 属性
PollMessage message = new PollMessage()
{
    type = "poll",
    question = "Which is your favorite season？",
    answer = answer,
    sender = "Tony"
};

// 把消息负载序列化为 JSON 格式，复制给 payload
string payload = JsonConvert.SerializeObject(message);

// 把 payload 发送到 msChannelName 频道中
public async void PublishStringMessage()
{
    if (rtmClient != null)
    {
        var options = new PublishOptions()
        {
            customType = "PollMessage";
        };

        var (status,response) = await rtmClient.PublishAsync(msChannelName, payload, options);

        if (status.Error)
        {
            Debug.Log(string.Format("{0} is failed, ErrorCode: {1}", status.Operation, status.ErrorCode));
        }
        else
        {
            Debug.Log("Publish Message Success!");
        }
    }
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
```cpp
PublishOptions options;
options.messageType = RTM_MESSAGE_TYPE_STRING;

std::string message = message.serialize();
uint64_t requestId;
rtm_client->publish("channelName", message.c_str(), message.size(), options, requestId);
```

调用该方法后，SDK 会触发 `onPublishResult` 回调并返回 API 调用结果。

```cpp
// 异步回调
class RtmEventHandler : public IRtmEventHandler {
  void onPublishResult(const uint64_t requestId, RTM_ERROR_CODE errorCode) override {
    if (errorCode != RTM_ERROR_OK) {
      printf("publish message failed error is %d reason is %s\n", errorCode, getErrorReason(errorCode));
    } else {
      printf("publish message success\n");
    }
  }
};
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
```swift
let message = PollMessage()
// ...

// 序列化对象
let payload = message.serialize() // 自定义类型的序列化

// 发布消息
rtm.publish(channelName: channel, message: payload, option: nil) { response, errorInfo in
    if errorInfo == nil {
        print("publish success!!")
    } else {
        print("publish failed, errorCode \(errorInfo!.errorCode), reason \(errorInfo!.reason)")
    }
}
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

接收到消息时，你需要通过反序列化将字符串消息恢复成原先的自定义类型。示例代码如下：

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
```java
eventListener = new RtmEventListener {
    @Override
    public void onMessageEvent(MessageEvent event) {
        log(INFO, "onMessageEvent");
        if (event.message.getType() == RtmMessageType.STRING) {
            // 调用自定义的反序列化接口
            PollMessage message = PollMessage.deserialize(event.message.getData());
        }
    }
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
```objc
@interface RtmHandler : NSObject <AgoraRtmClientDelegate>
@end

@implementation RtmHandler
// triggered when received message from remote
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveMessageEvent:(AgoraRtmMessageEvent *)event {

    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    if (channel_type == AgoraRtmChannelTypeStream) {
        NSString* topic = event.channelTopic; // if message from stream channel, user can get topic name
    }

    PollMessage* message = [[PollMessage alloc] init];
    [message deserialize:event.message.stringData];
    NSString* publisher = event.publisher;
}
@end
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
```csharp
// 添加消息事件监听
rtmClient.OnMessageEvent += OnMessageEvent;

private void OnMessageEvent(MessageEvent event)
{
    var channelName = event.channelName;
    var channelType = event.channelType;
    var topic = event.channelTopic;
    var publisher = event.publisher;
    var messageType = event.messageType;
    var customType = event.customType;
    var message = event.message;

    if (messageType == RTM_MESSAGE_TYPE.STRING)
    {
        Debug.Log(string.Format("You have recieved a string type message: {0} from: {1} in channel:{2}", message, publisher, channelName));
        if (customType == "PollMessage" )
        {
            PollMessage newPoll = new PollMessage();
            // 反序列化消息
            newPoll = JsonConvert.DeserializeObject<PollMessage>(message);
            string type = newPoll.type;
            string question = newPoll.question;
            ...
        }
    }
    ...
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
```cpp
class RtmHandler: public IRtmEventHandler {
    void onMessageEvent(const MessageEvent &event) override{
        printf("onMessageEvent");
        if (event.messageType == RTM_MESSAGE_TYPE_STRING) {
            PollMessage* message = new PollMessage();
            message->deserialize(event.message);
        }
    }
};
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
```swift
extension YourClassName: AgoraRtmDelegate {
    // triggered when received message from remote
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
        let channel = event.channelName
        let channelType = event.channelType

        if channelType == .stream {
            let topic = event.channelTopic // if message from stream channel, user can get topic name
        }

        let message = PollMessage()
        message.deserialize(event.message.stringData)
        let publisher = event.publisher
    }
}
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

### 使用 JSON Object [#使用-json-object]

你也可以直接利用 JSON Object 类型对消息进行序列化。JSON Object 是一种轻量级、简单、易读、跨平台的数据交换格式，具有广泛的应用性。 Newtonsoft.Json.Linq 中包含了对 JSON Object 类型的支持。

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
```java
JSONObject jsonObject = new JSONObject();
// 添加键值对
try {
    jsonObject.put("name", "John");
    jsonObject.put("age", 25);
} catch (JSONException e) {
    e.printStackTrace();
}

PublishOptions options = new PublishOptions();
options.customType = "customType";
mRtmClient.publish(msChannelName, jsonObject.toString(), options, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        log(CALLBACK, "send message to channel success");
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        log(ERROR, errorInfo.toString());
    }
});
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
```objc
NSDictionary *dictionary = @{@"key1": @"value1", @"key2": @"value2"};
NSString *jsonString = [self serializeDictionaryToJson:dictionary];
[rtm publish:channel message:jsonString option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
    if (errorInfo == nil) {
        NSLog(@"publish success!!");
    } else {
        NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
    }
}];
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
```csharp
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Agora.Rtm;

// 将投票消息定义成 JSON Object 类型，即序列化
string pollpayload = @"{
        'type':'Poll',
        'question':'Which is your favorite season？',
        'answer' : {
            'A':'Spring',
            'B':'Summer',
            'C':'Fall',
            'D':'Winter'
            },
        'sender' : 'Tony'
    }";

// 将 JSON Object 类型的消息发送到 msChannelName 频道
public async void PublishStringMessage()
{
    if (rtmClient != null)
    {
        var options = new PublishOptions()
        {
            customType = "JObject"
        };

        var (status,response) = await rtmClient.PublishAsync(msChannelName, payload, options);

        if (status.Error)
        {
            Debug.Log(string.Format("{0} is failed, ErrorCode {1}", status.Operation, status.ErrorCode));
        }
        else
        {
            Debug.Log("Publish Message Success!");
        }
    }
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
```cpp
PublishOptions options;
options.messageType = RTM_MESSAGE_TYPE_STRING;

Json::Value jsonObject;
jsonObject["name"] = "John";
jsonObject["age"] = 30;
jsonObject["city"] = "New York";
std::string message = jsonObject.toStyledString();

uint64_t requestId;
rtm_client->publish("channelName", message.c_str(), message.size(), options, requestId);
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
```swift
let dictionary: [String: Any] = ["key1": "value1", "key2": "value2"]

// 序列化字典为 JSON 字符串
let jsonString: String
do {
    let jsonData = try JSONSerialization.data(withJSONObject: dictionary, options: [])
    jsonString = String(data: jsonData, encoding: .utf8) ?? ""
} catch {
    print("Error serializing dictionary to JSON: \(error)")
    jsonString = ""
}

// 发布消息
rtm.publish(channelName: channel, message: jsonString, option: nil) { response, errorInfo in
    if errorInfo == nil {
        print("publish success!!")
    } else {
        print("publish failed, errorCode \(errorInfo!.errorCode), reason \(errorInfo!.reason)")
    }
}
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

接收到消息时，你需要定义一个 JObject 对象，对接收到的字符串进行反序列化。示例代码如下：

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
```java
eventListener = new RtmEventListener {
    @Override
    public void onMessageEvent(MessageEvent event) {
        log(INFO, "onMessageEvent");
        if (event.message.getType() == RtmMessageType.STRING) {
            // Json Object 类型的反序列化
            JSONObject jsonObject = new JSONObject(event.message.getData());
            String name = jsonObject.getString("name");
            int age = jsonObject.getInt("age");
        }
    }
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
```objc
@interface RtmHandler : NSObject <AgoraRtmClientDelegate>
@end

@implementation RtmHandler
// triggered when received message from remote
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveMessageEvent:(AgoraRtmMessageEvent *)event {

    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    if (channel_type == AgoraRtmChannelTypeStream) {
        NSString* topic = event.channelTopic; // if message from stream channel, user can get topic name
    }

    NSString* jsonString = event.message.stringData;
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
    NSString *name = jsonObject[@"name"];
    int age = jsonObject[@"age"];
    NSString* publisher = event.publisher;
}
@end
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
```csharp
// 添加消息事件监听
rtmClient.OnMessageEvent += OnMessageEvent;

private void OnMessageEvent(MessageEvent event)
{
    var channelName = event.channelName;
    var channelType = event.channelType;
    var topic = event.channelTopic;
    var publisher = event.publisher;
    var messageType = event.messageType;
    var customType = event.customType;
    var message = event.message;

    if (messageType == RTM_MESSAGE_TYPE.STRING)
    {
        Debug.Log(string.Format("You have recieved a string type message: {0} from: {1} in channel:{2}", message, publisher, channelName));
        if ( customType == "JObject" )
        {
             // 定义 JObject
            JObject newPoll = JObject.Parse(message);
            // 将接收到的 JObject 对象的各属性的值反序列化为字符串
            string type = newPoll["type"].ToString();
            string question = newPoll["question"].ToString();
            ...
        }
    }
    ...
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
```cpp
class RtmHandler: public IRtmEventHandler {
    void onMessageEvent(const MessageEvent &event) override{
        printf("onMessageEvent");
        if (event.messageType == RTM_MESSAGE_TYPE_STRING) {
             json jsonObj = json::parse(event.message);
        }
    }
};
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
```swift
class RtmHandler: NSObject, AgoraRtmClientDelegate {
    // triggered when received message from remote
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
        let channel = event.channelName
        let channelType = event.channelType

        if channelType == .stream {
            let topic = event.channelTopic // if message from stream channel, user can get topic name
        }

        let jsonString = event.message.stringData
        if let jsonData = jsonString.data(using: .utf8) {
            do {
                if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
                    let name = jsonObject["name"] as? String
                    let age = jsonObject["age"] as? Int
                    let publisher = event.publisher
                }
            } catch {
                print("Error parsing JSON: \(error)")
            }
        }
    }
}
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

## 使用 Protocol Buffers [#使用-protocol-buffers]

[Protocol Buffers](https://protobuf.dev/)（Protobuf）是一种轻便高效的序列化数据结构的方式，具有体积小，效率高，兼容性强，支持跨平台等优点，常被用于一些网络传输效率要求较高的场景，如在线游戏、大规模数据分析、物联网等。

以下示例代码显示了如何在 RTM 中利用 Protobuf 定义一个 `Position` 类型的 `message` 消息结构，完成数据的序列化、传输和反序列化。

1. 使用 Protobuf 定义一个 `Position` 类型的 `message` 消息结构。示例代码如下：

```protobuf
syntax = "proto3";
option cc_enable_arenas = true;
package MessageType;

message Position {

    string  type =1;
    Data data = 2;
    repeated string mentionedUsers = 3;
    string sender = 4;
}

message Data {
    Coordinate coordinate = 1;
    Direction direction =2;
}
message Coordinate {
    float x = 1;
    float y = 2;
    float z = 3;
}

message Direction {
    float pitch = 1;
    float roll = 2;
    float yaw =3;
}
```

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `publish` 发送消息。示例代码如下：

```java
byte[] message = position.ToByteArray(); // 二进制类型的数据
PublishOptions options = new PublishOptions();
options.customType = "customType";
mRtmClient.publish("msChannelName", message, options, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        log(CALLBACK, "send message to channel success");
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        log(ERROR, errorInfo.toString());
    }
});
```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

```java
eventListener = new RtmEventListener {
    @Override
    public void onMessageEvent(MessageEvent event) {
        log(INFO, "onMessageEvent");
        if (event.message.getType() == RtmMessageType.BINARY) {
            // 把二进制格式的消息反序列化为 Position 对象
            Position position = new Position();
            position = Position.ParseFrom(event.message.getData());
        }
    }
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `publish` 发送消息。示例代码如下：

```objc
NSData* raw_message = [position ToByteArray];
NSString* channel = @"your_channel";
[rtm publish:channel data:raw_message option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
    if (errorInfo == nil) {
        NSLog(@"publish success!!");
    } else {
        NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
    }
}];
```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

```objc
@interface RtmHandler : NSObject <AgoraRtmClientDelegate>
@end

@implementation RtmHandler
// triggered when received message from remote
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveMessageEvent:(AgoraRtmMessageEvent *)event {
    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    if (channel_type == AgoraRtmChannelTypeStream) {
        NSString* topic = event.channelTopic; // if message from stream channel, user can get topic name
    }

    Position* position = [[Position alloc] init];
    [position ParseFrom:event.message.rawData];
}
@end
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `PublishAsync` 发送消息。示例代码如下：

    ```csharp
    using Agora.Rtm;
    using Google.Protobuf;
    using MessageType;
    ...

    // 创建一个 Position 对象
    Position position = new Position()
    {
        Type = "positon",
        Data = new Data()
        {
            Coordinate = new Coordinate()
            {
                X = 10,
                Y = 5,
                Z =100
            },

            Direction = new Direction()
            {
                Pitch = 100,
                Roll = 200,
                Yaw =50
            }
        },
        MentionedUsers ={"Tony","Lily"},
        Sender = "Tony"
    };

    // 把 Position 对象转换为二进制格式
    byte[] message = position.ToByteArray();

    // 把二进制格式消息发送到 msChannelName 频道
    public async void PublishStringMessage()
    {
        if (rtmClient != null)
        {
            var options = new PublishOptions()
            {
                customType = "Position"
            };
            var (status,response) = await rtmClient.PublishAsync(msChannelName, message, options);

            if (status.Error)
            {
                Debug.Log(string.Format("{0} is failed, ErrorCode: {1}", status.Operation, status.ErrorCode));
            }
            else
            {
                Debug.Log("Publish Message Success!");
            }
        }
    }

    ...
    ```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

    ```csharp
    // 添加消息事件监听
    rtmClient.OnMessageEvent += OnMessageEvent;

    private void OnMessageEvent(MessageEvent event)
    {
        var channelName = event.channelName;
        var channelType = event.channelType;
        var topic = event.channelTopic;
        var publisher = event.publisher;
        var messageType = event.messageType;
        var customType = event.customType;
        var message = event.message;

        if (messageType == RTM_MESSAGE_TYPE.BIANRY)
        {
            if (customType == "Position")
            {
                Position position = new Position();
                // 把二进制格式的消息反序列化为 Position 对象
                position = Position.ParseFrom(message.GetData<byte[]>());
                string type = position.type;
                ...
            }
        }
        ...
    }
    ```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="flutter" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `publish` 发送消息。示例代码如下：

```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

```dart
// TODO Flutter 请根据上面其他语言的示例代码，提供 Dart 的示例代码

```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="cpp" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `publish` 发送消息。示例代码如下：

```cpp
PublishOptions options;
options.type = RTM_MESSAGE_TYPE_BINARY;

uint64_t requestId;
rtmClient->publish("channelName", position.ToByteArray(), position.ByteLength, options, requestId);
```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

```cpp
class RtmHandler: public IRtmEventHandler {
    void onMessageEvent(const MessageEvent &event) override{
        printf("onMessageEvent");
        if (event.messageType == RTM_MESSAGE_TYPE_BINARY) {
            Position* position = new Position();
            position->ParseFrom(event.message);
        }
    }
};
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="swift" />
2. 在程序中引用 `Google.Protobuf` 和定义好的 `MessageType`，把消息序列化成二进制格式后使用 RTM 的 `publish` 发送消息。示例代码如下：

```swift
let rawMessage: Data = position.toByteArray() // 这里需要确保 `toByteArray` 返回 Data 类型
let channel = "your_channel"

// 发布消息
rtm.publish(channelName: channel, data: rawMessage, option: nil) { response, errorInfo in
    if errorInfo == nil {
        print("publish success!!")
    } else {
        print("publish failed, errorCode \(errorInfo!.errorCode), reason \(errorInfo!.reason)")
    }
}
```

3. 当你接收到消息时，需要对消息进行反序列化。示例代码如下：

```swift
class RtmHandler: NSObject, AgoraRtmClientDelegate {
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
        let channel = event.channelName
        let channelType = event.channelType

        if channelType == .stream {
            let topic = event.channelTopic
        }

        let position = Position()
        position.parse(data: event.message.rawData)
    }
}
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>
