[WinRT] ストアアプリのセカンダリタイルを動的に作成する方法

Kindle Launcher の技術ネタの続きです。

クイック スタート: セカンダリ タイルのピン留め (XAML) (Windows)
http://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/hh868249.aspx
WinRT/Metro TIPS:Windows 8.1の新機能、セカンダリ・タイル作成時の代替ロゴを使うには?[Windows 8.1ストア・アプリ開発] – @IT
http://www.atmarkit.co.jp/ait/articles/1312/05/news084.html

ストアアプリを登録すると、スタート画面いタイルを表示できますが、これを複数表示させることができます。複数のタイルにIDを付けておいて、いろいろな状態でアプリを起動することが可能です。
サンプルには、リソース「ms-appx:///」のタイルを表示する方法が載っていますが、実は「ms-appdata:///」も使えます(とマニュアルに書いてあります)。リソースの場合はアプリ内に含める必要があるのですが、アプリケーションデータ(ms-appdata)が使えるということは、どこからダウンロードしたり作成した画像を使えるということです。
これを Amazon の書籍の画像を使えば、スタート画面に本の画像が表示できるということです。

アプリケーションデータの扱いについては、以下を立ち読みするか、

ひと目でわかる Windowsストアアプリ開発入門VisualC#2012編
http://www.amazon.co.jp//dp/482229806X

マニュアルのほうはこっちで。

Windows ランタイムを使ったアプリ データへのアクセス (Windows ランタイム アプリ) – Windows app development
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh464917.aspx

を参照してください。

動的にセカンダリタイルを作る

Kindle Launcher で使っているのがこれです。セカンダリタイルは、いちいちユーザーの確認が必要なので、一気に作ることがでいません。まあ、プログラムで一気に作るとスタート画面が「D○c○m○」で埋もれてしまいそうなので、これはこれでいいのかもしれませんが。

private async void OnButtonMakeTile(object sender, RoutedEventArgs e)
{
    var item = this.itemGridView.SelectedItem as Book;
    if (item == null) return;

    await CreateSecondaryTileAsync(item);
}

private async System.Threading.Tasks.Task<bool> CreateSecondaryTileAsync(Book item)
{
    string tileId = "ASIN-" + item.ASIN;
    var tile = new Windows.UI.StartScreen.SecondaryTile()
    {
        TileId = tileId,
        DisplayName = item.Title,
        Arguments = item.ASIN,
        RoamingEnabled = true,
    };
    tile.VisualElements.ForegroundText = Windows.UI.StartScreen.ForegroundText.Light;
    tile.VisualElements.ShowNameOnSquare150x150Logo = true;

    // アプリローカルに保存
    var cl = new HttpClient();
    var data = await cl.GetByteArrayAsync(new Uri(item.IconUrl));

    var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
    var path = item.ASIN + ".jpg";

    try
    {
        var file = await folder.CreateFileAsync(path);
        using (var sw = await file.OpenStreamForWriteAsync())
        {
            sw.Write(data, 0, data.Length);
            sw.Flush();
        }
    }
    catch
    {
        // 同名のファイルがある場合は、そのまま使う
    }

    // tile.VisualElements.Square150x150Logo = new Uri(item.IconUrl);
    tile.VisualElements.Square150x150Logo = new Uri("ms-appdata:///local/" + path );

    return await tile.RequestCreateForSelectionAsync(GetElementRect( this.btnMakeTile ));
}

public static Rect GetElementRect(FrameworkElement element)
{
    GeneralTransform buttonTransform = element.TransformToVisual(null);
    Point point = buttonTransform.TransformPoint(new Point());
    return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
}

Kindle の商品画像を HttpClient#GetByteArrayAsync でダウンロードしてきて、アプリケーションデータに保存します。保存するファイル名が一意になるようにするため、ASIN コードそのものを使っています。
保存したあとに、セカンダリタイルの画像を

tile.VisualElements.Square150x150Logo = new Uri("ms-appdata:///local/" + path );

のように指定しておけば良いわけです。

起動時に分岐させる

セカンダリタイルをクリックしたときの引数は TileId に設定しておきます。ここでは「”ASIN-” + item.ASIN」のように設定しています。これが引数となってアプリの起動時にわたるので、app.xaml.cs を開いて、以下のように、e.Arguments で判別させます。

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
    if (System.Diagnostics.Debugger.IsAttached)
    {
        this.DebugSettings.EnableFrameRateCounter = true;
    }
#endif

    if (e.Arguments != "")
    {
        var asin = e.Arguments;
        // 引数がある場合は、Kindle を起動する
        var opt = new LauncherOptions();
#if !WINDOWS_PHONE_APP
        opt.DesiredRemainingView = Windows.UI.ViewManagement.ViewSizePreference.UseNone;
#endif
        await Launcher.LaunchUriAsync(
            new Uri(string.Format("http://read.amazon.co.jp/?asin={0}", asin)), opt );
    }

引数は ASIN コードなので、そのまま、Kindle Cloud Reader に渡せば ok です。LauncherOptions を指定しておけば、起動時の状態が設定できるので Kindle Cloud Reader が全面にできるように UseNone に設定しておきます。デフォルトは半分半分ですね。

タイル自体は、tile.VisualElements で色々と外観が変えられますが、ここでは表紙を全面出しているため書名がちょっと見づらくなっています。まあ、ダウンロード時に画像の加工をして保存するとか、いろいろと手段があります。画像の加工自体は、

[win8.1] RenderTargetBitmapクラスで、XAMLをビットマップ形式で保存する
http://www.moonmile.net/blog/archives/4983

こんな風に RenderTargetBitmap を使えば手軽にできるので、一度、画面に表示させたうえで保存すればよいでしょう。ピン留めする直前とかに作れば ok かと。
あと、画像の入れ替えやバッチなども作れるので、既読とか交互に宣伝とかを流すのもよいでしょう。

カテゴリー: C#, WinRT パーマリンク