使ってみよう! Windows Live SDK/API

第37回Live Messenger Web Toolkit─⁠─WebサイトにLive Messenger機能を追加(5)

Twitter風? Live Messengerアプリ

今回は、第33回から36回までに渡り紹介してきたLive Messenger Web Toolkitを利用して、簡単なTwitter風? のWebアプリを作ってみたいと思います。これまでに紹介したUI Controlsに加え、Live Messenger Libraryとも連携し、アプリケーションを作ります。

作成するアプリケーションは図1のような画面のアプリケーションです。サインイン後、左上のリストからメンバーを選択してインスタントメッセージを送れます。異なるユーザーとの会話のメッセージを1画面に時系列で列挙するところがTwitterぽいと言えるかもしれません……。

図1 Twitter風?Live Messengerアプリ
図1 Twitter風?Live Messengerアプリ

実装する機能はそう多くありません。次の機能を実装します。

  • サインインユーザーの表示
  • オンラインメンバーの表示
  • メッセージの送信
  • メッセージの受信
  • メッセージの表示
  • Bingの検索結果表示

少しオリジナルな機能として「○○で検索」とメッセージを送信または受信するとBingの検索結果を自動で応答するようにします。

検索を除いて基本的な機能ばかりですが、これまでのUI Controlsの使用だけでは実現できません。Live Messenger Libraryを利用してメッセージの送信処理や受信イベント、オンラインユーザーの取得や更新を実装する必要があります。

ベースとなる部分はこれまでと同じようにSDKに含まれるASP.NETのサンプルを元にします。認証部分さえ別のプログラミング言語で実装すればASP.NETである必要はありません。Live Messenger Web LibraryはJavaScriptを記述して利用しますが、画面の操作などにJavaScriptのライブラリーのjQueryも利用します。jQueryについては本連載では解説していません。

画面の作成

最初に本題ではない、見た目の部分を作成してしまいましょう。アプリケーションの画面となるXHTMLは次のように記述します。ASP.NETの場合、Default.aspxに記述します。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="ja-jp"
      xmlns:msgr="http://messenger.live.com/2009/ui-tags">
<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
    <title>Live Messenger Web Toolkit</title>
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="http://www.wlmessenger.net/api/3.7/loader.js" type="text/javascript"></script>
    <script type="text/javascript">
        // ここにコードを追加

        Microsoft.Live.Core.Loader.load(['messenger.ui.styles.core', 'messenger.ui']);
    </script>
    <style type="text/css">
        body {
            background-color: #cde; }

        #content {
            margin: 30px auto;
            width: 800px;
            background-color: White; }

        #console {
            padding: 20px; }

        #consoleLeft {
            float: left;
            width: 520px; }

        #consoleRight {
            float:right;
            width: 220px; }

        #userPicture {
            float: left;
            width: 30px;
            height: 30px; }

        #userMessage {
            clear:both; }

        #text {
            margin: 10px 0 10px 0; }

        #sendButton {
            float:right;
            width: 120px;
            height: 30px; }

        #messages {
            clear: both;
            margin-top: 50px; }

        #messages  ul {
          margin: 0;
          padding: 20px 20px 50px 20px;
          list-style: none; }

        #messages li {
            clear: left;
            border-top: 1px solid #ccc;
            padding: 5px; }

        #messages .picture {
            float: left;
            width: 55px;
            height: 54px; }

        #messages .name {
            padding-right: 5px; }
    
    </style>
