KatsuYuzuのブログ

.NET の開発をメインとした日記です。

ストアアプリで自分のアプリからデータを共有する #win8dev_jp #wpdev_jp

f:id:KatsuYuzu:20140801004303j:plain
前回は共有を呼び出すまででしたので、今回は実際にデータを共有します。

データを共有する

共有できるデータはタイトルやテキスト、URL、ファイルなど様々で、共有操作を行うと対応している(そのデータ受け取れるよ!と宣言してくれている)アプリが一覧に表示されます。
ここで注意しないといけないのは、その場面にもっとも適切なデータのみを共有してください。共有したデータがどのように使われるかは相手のアプリ次第です。例えば、画像のみを渡すとアルバムに保管してくれるのに、URLも一緒に渡すと、画像には一切触れられずにURLのみを処理されるなんてことも起こりえます。

  1. ユニバーサルアプリプロジェクトを準備
  2. DataTransferManagerを利用して共有を行う

ユニバーサルアプリプロジェクトを準備

プロジェクトを作成します。前回と同じものです。
f:id:KatsuYuzu:20140730234130p:plain:w400
f:id:KatsuYuzu:20140730234433p:plain:h300

DataTransferManagerを利用して共有を行う

イベントのハンドル
// 任意の場所で購読
DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;

これは画面毎ではなく、どこで記述しても構いません。逆に、一度購読すると、解除するまでは一番最初に購読した処理が動作し続けます。画面毎に共有するデータが違う場合は画面遷移の前後で購読と解除を行うと簡単です。

/// <summary>
/// このページがフレームに表示されるときに呼び出されます。
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
}

/// <summary>
/// Page がアンロードされて親 Frame の現在のソースではなくなった直後に呼び出されます。
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    DataTransferManager.GetForCurrentView().DataRequested -= OnDataRequested;
}

アプリの状態管理がきちんと行えているのであれば、起動時に一度購読して、あとはアプリの状態に合わせてセットする共有データを切り替えれば良いでしょう。

データのセット

DataRequestedEventArgs.Request.Dataのたくさんあるプロパティに対して任意のデータをセットします。

private void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
    e.Request.Data.Properties.Title = "データのタイトル";
    e.Request.Data.Properties.Description = "データの説明";
    e.Request.Data.SetText("共有するテキスト!");
}

ただし、タイトルは必須です。タイトルがない場合やデータがない場合はエラーになります(Windows Phoneはうんともすんとも言わなくなります)。
f:id:KatsuYuzu:20140801002345p:plain

時間がかかるデータやリソースを消費するデータのセット

時間がかかるデータやリソースを消費するデータを共有する場合は、デリゲートを共有して、必要に応じて処理することができます。例えば、ファイルを共有するときに、ファイルが共有できることだけ(デリゲートのみ)を伝えて(ファイルを受け取れるアプリを含む)相手のアプリ一覧を表示し、ファイルが使われる場合はデリゲートの実行、ファイルが使われない場合は時間やリソースがかかるデータを扱わずに済むといったことができます。

// ファイルをデリゲートで共有するサンプル

// 共有データの拡張子
e.Request.Data.Properties.FileTypes.Add(".jpg");

// デリゲートの共有
e.Request.Data.SetDataProvider(
    StandardDataFormats.StorageItems,
    this.OnDeferredImageRequestedHandler);

// 実際の処理
async void OnDeferredImageRequestedHandler(DataProviderRequest request)
{
    // 非同期処理の開始(非同期の場合に必要)
    var deferral = request.GetDeferral();
    try
    {
        // マニフェストの[機能]で[画像ライブラリ]の指定が必要
#if WINDOWS_APP
        // 適当なファイルを用意
        var files = (await KnownFolders.PicturesLibrary.GetFilesAsync())
            .Where(x => Path.GetExtension(x.Name) == ".jpg")
            .Take(1);
#else
        // 適当なファイルを用意
        var files = (await KnownFolders.CameraRoll.GetFilesAsync())
            .Where(x => Path.GetExtension(x.Name) == ".jpg")
            .Take(1);
#endif
        // 共有データをセット
        request.SetData(files);
    }
    finally
    {
        // 非同期処理の終了(非同期の場合に必要)
        deferral.Complete();
    }
}

このコードでは、Windows ストアアプリではピクチャライブラリから、Windows Phoneではカメラロールから、それぞれ写真を1枚取得して共有しています。シナリオが適当ですが、共有の雰囲気。雰囲気、大事。