はじめに
仕事でiOSアプリのメッセージ機能をアーキテクチャから作り直す機会をいただいたので、その時にわかったMessageKitの概要について書いていこうと思います。
※自社の仕様に依存している技術が多々あります。
この記事で説明する内容
- MessageKitのインストール
- メッセージ履歴の表示
- ソケットでのメッセージ送信
- メッセージのインサート
MessageKitのインストール
pod 'MessageKit', '~> 3.7.0'
バージョンは3.7.0を使用しています。
上記をPodFileに記述してターミナルでpod install
メッセージ履歴の表示
import MessageKit
メッセージ画面にしたいVCに上記を記述すれば、messagesCollectionViewとしてメッセージのセルをもつcollectionViewを管理できます。
// メッセージ入力部分の設定
messageInputBar.delegate = self
// メッセージ表示の設定
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self
// MARK: - MessagesDataSource
extension YourViewController: MessagesDataSource {
func currentSender() -> SenderType {
return Sender(id: "your_user_id", displayName: "Your Name")
}
func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
return messages[indexPath.section] //sectionで順番を管理しているのがミスしがちなポイント
}
func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int {
return messages.count
}
}
// MARK: - MessagesLayoutDelegate
extension YourViewController: MessagesLayoutDelegate {
// カスタムなレイアウト設定があればここに追加
}
// MARK: - MessagesDisplayDelegate
extension YourViewController: MessagesDisplayDelegate {
// カスタムな表示設定があればここに追加
}
// MARK: - MessageInputBarDelegate
extension YourViewController: MessageInputBarDelegate {
// メッセージ入力部分のデリゲートメソッドがあればここに追加
}
上記のコードが最低限あればメッセージの表示ができます。
messagesにはその時々のメッセージを、指定された型に合わせて配列で用意すればOKです。
以下が1つのメッセージの型です。
Message(sender: Sender(id: "1", displayName: "User1"), messageId: "1", sentDate: Date(), kind: .text("Hello, World!"))
ソケットでのメッセージの送信
import Foundation
import Network
class SocketManager {
private var connection: NWConnection?
init() {
// ソケットの設定
let host = "your_server_host"
let port = "your_server_port"
// 接続先のエンドポイントを作成
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(host), port: NWEndpoint.Port(port)!)
// ソケットの接続
connection = NWConnection(to: endpoint, using: .tcp)
// データの受信ハンドラを設定
connection?.receiveMessage { (data, context, isComplete, error) in
if let data = data, !data.isEmpty {
// データを受信したときの処理
let receivedString = String(data: data, encoding: .utf8)
print("Received data: \(receivedString ?? "")")
}
if isComplete {
// ソケットの受信が完了したときの処理
}
}
}
func start() {
// ソケットの開始
connection?.start(queue: .global())
}
func send(message: String) {
// メッセージをデータに変換
if let data = message.data(using: .utf8) {
// ソケットにデータを送信
connection?.send(content: data, completion: .contentProcessed({ (error) in
if let error = error {
print("Error sending data: \(error)")
} else {
print("Data sent successfully")
}
}))
}
}
func stop() {
// ソケットの停止
connection?.cancel()
}
}
// 使用例
let socketManager = SocketManager()
socketManager.start()
socketManager.send(message: "Hello, Server!")
上記でStringのメッセージを送ることができます。
String以外の送る方法があるかもしれませんが、現状使用している技術はStringの送信だけです。
&や\、;等の記号を用いて区切りを入れるなどして画像や動画のIDを送信している形をとっています。
メッセージのインサート
メッセージのインサートは簡単で先ほどのメッセージの型
Message(sender: Sender(id: "1", displayName: "User1"), messageId: "1", sentDate: Date(), kind: .text("Hello, World!"))
をクライアントで作成してmessagesの配列に追加して
messagesCollectionView.reloadData()
でメッセージ画面をリロードするだけでインサートできます。
最後に
以上で簡易的ですが、メッセージ周りを実装する上での基本的な機能の紹介を終わります。
弊社では、経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談しましょう!