</head>
<body>
    <!-- Messenger Appliaction コントロール -->
    <msgr:app   
        id="appTag"   
        application-verifier-token="<%= ApplicationVerifier %>"
        privacy-url="Privacy.html"
        channel-url="Channel.html"
        token-url="RefreshMessengerToken.aspx"
        onAuthenticated="onAuthenticated"
        onSignedIn="onSignedIn"
        onSignedOut="onSignedOut">
    </msgr:app>

    <div id="content">
        <div id="console" style="clear: both;">
            <div id="consoleLeft">
                <!-- コンタクトリストの表示とテキスト入力エリア -->
                <form action="#">
                    <select id="onlineContacts"><option /></select>
                    <span>にインスタントメッセージを送る。</span>
                    <div><textarea id="text" cols="30" rows="2" style="width:512px;"></textarea></div>
                    <input id="sendButton" type="button" value="送信" disabled="disabled" />
                </form>
            </div>
            <div id="consoleRight">
                <!-- サインイン ユーザーの情報表示エリア -->
            </div>
        </div>
        <div id="messages">
            <ul>
                <!-- インスタントメッセージ表示エリア -->
            </ul>
        </div>
    </div>

    <!-- for Debug -->
    <msgr:bar></msgr:bar>
</body>
</html>

Messenger Applicationコントロールについては第34回を参考にしてください。Messenger Web Barコントロールは、デバッグや動作確認のため追加しています。上記でコメントとなっている部分に、これから追記していきます。

ここまでのVisual Studioの環境は図2のようになっています。

図2 Visual Studio 画面
図2 Visual Studio 画面

サインイン処理とユーザー情報の表示・編集

ユーザーのサインイン処理(サインインボタンの設置)と、名前・アイコン・表示メッセージについては、UI Controlsを利用します。それぞれ、Sign Inコントロール、Display Nameコントロール、Display Pictureコントロール、Personal Messageコントロールを使います。また、サインインしていない状態のときは、ユーザー情報を表示しないようにIfコントロールも使います。

XHTMLのサインイン ユーザーの情報表示エリア部分を次のように編集します。

<!-- サインイン ユーザーの情報表示エリア -->
<!-- Sign In コントロール -->
<msgr:sign-in size="medium" theme="blue"></msgr:sign-in>
<msgr:if cid="$user" condition="online"><!-- If コントロール -->
        <!-- 表示アイコン Display Picture コントロール -->
    <div id="userPicture"><msgr:display-picture cid="$user" presence-enabled="false" size="small"></msgr:display-picture></div>

        <!-- 名前 Display Name コントロール -->
    <div><msgr:display-name cid="$user" linked="true"></msgr:display-name></div>

        <!-- 表示メッセージ Personal Message コントロール -->
    <div id="userMessage"><msgr:personal-message cid="$user"></msgr:personal-message></div>
</msgr:if>

Display Pictureコントロールのpresence-enabled属性をfalseにすると、オンラインや退席などの状態を表す枠が表示されません。Display NameやPersonal Messageコントロールは、テキストの編集機能も備えているので、XHTML記述だけで表示と編集処理部分ができます。

サインインしていないときの画面は図3のようになります。

図3 サインインしていない場合の画面
図3 サインインしていない場合の画面

Live Messenger Library

ここまではUI Controlsの設置だけでした。ここからはLive Messenger Libraryを利用してJavaScriptコードを記述していきます。Live Messenger Libraryを利用すると、Live Messenger機能をWebアプリケーションに追加できUI Controlsと比べ柔軟に各種動作を制御できます。

ユーザーオブジェクトの取得

Live Messengerのほとんどの操作はサインインしたユーザーに対して行います。Live Messenger Libraryでは、サインインユーザーを表すUserオブジェクトを取得し、このオブジェクトを元にさまざまな操作をしていきます。Userオブジェクトの取得は第35回でも紹介しています。

Windows Liveサービスとの認証完了後にUserオブジェクトを取得します。Messenger ApplicationコントロールのonAuthenticated属性に認証完了後に呼ばれる関数を指定してあります。ここでUserオブジェクトを取得しましょう。次のJavaScriptのコードを追記します。

var User;

function onAuthenticated(e) {
    // 認証完了

    // User オブジェクト取得
    User = e.get_user();
}

オンラインメンバーの表示

次にユーザーのコンタクトリストのうちオンラインのメンバーのみを取得し、<select>要素内に表示します。コンタクトリストはユーザーがサインインした後に参照し、オンラインユーザー数が変わった場合に処理を行うよう記述します。

