Monacaプロジェクトのインポート
ベースになるMonacaプロジェクトは下記になります。こちらをクリックしてインポートしてください。
仕様について
このアプリの主な機能です。
- 認証画面
- ID/パスワード認証を利用します
- チャット画面
- チャットで扱うのは次のデータです
- 送信者名
- メッセージ
- チャットメッセージは閲覧は誰でも可能、更新や削除は本人のみ可とします
- 参加ユーザ一覧画面
- 同じチャットに参加しているユーザを一覧表示します
チャット自体はWebSocketサービスを利用します。WebSocketで送ったメッセージは保存できませんが、mBaaSのデータストアを使うことで認証とメッセージの保存と再現が可能です。
利用した技術
今回はjQueryとOnsen UIを利用しています。
画面
チャットアプリの画面は全部で3つです。
- ログイン/新規登録画面
- チャット画面
- ユーザ一覧画面
チャット画面
最初に表示される画面です。ただし認証されていない場合はログイン/新規登録画面へ遷移します。この画面ではメッセージを入力して送信します。
ログイン/新規登録画面
ログインと新規登録は処理が似ているので一つの画面にまとめてしまいました。ID/パスワードで認証していますが、追加で表示名も登録できます。
ユーザ一覧画面
チャットに参加しているユーザを一覧する画面です。
アプリ全体の処理
まず www/js/app.js
の中で、NCMBを初期化します。これはアプリ全体に関わる処理なので、JavaScriptファイルに記述しています。
const applicationKey = 'YOUR_APPLICATION_KEY';
const clientKey = 'YOUR_CLIENT_KEY';
const ncmb = new NCMB(applicationKey, clientKey);
なお、app.jsの中ではWebSocket周りを取り扱うChatクラスを作成しています。こちらは後述します。今回はPieSocketを利用しています。
チャットは複数人で行わないと楽しめないので、PieSocketのAPIキーは下記のものを設定してください。ハンズオン終了後、削除します。
const apiKey = 'oZ49l7gDlA5SSfvwwSurwrFNOB0EBVLLVKM1MrLw';
Chatクラスについて
js/app.js
に実装しているChatクラスの概要です。これはWebSocketのハンドリングをしています。
コンストラクターで、イベントをハンドリングしています。
- this.socket.onopen = () => this.onopen();
- this.socket.onmessage = (message) => this.onmessage(message.data);
WebSocketが接続されるとonopenが呼ばれます。
// WebSocketに繋がった際のイベントで呼び出されるメソッド
onopen() {
this.open = true;
}
メッセージを受信した時には onmessage が呼ばれます。今回は3種類のメッセージを想定しています。
- login
ログインした時に通知して、既存のユーザにログインをお知らせ - ping ほかのユーザに対して自分が接続中であると通知
- chat チャットメッセージを送信
メッセージ送信
メッセージ送信は send メソッドを使います。
chat.send('chat', message);
認証の判定
まず大事なのは認証の判定です。これは www/chat.html
に実装しています。
ons.getScriptPage().onInit = async function() {
const user = ncmb.User.getCurrentUser();
if (!user) {
// 未ログインの場合
return $('#formNav')[0].pushPage('login.html');
}
try {
// セッションの有効性を確認
await ncmb.DataStore('Hello').fetch();
} catch (e) {
// セッションが無効な場合エラーになるので、その場合はlocalStorageの認証データを削除
localStorage.removeItem(`NCMB/${ncmb.apikey}/CurrentUser`);
ncmb.sessionToken = null;
// ログイン画面に遷移
return $('#formNav')[0].pushPage('login.html');
}
}
ログイン/新規登録画面
ログイン/新規登録画面(login.html)ではユーザ名とパスワード、そして表示名(displayName)を入力しています。今回は処理を簡略化するため、新規登録とログイン処理を一つにまとめています。
認証処理
認証を実行する処理は #login
をクリックした際のイベントで作成していきます。
$('#login').on('click', async e => {
// この中に実装します
});
まず最初に必要な変数を揃えます。
// 実装済みです
const userName = $('#userName').val();
const password = $('#password').val();
const displayName = $('#displayName').val();
次にユーザ登録処理を行います。もしすでに登録されている場合はエラーになりますので、try/catchでエラーが出ないようにします。
// 実装済みです
try {
await registerUser(displayName, userName, password);
} catch (e) {
}
registerUserを実装してください。
// 新規ユーザ登録処理です
async function registerUser(displayName, userName, password) {
const user = new ncmb.User();
user
.set('displayName', displayName)
.set('userName', userName)
.set('password', password);
await user.signUpByAccount();
}
そしてユーザ登録が済んだら、そのユーザ名とパスワードでログイン処理を実行します。こちらはエラーをハンドリングします。エラーになるとしたら、パスワードの不一致になるでしょう。ユーザ名は表示してもいいように、Aclを誰でも表示可としています。ログイン処理が完了したら日報入力画面 form.html
に戻ります。
この時、チャットでloginイベントを送信しています。すでにチャット画面にいるほかのユーザはこのメッセージを受け取ったら、ユーザ一覧の中に追加しています。
// 実装済みです
try {
await loginUser(userName, password);
// ログインをWebSocketで通知します
chat.send('login', null);
$('#formNav')[0].pushPage('form.html');
} catch (e) {
ons.notification.alert('ログイン失敗しました。ユーザ名、パスワードを確認してください');
return false;
}
loginUserを実装してください。
// ユーザログイン処理です
async function loginUser(userName, password) {
await ncmb.User.login(userName, password);
const user = ncmb.User.getCurrentUser();
const acl = new ncmb.Acl();
acl
.setPublicReadAccess(true)
.setUserWriteAccess(user, true);
await user.set('acl', acl).update();
}
チャット画面について
初期表示を作る
ログインした後、チャット画面に戻ってきたらチャットのログを表示します。これはmBaaSのChatクラスにあるデータを表示します。
ons.getScriptPage().onShow = async function() {
$('#chats').empty();
// mBaaSのデータストアからデータを取得する
// 元々 const chats = []; となっている部分を消して実装してください
const Chat = ncmb.DataStore('Chat');
const chats = await Chat.limit(100).fetchAll();
// データを書き込む
for (const chat of chats) {
writeChat(chat.get('user'), chat.get('message'));
}
}
writeChatはHTMLを表示しているだけです。自分のメッセージとほかのユーザからのメッセージかで色や左右を分けています。
function writeChat(name, message) {
const user = ncmb.User.getCurrentUser();
let html = '';
if (user.get('displayName') === name) {
// 自分のメッセージ
html = `
<ons-list-item modifier="nodivider">
<div class="right">
<ons-button style="background-color: green">${message}</ons-button>
</div>
</ons-list-item>
`;
} else {
html = `
<ons-list-item modifier="nodivider">
<ons-button>${message}</ons-button>
<span class="list-item__subtitle">${name}</span>
</ons-list-item>
`;
}
$('#chats').append(html);
}
メッセージを送信する
次にメッセージを送信する処理です。これは #send
をクリックした際に実行します。chatクラスのsendメソッドを使ってメッセージを送信します。
$('#send').on('click', e => {
const message = $('#message').val();
if (message.trim() === '') return true;
chat.send('chat', message);
$('#message').val('')
saveToNCMB(message);
});
saveToNCMBはChatクラスにデータを保存しています。ACLは誰でも読み込み可能、編集は本人のみとしています。
saveToNCMBを実装してください。
async function saveToNCMB(message) {
// データストアのChatクラスを利用
const Chat = ncmb.DataStore('Chat');
// インスタンスを作成
const chat = new Chat();
// ログインユーザを取得
const user = ncmb.User.getCurrentUser();
// ACLを準備
const acl = new ncmb.Acl();
acl
.setPublicReadAccess(true) // 誰でも読み込み可能
.setUserWriteAccess(user, true); // 書き込みは本人のみ
// データをセットして保存処理を実行
await chat
.set('user', user.get('displayName'))
.set('message', message)
.set('acl', acl)
.save();
}
新規メッセージが来ると chat.message イベントが呼ばれますので、それを使ってチャットに書き込みを行います。
// 新しいメッセージが届いた時の処理
chat.message = function(user, message) {
writeChat(user, message);
}
ユーザ一覧画面を作る
ユーザ一覧画面はmBaaSの機能は使っていません。chat.usersを一覧表示しているだけです。
// すでに記述済み
ons.getScriptPage().onShow = function() {
$('#users').html(chat.users.map(u => `
<ons-list-item>
<div class="center">${u}</div>
</ons-list-item>
`));
}
まとめ
今回はチャットIDが固定ですが、これを異なるものにすればチャット部屋を複数作成できます。mBaaSと組み合わせることで認証を使ったり、チャットの記録を取れるようになります。画像をファイルストアに保存するのも難しくないでしょう。ぜひカスタマイズしてみてください。
今回のハンズオンで利用したmBaaSの機能は次の通りです。
- 会員登録(ID/パスワード)
- 会員認証(ID/パスワード)
- データストア登録/更新
- データストア検索
mBaaSには他にもたくさんの機能があります。ぜひほかのハンズオンで体験してください。