はじめに
今回と次回は、少し予告していたように、SkyDrive APIを利用した簡単なアプリ開発として、SkyDriveと連携するPowerPointアドインを作ります(図1 ) 。
図1 SkyDriveと連携するPowerPointアドイン
これまでの連載で紹介してきたように、Live SDK およびAPI群のLive Connect を利用すると、SkyDrive・Hotmail・Messengerなどのサービスと統合したアプリ開発が可能です。このLive Connectを利用したアドインを作ります。前回までの内容を見ていない方でも、とりあえずコードを記述していけば作れるよう構成していますので、ぜひトライしてみてください。
前回 に少しふれたLive SDK 5.1 Previewは既に正式にリリースされ利用できるようになっています。また、開発者向けのWebサイト「Live Connect デベロッパーセンター 」の内容もリニューアルされ、日本語対応も進んでいます。
図2 Live Connect デベロッパーセンター
また、今回アプリからアクセスするSkyDriveは、4月24日に、予告されていたWindows・Mac向けのクライアントアプリのリリースと、サービス内容が刷新され、使いやすいサービスとなっています。詳しくは、Building Windows 8 や、各種ニュース記事などを確認してください。
PowerPointアドインの開発
今回は、SkyDriveと連携したMicrosoft Office PowerPointのアドインを作ります。
Windows PhoneはSkyDriveとシームレスに連携していて、簡単に撮影した写真をSkyDriveにアップロードできます。通常、カメラロールというフォルダーに写真はアップロードされます。このアップロードされた最新の写真1枚を、スライドショーの最中にスライドに追加して表示するアドインを作ります。
プレゼンテーション中にWindows Phoneを使ってデモ画面や会場を撮影してSkyDriveにアップロードすると、スライドにその場で反映され、少しだけ凝ったプレゼンテーションが可能かもしれませんね。もちろん、写真のアップロードは、iPhone・iPadのSkyDriveアプリやSkyDrive.comを利用して構いません。
アドインでは、あらかじめスライドに写真をダウンロードして表示する場所にマーカーとなるオートシェイプの図形を配置して使います。
開発環境
開発にはVisual Studioを使用します。Officeアドインを作成するにはVisual StudioのProfessional以上が必要です。今ならVisual Studio 11 Beta を使ってみるのも手かもしれません。
ここでは、Visual Studio 11 BetaおよびPowerPoint 2010を使用し、言語はVisual Basicを選択します。
アプリの登録
はじめに、作成するアプリ(ここではアドイン)をあらかじめLiveサービスに登録します。登録にはLiveアカウントが必要です。Live Connectデベロッパーセンター のマイアプリ (図3 )へアクセスします。
図3 マイ アプリケーション
「アプリケーションの作成」から新しいアプリを登録します(図4 ) 。はじめてアプリを作る場合は、最初からこのページが表示されています。
図4 アプリの登録
アプリケーション名と言語を入力し、使用条件の確認後、同意するボタンをクリックします。登録が完了すると、Liveサービスにアクセスするときに必要な、クライアントID とクライアントシークレット が得られます。さらに、「 アプリケーションの設定ページ」に移動し必要な情報を入力しましょう(図5 ) 。作成するアドインでは、クライアントIDのみ使います。
図5 アプリの設定ページ
今回のようなデスクトップクライアント用のアプリ、また、Webアプリやモバイル クライアントアプリを開発する場合は、このマイアプリのページを利用します。モバイル クライアントアプリの場合は、API設定でモバイル クライアントアプリを選択する必要があります。
プロジェクトの作成
それでは、順に開発していきましょう。
メニューの[ファイル]―[新規作成]―[プロジェクト]から、テンプレート[Visual Basic]―[Office]―[2010]のPowerPoint 2010アドインを選択し、プロジェクトを作成します(図6 ) 。ここでは名前をSamplePowerPointAddInとしています。
図6 プロジェクトの新規作成
プロジェクトには、ThisAddIn.vbファイルがあり、ThisAddInクラスが定義されています。ここにアドインの処理を記述していきます。
Json.NETのインストール
Live Connectを利用する際にJSONデータを扱いますが、今回はJSONの処理にJson.NET を使います。
Visual Studio 11の場合、パッケージマネージャーのNuGet を利用してインストールできます。メニューの[プロジェクト]―[Manage NuGet Packages]からウィンドウを開いて、右上のOnlineの検索から「json.net」を検索し、Json.NETをインストールします(図7 ) 。
図7 NuGetでJson.NETのインストール
または、CodePlex からダウンロードし、Bin/Net40フォルダー内のNewtonsoft.Json.dllを、メニューの[プロジェクト]―[参照の追加]から、参照する方法でも構いません。
リボンの追加
はじめに、見た目の部分を作ります。プロジェクトへ、リボンを追加しましょう。ソリューションエクスプローラーで、プロジェクトが選択されている状態で、メニューの[プロジェクト]―[新しい項目の追加]より、「 リボン(ビジュアルなデザイナー) 」を選択・追加します(図8 ) 。名前はMainRibbon.vbとしました。
図8 リボンの追加
図9 のようにリボンが表示され、コントロールの追加や設定ができます。
図9 リボンの表示
リボンのコントロールを追加しましょう。ツールボックスの「Office リボン コントロール」からButton とMenu を配置します。ButtonとMenuともうひとつButtonを順にGroup1の中へドラッグ&ドロップし、さらにMenu1の▼部分をクリックして中にButtonをドラッグ&ドロップします。
Group1の中にある、Button 2個とMenu 1個を順にクリックして選択し、プロパティウィンドウの「ControlSize」を「RibbonControlSizeLarge」に変更します。ここまで行うと図10 のようになっています。
図10 リボンコントロールの配置
配置したボタンとメニューは、それぞれ、サインイン・サインアウト・マーカーの追加用です。サインイン・サインアウトは表示・非表示を切り替えてサインアウトはメニュータイプのUIを利用することにします。
ImageとLabelプロパティも編集して図11 のようにします。画像は適当なものを用意してください。TabのLabelプロパティも編集します。
MenuのImageとLabelは、サインインしたユーザーの名前とアイコンの表示用のため、編集不要です。
図11 編集後のリボン
また、MenuのVisibleプロパティをFalseに設定し、最初に表示したとき見えないようにしておきます。
ButtonとMenuの名前も変更しておきましょう。この後のコードでは、SignInButton・SignOutButton・MarkerButtonをボタン名、SignOutMenuをメニュー名として用います。
コードの編集
リボンのボタンをクリックしたときの処理は、ThisAddInクラスで行うようにします。ここで、リボン側のコードを記述しておきます。
まず、ThisAddIn.vbを編集し、次のようにメソッドを用意します。最初から記述されているThisAddIn_StartupとThisAddInShutdownは使いません。
Public Class ThisAddIn
Private Sub ThisAddIn_Startup () Handles Me . Startup
End Sub
Private Sub ThisAddIn_Shutdown () Handles Me . Shutdown
End Sub
Sub SignIn ()
End Sub
Sub SignOut ()
End Sub
Sub AddMarker ()
End Sub
End Class
リボン側で、追加したメソッドを呼ぶようにします。MainRibbon.vbのコードを次のように編集します。このとき、リボンのボタンをダブルクリックすると自動でボタンクリック時のコードが記述されます。
Imports Microsoft . Office . Tools . Ribbon
Public Class MainRibbon
Private Sub SignInButton_Click ( sender As Object , e As RibbonControlEventArgs ) Handles SignInButton . Click
Globals . ThisAddIn . SignIn ()
End Sub
Private Sub SignOutButton_Click ( sender As Object , e As RibbonControlEventArgs ) Handles SignOutButton . Click
Globals . ThisAddIn . SignOut ()
End Sub
Private Sub MarkerButton_Click ( sender As Object , e As RibbonControlEventArgs ) Handles MarkerButton . Click
Globals . ThisAddIn . AddMarker ()
End Sub
End Class
上記コードでは、ThisAddInクラスに追加した各メソッドを呼び出しています。以上でリボンの編集内容は完了です。
認可画面フォームの作成
Live Connectは、認可のプロトコル「OAuth 」を利用して、ユーザーからSkyDriveなどのリソースへのアクセス許可を得ます。その際に、Live Connectで用意されている認可画面(図12 )を表示し、ユーザーの認証・認可処理を行います。
図12 認可画面
次は、この認可画面の部分を作ります。認可画面はWebページのため、Webブラウザーコントロールを使って表示します。Webブラウザーコントロールを配置するフォームをプロジェクトに追加しましょう。
新しい項目の追加で、「 Windows フォーム」を選択・追加します(図13 ) 。ここではファイル名を、ConsentForm.vbとしています。
図13 Windowsフォームの追加
ツールボックスから、WebBrowser を追加したフォーム上へ、ドラッグ&ドロップします(図14 ) 。
図14 WebBrowserコントロールの配置
コントロール名を適当なものに変更しましょう。本稿では、MainWebBrowserと変更し、後述のコードで使います。
認可画面の表示
Live Connectのおさらいです。認可画面(図12 )のWebページのURLは次の通りです。ここにアクセスし、ユーザーからアプリに対してリソースへのアクセス許可を得ます。
https://oauth.live.com/authorize?client_id=CLIENT_ID &scope=SCOPES &response_type=code&redirect_uri=https://oauth.live.com/desktop
これは、OAuth 2.0のAuthorization Code Grant Flow というAuthorization Code (認可コード )を使用する方法を使います。
作成するフォームでは、生成時にClient ID (クライアントID )と認可の内容を示すScope (スコープ )を渡し、その認可画面をWebブラウザーコントロールで表示するようにします。
プロトコルに関する部分は、第45回 と第47回 に少し詳しくありますので、興味のある方は参照してください。
ConsentForm.vbに記述するコードは次のようになります。
Public Class ConsentForm
Private RedirectUri As Uri
Private ClientId As String
Private Scopes As IEnumerable ( Of String )
Public Sub New ( clientId As String , scopes As IEnumerable ( Of String ))
InitializeComponent ()
Me . RedirectUri = New Uri ( "https://oauth.live.com/desktop" )
Me . ClientId = clientId
Me . Scopes = scopes
End Sub
Private Sub ConsentForm_Load ( sender As Object , e As EventArgs ) Handles Me . Load
Dim uri = New Uri ( String . Format ( "https://oauth.live.com/authorize?locale=ja&client_id={0}&scope={1}&response_type=code&redirect_uri={2}" ,
Me . ClientId , String . Join ( "+"c , Scopes ), Me . RedirectUri ))
Me . MainWebBrowser . Navigate ( uri )
End Sub
End Class
Webブラウザーコントロール内の認可画面をユーザーが操作し、アプリの要求にユーザーが承諾した場合、別のURLへリダイレクトされます。そのURLは次のようになります。
https://oauth.live.com/desktop?code=[AuthorizationCode ]
このcodeパラメーターに認可コードが含まれています。この値を参照できるようコードに追記します。
Private _Parameters As New Dictionary ( Of String , String )
ReadOnly Property Parameters As IDictionary ( Of String , String )
Get
Return _Parameters
End Get
End Property
Private Sub MainWebBrowser_Navigated ( sender As Object , e As Windows . Forms . WebBrowserNavigatedEventArgs ) Handles MainWebBrowser . Navigated
If e . Url . Host <> RedirectUri . Host OrElse e . Url . AbsolutePath <> RedirectUri . AbsolutePath Then
Exit Sub
End If
Me . _Parameters . Clear ()
Dim param = e . Url . Query . Substring ( 1 ). Split ({ "&"c , "="c })
For i = 0 To param . Length - 1 Step 2
Dim val = param ( i + 1 )
Me . _Parameters . Add ( param ( i ), param ( i + 1 ))
Next
Me . DialogResult = Windows . Forms . DialogResult . OK
Me . Close ()
End Sub
上記のコードでは、ページがhttps://oauth.live.com/desktopへ遷移した場合、URLのクエリー部分を取得し、フォームを閉じます。認可コードを含むクエリーの値は、プロパティとして参照できるようにしています。
フォームに記述するコードは以上です。
Live Connect クラスの作成
さて、ここでLive Connectに関連した処理を行うクラスをいくつか作っていきます。作成するクラスは4つです。Live SDKのManaged API にあるクラスと似せて作っていますが、処理内容は少し異なるので注意してください。
新しくクラスを作るには、新しい項目の追加からクラスを選択・追加して行います。
LiveConnectSession
OAuthのAuthorization Code Grant Flowでは、認可コードを使って、アクセストークン という文字列を得ます。アクセストークンを使うと、認可されたリソースへのアクセスができるようになります。
はじめに、このアクセストークンなど認可情報を格納するLiveConnectSessionクラスを用意します。
LiveConnectSession.vb
Namespace Live
Public Class LiveConnectSession
Private _AccessToken As String
ReadOnly Property AccessToken As String
Get
Return _AccessToken
End Get
End Property
Private _RefreshToken As String
ReadOnly Property RefreshToken As String
Get
Return _RefreshToken
End Get
End Property
Private _Expires As DateTimeOffset
ReadOnly Property Expires As DateTimeOffset
Get
Return _Expires
End Get
End Property
Private _Scopes As IEnumerable ( Of String )
ReadOnly Property Scopes As IEnumerable ( Of String )
Get
Return _Scopes
End Get
End Property
Friend Sub New ( accessToken As String , refreshToken As String , expires As DateTimeOffset , scopes As IEnumerable ( Of String ))
Me . _AccessToken = accessToken
Me . _RefreshToken = refreshToken
Me . _Expires = expires
Me . _Scopes = scopes
End Sub
End Class
End Namespace
アクセストークンのAccessTokenプロパティ、その有効期限を示すExpiresプロパティ、許可を得ているスコープを示すScopesプロパティ、そして、アクセストークンの更新に必要なリフレッシュトークン と呼ばれる文字列のRefreshTokenプロパティから成っています。
LiveAuthClient
次に、認証・認可に関する処理を行うクラスを作ります。作成した認可画面フォームの表示はこのクラスから行います。また、得られた認可コードからアクセストークンを取得し、完了後にイベントを起こすという仕組みにします。
アクセストークンの取得は、次のURLにアクセスします。
https://oauth.live.com/token?client_id=CLIENT_ID &code=AUTHORIZATION_CODE &grant_type=authorization_code&redirect_uri=https://oauth.live.com/desktop
クラスは、次のように記述します。
LiveAuthClient.vb
Imports System . Threading . Tasks
Imports System . Net
Imports Newtonsoft . Json . Linq
Namespace Live
Public Class LiveAuthClient
Private ClientId As String
Private RedirectUri As Uri
Event InitializeCompleted As EventHandler ( Of LoginCompletedEventArgs )
Sub New ( clientId As String )
Me . ClientId = clientId
Me . RedirectUri = New Uri ( "https://oauth.live.com/desktop" )
End Sub
Sub InitializeAsync ( scopes As IEnumerable ( Of String ))
Using form = New ConsentForm ( Me . ClientId , scopes )
If form . ShowDialog <> Windows . Forms . DialogResult . OK OrElse
Not form . Parameters . ContainsKey ( "code" ) Then
Exit Sub
End If
Task . Factory . StartNew ( Of LiveConnectSession )(
Function ()
Return GetSession ( form . Parameters ( "code" ))
End Function ) _
. ContinueWith (
Sub ( t As Task ( Of LiveConnectSession ))
RaiseEvent InitializeCompleted ( Me , New LoginCompletedEventArgs ( t . Result ))
End Sub )
End Using
End Sub
Private Function GetSession ( code As String ) As LiveConnectSession
Dim uri = New Uri ( String . Format ( "https://oauth.live.com/token?client_id={0}&code={1}&grant_type=authorization_code&redirect_uri={2}" ,
Me . ClientId , code , Me . RedirectUri ))
Dim client = New WebClient
Dim json = client . DownloadString ( uri )
Dim o = JObject . Parse ( json )
If o ( "error" ) IsNot Nothing Then
Return Nothing
End If
Dim session As New LiveConnectSession (
o ( "access_token" ). ToString (),
o ( "refresh_token" ). ToString (),
New DateTimeOffset ( Now . ToUniversalTime ). AddSeconds ( o ( "expires_in" ). ToObject ( Of Integer )),
o ( "scope" ). ToString . Split ( " "c ))
Return session
End Function
End Class
End Namespace
GetSessionメソッドでアクセストークンを取得しています。サーバーからの応答は次のようなJSONデータになっています。コードでは、Json.NETのライブラリーを使用して、必要な情報を取り出し、LiveConnectSessionオブジェクトを作っています。
{
"access_token" : "xxxxx" ,
"expires_in" : 3600 ,
"refresh_token" : "xxxxx" ,
"scope" : "wl.offline_access wl.skydrive" ,
"token_type" : "bearer"
}
ちなみに、エラーの場合は、次のような構成のデータです。
{
"error" : "invalid_grant" ,
"error_description" : "The provided value for the input parameter 'code' is not valid."
}
LoginCompletedEventArgs
続いて、LiveConnectClientクラスで使用しているイベント用のクラスを作ります。
LoginCompletedEventArgs.vb
Namespace Live
Public Class LoginCompletedEventArgs
Inherits EventArgs
Private _Session As LiveConnectSession
ReadOnly Property Session As LiveConnectSession
Get
Return _Session
End Get
End Property
Sub New ( session As LiveConnectSession )
_Session = session
End Sub
End Class
End Namespace
LiveConnectClient
最後は、REST API の呼び出しを行うクラスです。Live Connectでは、REST APIを利用して、SkyDriveなどのリソースへアクセスします。この時にアクセストークンを使います。
REST APIは、これまでの連載で何度もでてきています。SkyDriveのフォルダーとファイル一覧であれば、次のURLへHTTP GETアクセスして取得します。
https://apis.live.net/v5.0/me/skydrive/files?access_token=ACCESS_TOKEN
今回はHTTP GETメソッドしか使いませんので、次のようなクラスにしました。
LiveConnectClient.vb
Namespace Live
Public Class LiveConnectClient
Private _Session As LiveConnectSession
ReadOnly Property Session As LiveConnectSession
Get
Return _Session
End Get
End Property
Public Sub New ( session As LiveConnectSession )
_Session = session
End Sub
Function [Get] ( path As String ) As String
Dim uri = New Uri ( "https://apis.live.net/v5.0/" &
path &
If ( path . Contains ( "&" ), "&" , "?" ) &
"access_token=" & Me . Session . AccessToken )
Dim client = New Net . WebClient With {. Encoding = System . Text . Encoding . UTF8 }
Return client . DownloadString ( uri )
End Function
End Class
End Namespace
以上で、必要なLive Connect関連のクラスが準備できました。
サインインユーザーの表示
ここで、今回の最後の内容です。ここまでで用意したクラスを使って、サインインしたユーザーの表示までしてみましょう。リボンのサインインボタンをクリックすると、認可画面フォームを表示します。ユーザーの認証と認可処理を行った後、サインインしたユーザーをリボンに表示します。
サインイン
ThisAddInクラスにあるSingInメソッドを編集します。
Private Const ClientId As String = "XXXXX"
Sub SignIn ()
Dim client = New LiveAuthClient ( ThisAddIn . ClientId )
AddHandler client . InitializeCompleted ,
Sub ( s , e )
If e . Session Is Nothing Then
Exit Sub
End If
Dim t = New Threading . Thread ( AddressOf GetUserInfo )
t . SetApartmentState ( Threading . ApartmentState . STA )
t . Start ( e . Session )
End Sub
client . InitializeAsync ( New String () { "wl.skydrive" , "wl.offline_access" })
End Sub
LiveAuthClientオブジェクトを生成し、InitializeAsyncメソッドを呼びます。生成時に登録したアプリのクライアントIDを指定し、メソッドを呼ぶときにスコープを指定します。作成するアドインで必要なスコープは、SkyDriveのアクセスと、ユーザーがオフライン時のアクセスです。値は、wl.skydrive とwl.offline_access です。wl.offline_accessを指定するとリフレッシュトークンの取得ができるようになります。
InitializeAsyncメソッドで、認可画面フォームを表示し、ユーザーが認可処理を行うとInitializeCompletedイベントが発生します。上記コードでは、イベント発生時にThreadを生成し、GetUserInfoメソッドを呼んでいます。次はこのGetUserInfoメソッドを追記しましょう。
GetUserInfoメソッドでは、LiveConnectSessionオブジェクトを付け取り、LiveConnectClientオブジェクトを通してREST APIにアクセスし、サインインしたユーザー情報を取得します。また、リボンコントロールの表示・非表示などの操作を行います。
Private LiveConnectClient As LiveConnectClient
Private Sub GetUserInfo ( session As LiveConnectSession )
Me . LiveConnectClient = New LiveConnectClient ( session )
Globals . Ribbons . MainRibbon . SignInButton . Enabled = False
Try
Dim url = "https://apis.live.net/v5.0/me/picture?access_token=" & session . AccessToken
Dim client = New Net . WebClient
Dim file = System . IO . Path . GetTempFileName
client . DownloadFile ( url , file )
Dim result = LiveConnectClient . Get ( "me" )
Dim o = JObject . Parse ( result )
Globals . Ribbons . MainRibbon . SignOutMenu . Label = o ( "name" ). ToString
Globals . Ribbons . MainRibbon . SignOutMenu . Image = New System . Drawing . Bitmap ( file )
Globals . Ribbons . MainRibbon . SignOutMenu . Visible = True
Globals . Ribbons . MainRibbon . SignInButton . Visible = False
Catch ex As Exception
End Try
End Sub
コード中にある次のURLにアクセスすると、サインインユーザーの表示アイコンを取得できます。
https://apis.live.net/v5.0/me/picture?access_token=ACCESS_TOKEN
また、LiveConnectClientオブジェクトを使ってREST APIを呼びます。Getメソッド内部では、次のURLにアクセスしています。
https://apis.live.net/v5.0/me?access_token=ACCESS_TOKEN
この結果は、次のようなJSONデータです。
{
"id" : "xxxxx" ,
"name" : "梓 中野" ,
"first_name" : "梓" ,
"last_name" : "中野" ,
"gender" : null ,
"locale" : "en_US"
}
コードでは、以上の得られたデータを、リボンのボタンに反映しています。
さて、ここまでを実行してみましょう。実行([ デバッグ]―[デバッグ開始] )すると、PowerPointが起動し、リボンに作成したタブ「写真の追加」が表示されているはずです。サインインボタンをクリックすると、認可画面が表示されます。サインイン後には、アイコンとユーザー名が表示されたでしょうか。
このサインイン処理は、次回に少しOfficeアドインの作法に従って書き直します。
おわりに
今回はここまでです。いかがでしたか。今回はほとんど準備段階となってしまいましたが、最後にLive Connectでユーザー情報を取得するところまで行いました。次回はメインとなる部分を実装していきましょう。また、Officeアドインでの非同期処理についても扱います。