ユーザーのサインインとサインアウトのイベントはMessenger Applicationコントロールを使い通知を受けます。onSignedInとonSignedOut属性にそれぞれサインイン・サインアウトしたとき呼ばれる関数を指定します。

オンラインのコンタクトリストは、UserオブジェクトのOnlineContactsプロパティから参照できます。このプロパティはコレクションとして実装されており、内容に変更があった場合、イベントとして通知を受け取れます。

上記の内容をコードで書いてみましょう。サインイン・サインアウトに呼ばれる関数は次のようになります。

function onSignedIn(e) {
    // 送信ボタンの有効化
    $("#sendButton").removeAttr("disabled");

    // オンラインのメンバーに更新があった場合に呼ぶ関数を指定
    User.get_onlineContacts().add_collectionChanged(onlineContactsCollectionChanged);

    // 会話コレクションに更新があった場合に呼ぶ関数を指定
    User.get_conversations().add_collectionChanged(conversationCollectionChanged);
}

function onSignedOut(e) {
    // 送信ボタンの無効化
    $("#sendButton").attr("disabled", "disabled");
}

オンラインのコンタクトはUser.get_onlineContacts()と記述して参照します。Live Messenger Libraryではプロパティをget_, set_のプレフィックスを付けてアクセスします。コレクションの内容が変化したときに発生するCollectionChangedイベントをadd_collectionChanged(関数)のように記述し、イベントと呼ばれる関数を関連付けしています。

上記コードでは、サインイン・サインアウトに合わせて送信ボタンの有効・無効化と、メッセージ送受信時に必要となるイベントの関連付けも行っています。

オンラインコンタクトの内容に変更があった場合、onlineContactsCollectionChanged関数が呼ばれます。ここでメンバー一覧を取得し<select>要素に<option>要素を追加します。<option>要素のvalue属性にはメンバーを一意に表すCIDの値を指定し、メッセージの送信時に使用します。

function onlineContactsCollectionChanged() {
    var list = $("#onlineContacts"); // <select>要素
    var selectedCid = list.val(); // 選択されている項目の value 属性値を取得
    var existed = false;
    list.children().remove(); // 一度 <select>要素内の項目を削除

    // オンラインのメンバー列挙
    for (var i = 0; i < User.get_onlineContacts().get_count(); ++i) {
        var c = User.get_onlineContacts().get_item(i);
        var cid = c.get_cid(); // メンバーの CID 取得
        if (cid == selectedCid) {
            existed = true;
        }
        // <option>要素の追加 value属性には CID を指定し、表示テキストはメンバーの名前を指定
        list.append($("<option>").attr("value", cid).text(c.get_displayName()));
    }

    if (existed) {
        // 一覧の更新前に選択されていた項目を選択
        list.val(selectedCid);
    }
}

メッセージの送信

続いて、インスタントメッセージの送信です。オンラインのメンバーをひとり選択し、その相手にメッセージを送信します。メッセージの送信はメールのように特定の相手へ向けた発信のように思えますが、実際は少し異なります。メッセージを送るには、まず自分と相手との会話(Conversationオブジェクト)を作成し、その会話に対してメッセージを送信します。今回のアプリケーションは複数人で一緒の会話には対応していませんが、複数のメンバーとの会話は、ふたりの会話に新たにメンバーを追加して、その会話に対してメッセージを送信することで実現します。

メッセージを送信するコードは次のようになります。ここでは、送信相手のCIDと送信するテキストを受け取る関数を定義しています。

function sendMessage(cid, text) {
    if (!cid || !text) return;

    var contact = User.get_onlineContacts().findByCid(cid);
    if (!contact) return;

    // メッセージの作成
    var message = new Microsoft.Live.Messenger.TextMessage(text);

    // 会話の作成とメッセージの送信
    var conv = User.get_conversations().create(contact);
    conv.sendMessage(message);

    // メッセージの表示
    var userCid = User.get_presence().get_imAddress().get_cid(); // サインインユーザーの CID
    showMessage(userCid, text);
}

