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

第47回デスクトップアプリでWindows Live統合

はじめに

前回から少し時間が空いてしまいましたが、今回も引き続きWindows Liveサービスと統合したアプリ開発を可能にするLive Connectを利用したアプリ開発をみていきましょう。今回はデスクトップアプリからの利用を紹介します。また、Live Messengerのステータス更新も紹介します。

デスクトップアプリのWindows Live統合

これまで連載で紹介したLive Connectの利用は、Webブラウザー上で動作するアプリ、またはサーバーサイドで動作するWebアプリからでした。Live Connectは、Webアプリで利用しやすいタイプのAPIコレクションですが、PCクライアントで動作するデスクトップアプリでも利用できます。また、モバイルアプリからも同様に利用可能です。

Live Connectの例ではありませんが、デスクトップアプリのLiveメールやLiveフォトギャラリーでは、図1のようにLiveアカウントでサインインでき、WebのWindows Liveサービスと連携しています。今回紹介する内容で、このようなUIや機能を持つアプリの作成も可能です。

図1 Liveメール 図1 Liveメール

アプリの登録

まず、アプリの登録ですが、デスクトップやモバイルアプリの場合は、アプリのURL(リダイレクト先のドメイン)を設定する必要がありません。アプリケーション設定サイトで、アプリのタイプをモバイルに設定します図2

図2 アプリの設定
図2 アプリの設定

認可フロー

Live Connectでは、OAuth 2.0を使ってユーザーリソースへのアクセス許可を得ます。Live Connectでサポートしている認可方法は2種類あり、今回はImplicit Grant Flowによる方法を使います。詳しくは、第45回で説明していますので、そちらを参照してください。

OAuthの認可フローによって、Access Tokenアクセストークンを取得し、アクセストークンを使ってユーザーリソースにアクセスします。では、デスクトップアプリでの認可フローを簡単にみてみましょう。

①認可画面の表示

認可画面は、Webページでしか用意されていません[1]。通常はWebBroswerクラスなど、各プログラミング言語やライブラリーで用意されているWebブラウザーコントロールによって表示を行うようにします。

認可画面のURLは次の通りです。

  • https://oauth.live.com/authorize?client_id=CLIENT_ID&scope=SCOPES&response_type=token&redirect_uri=https://oauth.live.com/desktop

ここでリダイレクト先を指定する必要がありますが、デスクトップアプリでは、https://oauth.live.com/desktopを指定します。

②アクセストークンの取得

認可処理が完了すると、指定した通りhttps://oauth.live.com/desktopへリダイレクトされます。このときアクセストークンが含まれています。

  • https://oauth.live.com/desktop#access_token=[AccessToken]

上記のURLへ移動したら、アプリは、Webブラウザーコントロールを使ってアクセストークン部分のみを抽出します。これでアクセストークンが取得できました。

アクセストークンの更新

少しだけ補足します。アクセストークンの有効期限は、通常短く設定されています。新しくアクセストークンを得るためには、Refresh Tokenリフレッシュトークンを使います。ただし、Authorization Code Grant Flowというもうひとつの認可フローでなければ、リフレッシュトークンを得られません。

これから紹介するサンプルアプリでは、Implicit Grant Flowを用いているため、そのまま利用できませんが、どちらの認可フローでも、Webブラウザーコントロール等を利用する点は変わりません。

サンプルアプリの作成

それでは、実際にアプリを作ってみましょう。サンプルアプリは、Visual Studioを利用してWPFアプリとして作ります。言語は、Visual Basicを使用します。無償のVisual Basic 2010 Expressで作れます。

サンプルアプリは、.NET Frameworkを使用しますが、Webブラウザーコントロールを利用できる言語やプラットフォームであれば同様の方法でアプリが作れます。もちろん、iOSAndroidでも可能です。ぜひトライしてみてください。

今回のサンプルアプリは、Live Connectとは関係ありませんが、Liveメールなどのアプリに似せて、リボンUIにします。リボンを使うには、Microsoft Ribbon for WPFをダウンロードし、インストールを行います。するとVisual Studioのツールボックスにリボンコントロールが追加されます図3⁠。また、REST APIでJSONのデータ処理に、Json.NETを利用しています。あらかじめ準備してください。

図3 ツールボックス内のリボンコントロール
図3 ツールボックス内のリボンコントロール

それでは、新しいプロジェクトの作成で、WPFアプリケーション プロジェクトを作成し、アプリを作っていきましょう!

サインインウィンドウ

最初に、認証と認可処理を行うサインインウィンドウを作ります。Webブラウザーコントロールを使って、認可画面の表示と、アクセストークンの取得を行います。

