AWS + Nginx + Node.js + iOS(Swift) でリアルタイムチャットアプリを作ろう

こんにちは、毒きのこです。

皆さんいかがお過ごしでしょうか。ウチは冬休みに入りました。今年お世話になった方、色々有難うございました。来年もまた宜しくお願い致します。

今回のお題はズバリ「AWS + Nginx + Node.js + iOS(Swift) でリアルタイムチャットアプリを作ろう」ですが、なぜこれを書こうと思ったか。

スマホアプリでチャットを導入するって、個人で開発するアプリではなかなかボリューム的にはないかなぁと思ってて、その理由としてはiOS/Androidのクライアント側だけではなくサーバーサイドの実装も色々必要になってくるからです。ボリュームとしてもそこそこある感じです。

そこでググってみたら色々出てくるではありませんか。iOSだけを例に取らせていただきますが、その内容のほとんどがFirebaseを使ったものでした。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-22-14-24-23

トップ記事はほとんどFirebaseとの連携だ〜

まぁそれだけFirebaseが優秀でいかにサーバーレスで簡単にリアルタイムチャットのようなサービスを組みやすいか、ってことですね。

これ自体は全然素晴らしいことで良いのですが、僕は結構昔にParseというサービスを使ってとあるiOS/Androidアプリを開発していた時期がありました。ご存知Parseはサービスを終了することとなったのですが、その時の損害というかダメージが大きかったが若干トラウマになっています…。

ParseやFirebaseといったようなサービスに頼るとロックインの危険性があるってわけですね。だからといってAWS等が必ずや永遠に続くサービスで安心かというとそういうわけでもありませんが。

そこでググっても全然出てこなかったので、Firebaseを使わず同じくらいのボリュームのものを自前で作るとどれだけ大変なのか、実際にやってみることにしました。

使用環境 (ちなみにiOSクライアント側以外は基本最新にしとけば問題ないです)

  • 開発マシン (Mac)
  • AWS (Ubuntu 14.04 LTS)
  • Nginx (1.10.0)
  • Node.js (7.2.1)
  • Swift (3.0) + Xcode8.2

また今回は一部html, cssのソースは下記記事書いてくださった方のを使わせてもらってます。こちらのFirebaseではなく自鯖による実装版、みたいな感じでみてもらえればと。

swiftでリアルタイムチャット – Qiita
今回のチャットを作るにあたってはFirebaseという端末同志のやり取りにリアルタイム性を持たせることに特化したバックエンドサービスを使ってリアルタイムチャットを構築していきます。
Firebaseの説明、使い方はこちらの記事の「ア…

AWS

インスタンスの作成と設定

まずAWSでUbuntuサーバーを立ち上げます。構成ですが、1:1のチャットを実現するだけなのでスペックは最小のもので問題ありません。

インスタンスはt2.nano、セキュリティグループはインバウンド側22, 80, 3000, 443を開けておいてください。3000はNode.jsで使うPort、443はSSLです。(今回SSLは使ってませんが)

この1つのインスタンスにNginx + Node.jsを載せる感じですね。今回は簡単サンプルなのでDBは使いません。

ファイアウォールの設定

Ubuntuのファイアウォール設定ではufwを使用します。ufwはiptablesのラッパーでこれを使用することで簡単にファイアウォールの設定が出来ます。以下のコマンドでインストールします。

インストールが完了したらファイアウォールを有効に。

とりあえず必要なポートを全て開けておきましょう。

設定が完了したらリロードします。

キーペアファイルを使ってssh接続確認しましょう。無事接続も出来たらAWS側の設定は一旦終わり。実際は他にもやるべき初期設定等ありますが、ここでは割愛。

Nginx

インストール

では立ち上げたUbuntuサーバーに対しNginxをインストールします。インストール方法はソースからやれば細かい設定も出来ますが、ここでは一番最短なパッケージから入れます。

インストール出来たか確認。

Nginxを起動しましょう。

ブラウザでホスト名を打ち込んで「Welcome to nginx!」という画面が出れば無事起動しています。

表示するNode.jsのパス等を設定

Nginxがインストールできたら次はlocationディレクティブ等追記し、実際ブラウザからアクセスするための設定を行います。

以下を入力し設定ファイルを開きます。

