Windows PhoneからSkyDriveにファイルをアップロードする方法
既にMarketplaceから公開されているSensor Checkerを見ながら思った。計測結果をファイル化したいと。都合よくLive SDK v5.0が公開され思った。SkyDriveに計測結果をアップしたら便利だよなと、無料で25GBだし…ということで、計測結果をファイル化してSkyDriveにアップする機能拡張を行いました。既に機能追加版はMarketplaceにアップロードしたので、Rejectされなければ直ぐアップデートされるはずです。
SkyDriveへのファイルアップロードは、意外と簡単。方法を順番に説明していきます。
1. 最新版のLive SDKをダウンロード&インストール
https://www.microsoft.com/download/en/confirmation.aspx?id=28195 からファイルをダウンロードして、ダブルクリック&インストールします。
2. Windows Phone向けのアプリケーションプロジェクトを作成し、参照設定にLiveのコンポーネントを追加
- Microsoft.Live
- Microsoft.Live.Controls
を追加します。
3. Appクラスに、LiveConnectSession型のスタティックなプロパティを追加する
Appクラスは、App.xaml.csにあります。
using Microsoft.Live;
を先頭に加え、
public LiveConnectSession LiveSession { get; set; }
を定義しておきます。
これで準備は万端です。
4. Windows Liveへのサイン用ページを作成
プロジェクトにページを一枚追加します。そのページの先頭のほうに、名前空間を以下の様に追加します。
<phone:PhoneApplicationPage
…
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:live="clr-namespace:Microsoft.Live.Controls;assembly=Microsoft.Live.Controls"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
…
そして、Windows Liveのサインインページにナビゲートする為のボタンを追加します。
<StackPanel Name="SigninPanel" Grid.Row="0">
<TextBlock Text="Signin to SkyDrive" FontSize="24" HorizontalAlignment="Center"/>
<live:SignInButton Name="buttonSignin" Content="Sign-in to SkyDrive"
ClientId="########" ← クライアントID
Scopes="wl.basic wl.skydrive wl.offline_access wl.signin wl.skydrive_update" ←許可範囲
RedirectUri="https://oauth.live.com/desktop"
Branding="Skydrive"
SignInText="SignIn"
SessionChanged="buttonSignin_SessionChanged" ←セッション情報変化の通知を受ける為のハンドラ登録
/>
</StackPanel>
LiveのWindows Phone用部品としてサインイン用ボタンが用意されています。これを使えば簡単にSkyDriveにアクセスする為の認証が行えます。
アトリビュートのClientIdは、https://manage.dev.live.com/ にアクセスして作成するアプリを登録すると、そこで表示されるので、その値をコピペします。
Scopesは、サインインする際にアプリケーションに対して、アクセス要求の範囲を指定します。サインインの際、ユーザーに対して、これらのアクセスを許可するかの判断が任されます。
詳しくは、https://msdn.microsoft.com/en-us/library/hh243646.aspx を見てください。ファイルのアップロードを行うには、wl.skydrive_updateを指定する必要があります。
実行すると以下のページが表示されます。
サインインをタップすると、以下の画面が表示され、Live IDとパスワードを入力し、サインインをタップすると、Scopesに対応した許可画面が表示されます。
右側の図で表示される項目はScopesの指定によって変わりますが、ここでユーザーが”はい”をタップすると、SkyDriveへのアクセスが可能になります。
SessionChangedアトリビュートに登録したハンドラは、
private void buttonSignin_SessionChanged(object sender, Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs e)
{
if (e.Session != null && e.Status == LiveConnectSessionStatus.Connected)
{
App.LiveSession = e.Session;
…
}
else
{
MessageBox.Show("Signin Failed. ");
}
}
こんな感じで、接続が成功したら、AppクラスのLiveSessionプロパティにセッションを保存しておきます。
5. SkyDriveのフォルダー情報取得
ファイルをアップロードする場合、アップロード先のフォルダー情報が必要です。フォルダー情報を取得するには、以下の様なコードを書きます。
LiveConnectClient client = new LiveConnectClient(App.LiveSession);
client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(client_GetCompleted);
client.GetAsync("me/skydrive/files?filter=folders", client);
フォルダー情報を取得するには、4.で取得したSession情報を使って先ずLiveConnectClientのインスタンスを作成します。clientのGetAsync()メソッドを、赤字で書いた文字列を引数にしてコールすると、応答が帰ってくると、GetCompletedに登録したハンドラがコールされます。
赤字の部分を解読すると、LiveのAPIはREST形式のAPIなので、URLが"me/skydrive/files"で、引数が"filter=folders"で、検索条件としてfoldersを指定してクエリーをかけてると読めます。GetAsyncの2番目の引数は、GetCompletedがコールされた際に再利用する為の状態変数で、ここではclientを渡しています。
GetCompletedのハンドラは、以下の様なコードです。
void client_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
string path = null;
Dictionary<string, object> folderData = e.Result as Dictionary<string, object>;
List<object> folders = (List<object>)folderData["data"];
foreach (var item in folders)
{
Dictionary<string, object> folder = item as Dictionary<string, object>;
if (folder["name"].ToString() == uploadFolderName)
{
path = folder["id"].ToString();
break;
}
}
if (path != null)
{
UploadFile(path, e.UserState as LiveConnectClient);
}
else
{
…
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
このハンドラに渡される引数eのResultは、文字列をキーとし、object型の変数を値とする結果が渡されてきます。実際どんな値が送られてくるかは、デバッグ時ステップ実行して確かめてください。基本は、"data”という文字列をキーにした値には、SkyDriveのドキュメント直下に存在するフォルダー情報を格納したリストが入っています。そのリストにはまたキーバリューペアが入っているのでDictionary型で受けます。"name"というキーにはフォルダー名が格納されていて、"id"にそのフォルダーのパス(path) が格納されています。フォルダーに対して取得できる情報については、https://msdn.microsoft.com/en-us/library/hh243648.aspx#folder を参考にしてください。
このコードでアップロード先のフォルダーのパスを取得して、ファイルをアップロードするわけです。次にUploadFileの中身を紹介します。
6. ファイルのアップロード
var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
{
fstream = storage.OpenFile(filename, System.IO.FileMode.Open);
client.UploadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(client_UploadCompleted);
client.UploadAsync(path, filename, fstream);
}
clientは、LiveConnectClientのインスタンス、pathは、5.で説明した、フォルダーのSkyDrive上のパス(id)です。filenameは、アップロードしたいファイル名で、このコードは、IsolatedStorageに格納されているファイルを同じファイル名でアップロードする事を前提としてコーディングされています。UploadAsync()メソッドをコールすると、実際にSkyDriveにアップロードが開始されるわけです。このメソッドの3番目の引数がStreamになっているので、カメラや音源など、予め作成しておいたファイルでなくてもアップロードが可能と思われます。
実際にやってみたところ、ファイル名の拡張子がxml、つまりXMLファイルの場合は、上手くアップロードできないようです。私はこれで半日嵌りましたので、皆さんご注意。
ちょっと長くなりましたが、SkyDriveへのファイルアップロードは完全なパターンコードです。SkyDriveはLive IDを登録するだけで、無料で25GBのストレージが使えます。アクセス権の設定なども可能なので、いろんな種類のファイルをアプリからアップロードしたい方、是非お試しを。