新しい項目の追加から、プロジェクトに「ウィンドウ(WPF⁠⁠」を追加します。ここでは、名前をSignInWindow.xamlとします。XAMLコードを編集して以下のようにWebブラウザーコントロールを追加します。

SignInWindow.xaml
<Window x:Class="SignInWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="サインイン" Height="450" Width="560">
    <Grid>
        <WebBrowser x:Name="SignInWebBrowser" />
    </Grid>
</Window>

SignInWindow.xaml.vbファイルを開いて、コードを編集します。サインインウィンドウの使い方として、インスタンスを生成するときにClient IDScopeを渡すようにします。コンストラクタを次のように記述します。

Private ClientId As String
Private Scopes As New List(Of String)

Public Sub New(clientId As String, scope As IEnumerable(Of String))
    Me.ClientId = clientId
    Me.Scopes.AddRange(scope)

    InitializeComponent()
End Sub

ウィンドウを開いた時にWebブラウザーコントロールに認証・認可画面を表示します。ウィンドウのLoadイベントを次のように記述します。認可画面のURLのパラメーターにClient IDとScopeを指定します。

Private Const AuthorizeUriFormat As String = "https://oauth.live.com/authorize?client_id={0}&scope={1}&response_type=token&locale=ja&display=popup&redirect_uri=https://oauth.live.com/desktop"

Private Sub SignInWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    SignInWebBrowser.Navigate(
        String.Format(AuthorizeUriFormat, Me.ClientId, String.Join("+", Me.Scopes)))
End Sub

サインインウィンドウ クラスに、アクセストークンを参照するためのプロパティを次のように追加します。

Private _AccessToken As String
ReadOnly Property AccessToken As String
    Get
        Return _AccessToken
    End Get
End Property

ユーザーが認可処理を終えると、https://oauth.live.com/desktopにリダイレクトされます。WebブラウザーコントロールのNavigatedイベントを使って、表示されているページのURLを取得し、アクセストークンの部分を抜き出します。

Private Sub SignInWebBrowser_Navigated(sender As System.Object, e As System.Windows.Navigation.NavigationEventArgs) Handles SignInWebBrowser.Navigated

    ' 表示しているページの URL が https://oauth.live.com/desktop でなければ処理を抜ける
    Dim redirectUri = New Uri("https://oauth.live.com/desktop")
    If e.Uri.Host <> redirectUri.Host OrElse
       e.Uri.AbsolutePath <> redirectUri.AbsolutePath Then
        Exit Sub
    End If

    ' URL のフラグメント部分から access_token の値を取得する
    If e.Uri.Fragment.Contains("access_token") Then
        Dim items = New Dictionary(Of String, String)
        Dim param = e.Uri.Fragment.Substring(1).Split({"&"c, "="c})

        For i = 0 To param.Length - 1 Step 2
            items.Add(param(i), param(i + 1))
        Next

        If items.ContainsKey("access_token") Then
            ' URL に access_token が含まれていた場合

            _AccessToken = items("access_token")
            Me.DialogResult = True
        End If
    End If

    ' サインインウィンドウを閉じる
    Me.Close()
End Sub

最後にウィンドウを閉じて完了です。以上で、サインインウィンドウ部分ができました。

メインウィンドウ

次は、メインウィンドウを作ります。プロジェクトにデフォルトで作成されているウィンドウのMainWindow.xamlのXAMLコードを以下のように編集します。

MainWindow.xaml
<my:RibbonWindow x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
    Title="アプリ" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <my:Ribbon FontFamily="Meiryo UI">
            <my:RibbonTab Header="ホーム">
                <my:RibbonGroup>
                    <my:RibbonButton 
                        x:Name="SignInButton"
                        Label="サインイン"
                        LargeImageSource="signout.png" />
                    <my:RibbonMenuButton 
                        x:Name="SignOutMenuButton"
                        LargeImageSource="signout.png"
                        Label="名前"
                        Visibility="Collapsed">
                        <my:RibbonMenuItem 
                            x:Name="SignOutMenuItem"
                            Header="サインアウト" />
                    </my:RibbonMenuButton>
                </my:RibbonGroup>
            </my:RibbonTab>
        </my:Ribbon>
    </Grid>
</my:RibbonWindow>

上記のコード編集のとき、ツールボックスからリボンコントロールをドラッグ&ドロップすると自動的にリボンコントロールのライブラリーの参照が追加されますので、利用しましょう。<Window>要素は、上記のようにリボン用のウィンドウに変更します。LiveメールなどのUIにならって、サインインはRibbonButton、サインアウトはRibbonMenuButtonを使います。

サインインボタンをクリックしたときに、作成したサインインウィンドウの表示を行います。MainWindow.xaml.vbファイルに次のコードを追加します。

Private Sub SignInButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles SignInButton.Click

    Dim window = New SignInWindow("*** Client ID を指定***", New String() {"wl.share"}) With {
        .Owner = Me,
        .WindowStartupLocation = Windows.WindowStartupLocation.CenterOwner}

    If window.ShowDialog <> True Then
        Exit Sub
    End If

End Sub

SignInWindowオブジェクトを生成する際に、Client IDとScopeを指定します。Client IDは、適切なものに置き換えてください。Scopeのwl.shareについては後述します。

ここまでを一度実行してみましょう。作成したサインインウィンドウが表示されましたか?図4

図4 サインインウィンドウ
図4 サインインウィンドウ

サインインウィンドウで認可処理を行うとウィンドウが閉じます。その後の処理は、まだ書いていません。次は、サインイン後(認可後)の処理を書いていきましょう。

サインインウィンドウのクラスからアクセストークンを得て、REST APIを呼出します。サインインしたユーザーの名前を取得して、リボンの表示を変更します。コードを次のように変更します。

' 必要な Imports
' Imports System.Net
' Imports System.Threading.Tasks
' Imports Newtonsoft.Json
' Imports Newtonsoft.Json.Linq

' Developer Preview の REST API URI
Private Const LiveUriFormat As String = "https://beta.apis.live.net/v5.0/{0}?access_token={1}"
Private AccessToken As String

Private Sub SignInButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles SignInButton.Click

    Dim window = New SignInWindow(ClientId, New String() {"wl.share"}) With {
        .Owner = Me,
        .WindowStartupLocation = Windows.WindowStartupLocation.CenterOwner}

    If window.ShowDialog <> True Then
        Exit Sub
    End If

    ' (メソッド内は下記のコードを追加)

    Me.AccessToken = window.AccessToken

    Task.Factory.StartNew(
        Function() As JObject

            ' REST API の呼び出し
            Using client = New WebClient With {.Encoding = System.Text.Encoding.UTF8}
                ' ユーザーの情報を JSON データを取得
                Dim json = client.DownloadString(String.Format(LiveUriFormat, "me", Me.AccessToken))
                Return JObject.Parse(json)
            End Using

        End Function).ContinueWith(
        Sub(o As Task(Of JObject))
            ' UI の変更 (サインインボタンの非表示、ユーザーのアイコン表示など)
            Me.SignInButton.Visibility = Windows.Visibility.Collapsed
            Me.SignOutMenuButton.Visibility = Windows.Visibility.Visible
            Me.SignOutMenuButton.Label = o.Result("name").Value(Of String)()
            Dim iconUri = New Uri(String.Format(LiveUriFormat, "me/picture", Me.AccessToken))
            Dim bmp = New BitmapImage(iconUri)
            Me.SignOutMenuButton.LargeImageSource = bmp

        End Sub, TaskScheduler.FromCurrentSynchronizationContext)
End Sub

追加した主なコードは、REST APIの呼び出しとUIの変更部分です。REST API呼出しでは、https://beta.apis.live.net/v5.0/meにHTTP GETメソッドでアクセスして、ユーザーの基本情報を取得しています。URLは、Developer Preview版のものを使用していますので、Live Connectの正式版リリース後には、正式なURLに置き換える必要があります。

UIの変更では、ボタンなどの表示切り替えと名前の表示などを行っています。ユーザーのアイコンは、https://beta.apis.live.net/v5.0/me/pictureにアクセスすると得られます。

サインアウト処理も書いておきましょう。実は、サインアウトする手段は特に用意されていません。ここでは単にUIの表示の切り替えと、取得したアクセストークンの破棄を行います。

Private Sub SignOutMenuItem_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles SignOutMenuItem.Click
    Me.AccessToken = Nothing
    Me.SignInButton.Visibility = Windows.Visibility.Visible
    Me.SignOutMenuButton.Visibility = Windows.Visibility.Collapsed
End Sub

ちなみに、JavaScript APIではlogoutメソッドが用意されています。

以上で、デスクトップアプリによるWindows Liveサービスの統合の基本的な内容でした。実行画面は図5のようになります。

図5 実行結果
図5 実行結果

コードからわかる通り、エラー処理は含まれていません。実際は、ネットワーク接続のエラーや、アクセストークンの有効期限切れによるエラーレスポンス処理などを考慮する必要があります。

表示メッセージの更新

次は、Windows Liveサービスにアクセスする例として、今回は、Live Messengerの表示メッセージ図6を更新します。この表示メッセージについて、以前は、Live Messengerのユーザーの状態などメッセージとして表示するだけの機能しかありませんでしたが、現在は情報を共有するためのツールになっています。ユーザーの更新情報としてlive.comでもその内容を確認でき、共有したいWebサイトや写真・動画のリンクも含めることができます。

図6 表示メッセージ
図6 表示メッセージ

Activityオブジェクト

Live Connectで利用する場合、ユーザーに要求する許可(Scope)の値は、wl.shareです。REST APIでアクセスするパスは、me/shareです。投稿のみ行うことができ、HTTP POSTメソッドでActivityオブジェクトを送信します。JSON形式では次のような値です。

{
    "description": "デスクトップアプリからの利用を紹介します。", 
    "link": "http://gihyo.jp/dev/serial/01/wl-sdk/0047", 
    "message": "第47回 デスクトップアプリでWindows Live統合", 
    "name": "使ってみよう! Windows Live SDK/API", 
    "picture": "http://image.gihyo.co.jp/assets/images/ICON/2008/thumb/TH64_137_wl-sdk.png"
}

Activityオブジェクトの内容は次の通りです。

プロパティ説明
messagestringメッセージ(必須)
linkstring共有する内容のURL
descriptionstring共有する内容の説明
picturestring共有する内容のサムネイル画像のURL
namestring共有する内容のタイトル
sourcestring動画の共有の場合、動画のURL(487文字以下)

上記の内容に加えて、次の読み取り専用の値があります。投稿後のレスポンスは次のように、fromオブジェクトが含まれています。

{
  "from": {
    "name": "梓 中野",
    "id": "xxxxx"
  },
  "message": "第47回デスクトップアプリでWindows Live統合",
  "link": "http://gihyo.jp/dev/serial/01/wl-sdk/0047",
  "description": "デスクトップアプリからの利用を紹介します。",
  "picture": "http://image.gihyo.co.jp/assets/images/ICON/2008/thumb/TH64_137_wl-sdk.png",
  "name": "使ってみよう! Windows Live SDK/API",
  "source": null
}

値は次の通りです。

プロパティ説明
fromstring共有した(投稿した)ユーザーの名前
idstringユーザーのID

サンプルアプリ

さきほど作ったサンプルアプリに、表示メッセージの投稿機能をつけてみましょう。

メインウィンドウのXAMLコードに追記し、<Grid>要素の中に、次のようにテキストボックスとボタンを追加します。

<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Top" Margin="5">
    <TextBox x:Name="StatusTextBox" Width="300" />
    <Button x:Name="PostButton" Content="投稿" Width="80" Margin="10 0 0 0" />
</StackPanel>

投稿ボタンをクリックしたときの処理を、MainWindow.xaml.vbファイルに以下のコードを追記します。

Private Sub PostButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles PostButton.Click
    Dim message = StatusTextBox.Text

    task.Factory.StartNew(
        Function() As JObject

            ' Activity の作成
            Dim activity = New JObject
            activity("message") = message

            ' REST API 呼出し(投稿)
            Using client = New WebClient With {.Encoding = System.Text.Encoding.UTF8}
                client.Headers(HttpRequestHeader.ContentType) = "application/json"
                Dim json = client.UploadString(String.Format(LiveUriFormat, "me/share", Me.AccessToken),
                                               JsonConvert.SerializeObject(activity, Formatting.None))
                Return JObject.Parse(json)
            End Using

        End Function).ContinueWith(
        Sub(o)
            MessageBox.Show("投稿しました")
        End Sub, TaskScheduler.FromCurrentSynchronizationContext)
End Sub

編集は以上です。実行して確認してみてください。上記コードでは、Activityのテキストメッセージのみ設定しています。レスポンスデータの内容は確認していません。実際にはエラー処理などが必要になってきます。

次のようにほかの値も指定すると画像の共有なども可能です。こちらも試してみてください。

' Activity の作成
Dim activity = New JObject
activity("message") = "第47回 デスクトップアプリでWindows Live統合"
activity("link") = "http://gihyo.jp/dev/serial/01/wl-sdk/0047"
activity("description") = "デスクトップアプリからの利用を紹介します。"
activity("picture") = "http://image.gihyo.co.jp/assets/images/ICON/2008/thumb/TH64_137_wl-sdk.png"
activity("name") = "使ってみよう! Windows Live SDK/API"

live.comで表示される更新情報は図7のようになります。

図7 更新情報
図7 更新情報

おわりに

今回は以上です。いかがでしたでしょうか。デスクトップアプリからのLive Connectの利用について紹介しました。モバイルアプリも同じようにWebブラウザーコントロールを使用してアクセストークンを取得します。注釈で少しふれていますが、Live SDK Developer Previewでは、Windows PhoneとWindows 8の新しいアプリタイプのMetro styleアプリでは、サインインコントロールが用意されています。こちらの紹介もまたの機会に紹介したいと思います。

Liveサービスとの連携では、ユーザーの更新情報の投稿を紹介しました。Live Messengerとの統合は、表示メッセージの投稿だけでなく、インスタントメッセージのやりとりも可能です。Live Connect登場以前の方法とは異なり、オープンな規格であるXMPPという方法で接続します。こちらも次の機会に紹介したいと思いますのでお楽しみに。

おすすめ記事

記事・ニュース一覧