後から設定するNode.jsの特定のhtmlを表示させるためにバーチャルサーバーの定義、locationディレクティブ等の設定を行います。

httpディレクティブ内に上記server、locationディレクティブを追記します。後ほど/var/www/app/内にchatディレクトリを作成しその中にNode.jsのプロジェクトを作成します。そのため、http://[ドメイン]/chat/chat.html でアクセスするために上記設定を行っています。

nginx.confを設定したら、以下でNginxを再起動し反映させます。

Node.js

Node.jsのインストール

UbuntuサーバーにNode.jsをインストールします。こちらも色々インストールの仕方があるのですが、一番手っ取り早い方法でいきます。node.jsとパッケージ管理ツールをまとめてインストールします。

次にNode.jsのバージョン管理に関して。nvmが有名ではありますが、npmのnをここでは使います。

今度はインストールしたnを使ってNode.jsとnpmを最新版にします。

それではNode.jsのインストールは一旦ここで終了。

サーバーサイドの実装

ブラウザ側チャット画面と、そのサーバーサイドの実装を行います。サーバーサイドがNode.js、ブラウザ側のチャット画面はHtml5 + Javascript(JQuery) +CSSを使って作成します。

ローカルの開発環境ですがNode.jsやPHP, Java開発など一般的なWeb開発に最適なIDEがあるのでそれを使います。その名もIntelliJ IDEA。日々Web開発するエンジニアにとっては普通に買う価値アリなので、まだ買ってない方はこれを機にぜひ。

まずIDEAでchatという名前でStatic Webプロジェクトを作成してください。プロジェクトが作成されたら、jsファイル等を追加して行って以下のようなファイル構成にします。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-22-14-49-53
「node_modules」ディレクトリだけ無視してください。こちらローカルでnpmインストールして出来ただけなので実際はなくて大丈夫です。

それでは1つずつソースを書いていきます。

まずpackage.jsonから。
※ここではexpressなど入れてますが今回使用しないので実際はmimeとsocket.ioだけで問題ありません。

次にNode.jsのサーバーとして起動させるためのserver.js

一応存在しないパス等が来た場合にエラーを返す関数を用意し、後は普通にport3000でlistenします。

次に var chatServer = require(‘./lib/chat_server’) でも指定しているchat_server.jsを。こちらはsocket.ioの具体的な処理を記述します。

ここまでがサーバー側の実装。次にブラウザの画面周りに関わるファイルを作成していきます。チャット画面にあたるchat.htmlです。こちらsocket.io.jsやjqueryらを読み込むのを忘れずに。

Chatクラスを作成するファイルです。

チャットの表示周りを行うファイルです。

ちょっとサンプルなので色々雑ですが、ブラウザ側は「山田 太郎」という名前で固定です。この山田 太郎と、この後作成するiOS側のユーザーが1:1のチャットを行い、その描画周りをこのファイルで行っている感じです。

最後にCSS。チャット画面や吹き出しなどをレイアウトします。

これでNode.js、ブラウザ側の実装はおしまいです。

サーバーへデプロイ

作ったこれらをサーバーへ上げます。デプロイツールなど色々ありますが、IDEAにはDeployment機能があるのでそちらを使います。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-22-15-21-02

sftpで「chat」というのを作成。「Connection」タブではサーバーの情報を書き込みます。User Nameは「ubuntu」、Autho typeをKey pairにしてAWSのpemを指定します。SFTPはサーバーのホスト名ですね。

ちなみに「Test SFTP Connection」ボタンで実際にssh接続による疎通確認が取れますので、ここで失敗してたら設定が間違っています。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-22-15-21-12

次に「Mappings」タブを開いてマッピングを行います。こちらは実際サーバーにあげる場所を指定します。 /var/www/app/chat ですね。

設定が完了したら、OKを押して終了しましょう。

IDEA画面左側のエクスプローラーのプロジェクト名のところにカーソルをやって⌘ + alt + shift + x でサーバーへアップします。(右クリックからのUpload to chatというのを選んでもOKです)

AWSでsshログインし、実際 /var/www/app/chatができてるか確認しましょう。また所有権やアクセス権等がちゃんと設定されてないかもしれないので、その場合は/var/www/app上で以下をしておきましょう。