送信するメッセージは文字列からTextMessageオブジェクトを生成して使います。TextMessageクラス以外にもシェイクを表すNudeMessageクラスやアプリケーション独自のメッセージを定義できるApplicationMessageクラスがライブラリーには用意されています。

会話はConversationクラスで表します。User.Conversationsプロパティからサインインユーザーの現在のConversationコレクションを参照でき、Createメソッドで指定したユーザーとの会話を新たに作成します。メッセージの送信は、ConversationオブジェクトのSendMessageメソッドを使います。

同じユーザー相手へのメッセージでも毎回新たに会話を作成するように見えますが、Createメソッドは既に送信相手との会話が作成されていた場合、既存のConversationオブジェクトを返すので問題ありません。メッセージ送信後のコードにあるshowMessage関数は、後で作成します。

送信ボタンをクリックすると上記の関数を実行するようにしておきましょう。

$(function () {            
    $("#sendButton").click(
        function () {
            if (!User) return false;

            var cid = $("#onlineContacts").val();
            var text = $("#text").val();

            // メッセージの送信
            sendMessage(cid, text);

            // 入力されたテキストから検索
            search(text, cid);
            $("#text").val("");
            return false;
        });
});

メッセージの受信

次はインスタントメッセージの受信です。これも送信と同じくConversationオブジェクトを使います。メッセージを受信するとConversationクラスのMessageReceivedイベントが起きるので、そのイベント引数から受信メッセージを得ます。これを実現するには、まずUserオブジェクトのConversationオブジェクトのコレクションの変更を監視し、新しいオブジェクトが追加されたときMessageReceivedイベントを関数に関連付けておきます。

コレクションの変更イベントは、onSignedIn関数内に次のように記述し、関連付けていました。

User.get_conversations().add_collectionChanged(conversationCollectionChanged);

関連付けたconversationCollectionChanged関数は次のように追記します。

function conversationCollectionChanged(sender, e) {
    // 追加された Conversation オブジェクト取得
    var items = e.get_newItems();

    // MessageReceived イベントと関連付け
    $.each(items, function () {
        if (!this.get_closed()) {
            this.add_messageReceived(messageReceived);
        }
    });
}

そしてMessageReceivedイベントで呼ばれる関数は次のように記述します。

function messageReceived(sender, e) {
    switch (e.get_message().get_type()) {
        case Microsoft.Live.Messenger.MessageType.textMessage:
            // Message オブジェクト参照
            var message = e.get_message();

            // 送信者の Contact オブジェクト取得
            var contact = User.get_contacts().findByAddress(message.get_sender());
            if (contact) {                        
                var cid = contact.get_cid(); // 送信者の CID
                var text = message.get_text(); // 受信メッセージのテキスト

                // 受信メッセージの表示
                showMessage(cid, text);

                // メッセージのテキストから検索
                search(text, cid);
            }
            break;
        default:
            break;
    }
}

受信したメッセージの種類を調べ、TextMessageオブジェクトのみ処理しています。Messageオブジェクトには上記のSenderプロパティやTextプロパティ以外にも、オフラインメッセージかどうかを示すIsOfflineMessageプロパティやタイムスタンプのTimestampプロパティなどがあります。

メッセージの表示

インスタントメッセージを送受信したときに、画面にそれらのメッセージを表示するようにしましょう。メッセージの送信者のアイコンと名前はUI Controlsを利用し、メッセージの送受信時に動的に追加します。<ul>要素に以下のような内容を追加するコードを書きます。

<li>
    <div class="picture"><msgr:display-picture cid="..." presence-enabled="false" size="medium"></msgr:display-picture></div>
    <div class="name"><msgr:display-name cid="..." editable="false" linked="true"></msgr:display-name></div>
    <span class="message">メッセージ</span>
</li>

実際のコードは以下の通りです。メッセージの表示(画面へ追加)処理はshowMessageという関数に記述します。既に出てきたコードでもshowMessageを呼び出すようにしています。

