ハンズオン開催
こちらの内容を元にオンラインハンズオンを開催します。1時間程度になりますので、ご興味があればぜひご参加ください。
NCMBのSwift SDKを使ってデモアプリを作ってみます。リアルタイム通信系は人気があるのですが、NCMBでは残念ながらWebSocketは使えません。そこで今回はPieSocketというWebSocketを提供するサービスと組み合わせて、Swift製のチャットアプリを作ってみます。
前回は仕様と画面の説明、Swift SDKの初期化までを説明しました。今回はチャットメッセージの送信について解説します。
コードについて
今回のコードはNCMBMania/Swift_Chat_Demoにアップロードしてあります。実装時の参考にしてください。
チャットメッセージの送信
フローは次のようになります。
- NCMBのデータストアにチャットメッセージを保存する
- WebSocketでメッセージを送信する
NCMBのデータストアにチャットメッセージを保存する
入力されたテキストと、ログインユーザの情報を紐付けてNCMBに保存します。これは ChatInputView の send メソッドに実装します。注意点としてはACLを使ってアクセスコントロールを設定しているところでしょうか。
// チャットメッセージを送信する関数
func send() {
// NCMBのデータストア用のオブジェクトを用意
let obj = NCMBObject(className: "Chat")
// 必要なデータを設定
obj["body"] = message
let user = NCMBUser.currentUser
obj["userId"] = user!.objectId
var acl = NCMBACL.empty // ACL(アクセス管理)を定義
// * = 全員。読み込み可能、編集不可
acl.put(key: "*", readable: true, writable: false)
// ユーザのobjectId。指定したユーザ(投稿者)のみ読み込み可能、編集可能
acl.put(key: user!.objectId!, readable: true, writable: true)
obj.acl = acl // ACLを設定
// 表示名も設定
if let displayName: String = user!["displayName"] {
obj["displayName"] = displayName
}
_ = obj.save() // 保存
message = "" // 入力されていたメッセージを消す
chat.send(obj: obj) // WebSocketで送信
}
WebSocketでメッセージを送信する
保存後、WebSocketでメッセージを送信します。WebSocketでは基本的にテキストメッセージを送信するので、NCMBObjectから必要なデータを取り出して、JSONテキストに変換します。これは ChatScreenModel の makeMessage
メソッドで行います。
// チャットメッセージを送信する関数
func send(obj: NCMBObject) {
// NCMBObjectからメッセージを作成して、送信
webSocketTask?.send(.string(makeMessage(obj: obj)), completionHandler: { error in
if error != nil {
// エラーの場合
print(error)
}
})
}
makeMessage
は必要な情報を集めてDictionaryを作成し、それをJSONテキスト化します。日付だけISO8601形式に変換して入れています。
// NCMBObjectをDictionaryにして、JSON文字列にする関数
private func makeMessage(obj: NCMBObject) -> String {
// Dictionaryの準備
var json = Dictionary<String, String>()
json["objectId"] = obj.objectId! // チャットメッセージのobjectId
json["body"] = obj["body"] ?? "" // チャットメッセージ
json["userId"] = obj["userId"] ?? "" // チャットの送信者
json["displayName"] = obj["displayName"] ?? "" // チャットの表示名
// 投稿日時
let formatter = ISO8601DateFormatter()
json["createDate"] = formatter.string(from: Date())
do {
// Dictionaryを文字列化
let jsonData = try JSONSerialization.data(withJSONObject: json)
return String(bytes: jsonData, encoding: .utf8)!
} catch (let e) {
print(e)
}
return "" // エラーの場合
}
WebSocketでメッセージを送信すると受信時のハンドラである onReceive
メソッドが呼ばれます。ここでは送信時と逆に、受け取ったメッセージを分解してNCMBObjectオブジェクトを作成します。なお、URLSessionWebSocketTaskではメッセージを1度しか受信してくれないので、最後にもう一度受信時のハンドラを設定しておきます。
// メッセージを受け取った時に呼ばれる関数
private func onReceive(incoming: Result<URLSessionWebSocketTask.Message, Error>) {
switch incoming {
case let .success(message): // 正しく受け取れている場合
// メッセージの種類に応じて処理分け(今回はテキストのみ)
switch message {
case let .string(msg):
// テキストをデータ化
let data: Data = msg.data(using: String.Encoding.utf8)!
do {
// JSONとしてパース
let params = try JSONSerialization.jsonObject(with: data) as! Dictionary<String, String>
// NCMBObjectとして作り直し
let obj = NCMBObject(className: "Chat")
obj["displayName"] = params["displayName"]
obj.objectId = params["objectId"]
obj["userId"] = params["userId"]
obj["body"] = params["body"]
obj["createDate"] = params["createDate"]
DispatchQueue.main.async {
self.messages.append(obj) // メッセージの配列に追加
}
} catch {
}
break
case let .data(data):
print(data)
@unknown default:
print("unknown \(message)")
}
break
case let .failure(err):
print(err)
break
}
webSocketTask?.receive(completionHandler: onReceive)
}
これでメッセージの送信処理が完了します。
まとめ
今回はチャットメッセージの送信と、NCMBのデータストアへの保存について解説しました。次回はチャットメッセージの表示と、過去のメッセージを取得する部分を解説します。