サーバー側に必要なモジュールをインストールするために/var/www/app/chat上で以下を叩きます。

これでサーバーサイド側はおしまい。最後、iOSのアプリ側の作成を行います。

iOS(Swift3 + Xcode8.2)

プロジェクトの作成

Xcodeを起動し、「chat」プロジェクトを作成します。最初に作られるViewControllerは使用しないので消してしまっても構いません。では早速必要なクラスなどを作成していきます。

まず今回アプリ側とサーバーでNode.jsを使ったリアルタイムチャットを行うのですが、それにはWebSocketを使って実現します。Socket.ioのライブラリは色々あるのですが「Socket.IO-Client-Swift」が一番使いやすかったのでこちらを採用します。

socketio/socket.io-client-swift
Contribute to socket.io-client-swift development by creating an account on GitHub.

次にアプリ側でチャットのUIを簡単に作成してくれる優秀なライブラリがあるので、今回はそちらも使います。

jessesquires/JSQMessagesViewController
JSQMessagesViewController – An elegant messages UI library for iOS

どちらもPodfileを作成し、そちらに記入します。

こちら作成し追記したらターミナル上で’pod install’しxcworkspaceを作成。こちらで次からは起動してやります。

※Xcodeが起動したら一度ビルドしてエラーを解除してやります。

次にWebSocket周りを管理するマネージャークラスを作成します。

基本的なon、emitの関数らが定義されたマネージャークラスですね。

次にチャット画面となるChatViewControllerを。

超最低限の実装ですね。 とりあえずJSQMessagesViewControllerの仕様に従ってsenderIDやらnameなんかを設定してやります。

ちなみにこのライブラリ、デフォルトで添付のためのボタンなんかも表示されますが、その受け皿を用意してないのでこのままだとタップすると落ちます。まぁドキュメントも充実してますし(Objective-Cですが)、簡単なんでファイル添付等にも挑戦したい方はやってみると良いかもしれません。

最後、StoryboardでCustom Classの設定を忘れずに。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-22-15-56-22

これでiOS側は完了です。JSQMessageViewControllerのおかげでチャット周りの描画だのなんだのってのをほとんど実装しないですみましたね。これは楽。

これで一通り実装は終わりです。実際の動作を見てみましょう。

動作確認

全ての準備が出来ましたらAWSの/var/www/app/chat上で以下を実行してNode.jsからサーバーを立ち上げましょう。

これでアプリやブラウザからWebsocketへのコネクションが貼れるようになります。
さて、実行したらどうなるか。

はい、無事に動いてますね。それととりあえず言えることは動画取るのが一番難しいですね。苦手ですこういうのは…。

一番左がチャットのログをとって表示してます。真ん中がブラウザ画面ですね。こっちは「山田 太郎」としてチャットに参加してます。一番右がiOSのシミュレーター画面です。「毒きのこ」でチャットに参加してます。問題なく動作してますね。もちろん実機を使っても確認可能です。

おわりに

どうでしょうか、実際これFirebaseを使った場合と違いチャットのやりとり履歴なんかは残っていません。それをやるなら別途DBサーバーをたてるか一般的にはRedisを使って保存・表示等してやらないと行けません。

そう考えるといかにFirebaseが楽かがわかりますね。基本的な設定さえしてしまえばサーバーサイドを一切考えずにフロント側の開発だけに集中できますから。

今回はiOSでのリアルタイムチャットアプリということで、諸々自前で実装し実現させてみました。ベンダーロックインのようなリスクを恐れる方は自前で作ってみてはいかがでしょうか。

※ただこれ1:1の、しかもデータが一切残らないかつログイン機能等もなにもないんで簡単に作れてはいますが、複数人チャットやパフォーマンス等考慮するとなってくるとやはりサーバー・インフラ側は結構大変なので、サーバーレスで簡単に実現出来る時代が早く来てほしいですたいね(´・ω・`)もう来てるのかな僕が知らないだけで。

それでは良い開発ライフを〜。

あと今回のプロジェクト一式をGitHubにあげておくので色々いじってみたい!って方は是非いじいじしてみてください。

daihase/Realtime_Chat_App
Contribute to Realtime_Chat_App development by creating an account on GitHub.
スポンサーリンク
レクタングル(大)広告
レクタングル(大)広告