function showMessage(cid, text) {
    var li = $("<li>");
    var pic = $("<div>").addClass("picture");
    $create(Microsoft.Live.UI.Messenger.DisplayPictureControl,
                   { cid: cid, presenceEnabled: false, size: "medium" },
                   null, null, pic.get(0));
    li.append(pic);

    var name = $("<div>").addClass("name");
    $create(Microsoft.Live.UI.Messenger.DisplayNameControl, { cid: cid }, null, null, name.get(0));
    li.append(name);

    li.append($("<span>").addClass("message").text(text));
    $("#messages>ul").prepend(li);
}

この動的なUI Controlsの作成は第35回でも紹介しています。

Bingで検索

最後に送受信したメッセージテキスト内に「○○で検索」という内容が含まれていた場合、その内容でWeb検索結果を自動送信するようにします。

Bingでの検索はBing APIを利用します。Bing APIについては本連載で扱っていいませんが、その内容はBingブランド移行前のLive Search API 2.0とほぼ同じです(Bing APIの最新バージョンはLive Search APIのバージョンを引き継いで2.2です⁠⁠。Live Search APIについては第25回で紹介しています。併せて参照してください。

コードは次の通りです。search関数の引数には送受信メッセージのテキストと送信者のCIDを渡すようにします。

var appId = "取得したApplication ID";
function search(text, cid) {
    if (!text.match(/(.+)で検索/) || RegExp.$1.match(/で検索/)) {
        return false;
    }

    // Bing で検索
    $.ajax({
        type: "GET",
        url: "http://api.bing.net/json.aspx",
        dataType: "jsonp",
        data: {
            AppId: appId,
            Version: 2.2,
            Market: "ja-JP",
            Query: RegExp.$1,
            Sources: "web",
            "Web.Count": 1,
            JsonType: "callback"
        },
        success: function (data, dataType) {
            procSearchResult(data, cid);
        },
        jsonp: "JsonCallback"
    });
}

「○○で検索」という形式であれば検索ワード部分を取り出し、jQueryのajaxメソッドを使ってBing APIを非同期で呼出します。受信結果はsuccessオプションに指定した関数が呼ばれるように記述しています。検索結果のメッセージを自動で送信する必要があるため、各呼び出しの元となった送信者のCIDがわかるようにしています。

検索結果を元にメッセージを送信する関数は次のようになります。

function procSearchResult(response, cid) {
    if (response.SearchResponse.Errors) {
        var text = "";
        $.each(response.SearchResponse.Errors, function () {
            text += this.Message + "\n";
        });
        alert(text); // error!
        return false;
    }

    var text = "";
    if (response.SearchResponse.Web.Total == 0) {
        text = response.SearchResponse.Query.SearchTerms + "の検索結果 (0件)";
    } else {
        text = response.SearchResponse.Query.SearchTerms + "の検索結果 (" +
               response.SearchResponse.Web.Total + "件)\n" +
               response.SearchResponse.Web.Results[0].Title + "\n" +
               response.SearchResponse.Web.Results[0].Url;
    }

    // 検索結果を送信
    sendMessage(cid, text);
}

以上で完了です。実際にアプリケーションをWebに配置して確認してみましょう。

おわりに

いかがでしたでしょうか。今回はここまでです。Live Messenger Web Toolkit連載のまとめというわけではないですが、簡単なアプリケーションを作成しました。本連載では作成できませんでしたが、Webサーバー上のデータベースを用意してユーザー情報を保存できるようにし、前回のアプリケーションコンタクトを活用するとより本格的なLive Messengerと統合したWebアプリケーションが作成できるかと思います。Twitterと連携もおもしろいかもしれません。

今回のアプリケーションは、例外処理や送信失敗時の処理などは実装していませんので実用に耐えるものにするには、もう少し作り込みが必要です。より詳細な情報は、Live Messenger Libraryのリファレンスをご確認ください。

おすすめ記事

記事・ニュース一覧