かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Uno Platform でプラットフォームによって実装されていない機能を実行時に判別する

さて、Uno Platform ですが UWP の API を気合で Android/iOS 向けに提供しているのですが、全部の API が提供されているわけではないです。 UI まわりは、かなり動きますがそれ以外は結構 NotImplementedException が出てしまいます。

例えば以下のようにボタンを押したらファイルを選択するダイアログを出してファイル名をダイアログで出すような機能を実装したとします。

var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".jpg");

var file = await picker.PickSingleFileAsync();
if (file == null)
{
    await new MessageDialog("Canceled").ShowAsync();
    return;
}

await new MessageDialog(file.Name).ShowAsync();

FileOpenPicker は、実装されてないクラスのうちの一つなので UWP 以外では現時点では例外になります。でも UWP では FileOpenPicker を使いたい、Android/iOS などの対応していないプラットフォームではそれなりに動かしたいという場合はどうするのかというのですが、#if ディレクティブや partial class でプラットフォームごとの処理を書くという方法もありますが、機能自体が提供されているかを実行時に判定する方法もあります。

Windows.Foundation.Metadata.ApiInformationIsTypePresent でクラスが提供されているかどうか、IsMethodPresent でメソッドが提供されているかどうか確認できます。例えばさっきの処理に追加するとこんな感じです。

if (ApiInformation.IsTypePresent("Windows.Storage.Pickers.FileOpenPicker"))
{
    var picker = new FileOpenPicker();
    picker.FileTypeFilter.Add(".png");
    picker.FileTypeFilter.Add(".jpg");

    var file = await picker.PickSingleFileAsync();
    if (file == null)
    {
        await new MessageDialog("Canceled").ShowAsync();
        return;
    }

    await new MessageDialog(file.Name).ShowAsync();
}
else
{
    await new MessageDialog("FileOpenPicker isn't provided at this platfrom.").ShowAsync();
}

UWP で実行するとダイアログが出て

f:id:okazuki:20191226233958p:plain

例えば iOS で起動すると、こんな感じでエラーではなくサポートされていないことを判定して個別の処理が実行可能です。

f:id:okazuki:20191226234151p:plain

まとめ

ケースバイケースだけど、こういう方法もあるよって感じで