Help us understand the problem. What is going on with this article?

Uno Platform のススメ

はじめに

この記事は Xamarin Advent Calendar 2019 の 8 日目の記事です。

最近ちょっとずつ注目されつつある (?) "Uno Platform" という .NET 向けの UI フレームワークの紹介記事です。

Uno Platform とは

Uno Platform は .NET 向けのクロスプラットフォーム UI フレームワークです。 .NET のクロスプラットフォームフレームワークとしては "Xamarin.Forms" が Xamarin 自身からリリースされていることもあり、最も有名だとは思います。

Uno Platform の最大の特徴はなんといっても UWP の API 互換によるクロスプラットフォームを実現する という点に尽きます。ユーザー (アプリ開発者) としては UWP アプリを作れば (理想論でいえば) それをそのまま Android / iOS に持ってくる事が可能になるわけです。

UWP 互換を目指していることから、 見栄えのカスタマイズ性が高い 事も特徴として挙げられます。 UWP や WPF では従来の Win32 GDI の UI コンポーネントによるレンダリングをせずに自前のレンダラーでレンダリングをしていて、ボタンなどの見栄えは (標準スタイルはありますが) 全てアプリケーション開発者が独自に定義することが可能です。 Uno Platform でも UWP と同様なカスタマイズが可能となっています。

Xamarin.Forms は各コンポーネントはプラットフォームネイティブの UI コンポーネントで構成されるので、単一コードで各プラットフォームに沿った UI をクラスプラットフォームで構築しやすいというメリットがありますが、反面設定できる項目が少なくカスタマイズ性が低いということになります。これはどちらが優れているかという事ではなくフレームワークの性質ということだと思うので、ケースによって判断すればよいと思います。

(ちなみに Uno Platform は Native Style を指定する事でプラットフォームネイティブのコンポーネントを同一画面内で混在させて使用する事が可能となっています)

Windows は (今のところは) Uno ではなくそのまま UWP アプリとしてビルドすることで対応しています。 Windows 以外のバックエンドは Xamarin (Xamarin.Android, Xamarin.iOS など) が使われています。

Uno Platform を試す

手っ取り早く試すには Visual Studio の拡張機能で Uno のプロジェクトテンプレートをインストールすることです。

Visual Studio の機能拡張から "Uno Platform Solution Templates" をインストールします。

1.png

インストールするとプロジェクトテンプレートから Uno Platform が選べるようになります。

image.png

完了すると各プラットフォーム向けプロジェクトを含んだソリューションが生成されます。

Uno Platform の実装を調べる

チェックアウトしてきてビルドするとするソリューションに含まれるサンプルアプリが動くので、それで動作を確認します。

Xamarin.Forms では "抽象的な UI コンポーネントを定義したコアクラス群 (論理層)" と "プラットフォームに依存した具体的な実装を提供するレンダラー" に分かれていましたが、 Uno は UWP の API 丸ごと Bait and Switch で切り替えるような形のようです。本家 UWP のクラスがある意味 Xamarin.Forms の Core に相当するというイメージでしょうか。例えば UIElement は Android 用の UIElement クラスの実装が用意されています (厳密にはプリプロセッサ切り替えと partial class でソース自体はある程度共通化されている) 。

このような構造のため、 Xamarin.Forms と違って独自の Backend 実装をするのは結構ハードルが高そうです。 Xamarin.Forms の場合は抽象レイヤー (Core) とプラットフォーム実装が完全に分離されているので割と気軽 (?) に実装できます。

以降、 Android 版で実装と動作をみていきます。

次のような XAML を定義してみました。

<Page
  x:Class="App2.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

  <Page.Resources>
    <win:Style x:Key="NativeDefaultButton" TargetType="Button" />
  </Page.Resources>

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
      <Button Width="240" Height="48">Button 1</Button>
      <Button Width="240" Height="48" Background="AliceBlue">Button 2</Button>
      <Button Width="240" Height="48" Style="{StaticResource NativeDefaultButton}">Button 3</Button>
      <Button Width="240" Height="48" Style="{StaticResource NativeDefaultButton}" Background="AliceBlue">Button 4</Button>
      <Button Width="240" Height="48">
        <Button.Template>
          <ControlTemplate>
            <Grid>
              <Ellipse Fill="LightGray"></Ellipse>
              <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
            </Grid>
          </ControlTemplate>  
        </Button.Template>
        <Button.Content>Button 5</Button.Content>
      </Button>
    </StackPanel>
  </Grid>
</Page>

Button を様々な見栄え設定で表示するようにしています。実行すると次のような表示になります。

UWP Android
9.png 8.png

特徴として

  • Button 1, Button 2 は UWP (Uno) の標準デザインそのものです
  • Button 3, Button 4 は Native Style を適用することでプラットフォームネイティブのボタン になっています
    • UWP はネイティブ = UWP なので結局同じになります
    • Android は見栄えを真似ているのではなく本当にすりかわっているのでネイティブそのものの挙動 (アニメーションとか) をします
  • Button 5 は UWP 的に Template を適用して標準と違うデザインにしています

Button クラスをみてみる

Button 自体は UWP の Button クラス (Windows.UI.Xaml.Controls.Button) です。イベントや論理的なプロパティはここに定義されています。

見栄えについては UWP の作法にのっとって ControlTemplate に指定されたテンプレートに沿って構築されます。 UWP の各コンポーネントは突き詰めると Android の View にそれぞれ変換されて表示されます。この観点からすると Xamarin.Forms と同じようにも思えますが、 Xamarin.Forms は Button をプラットフォームネイティブの Button として置き換えるので、論理的に高レイヤーでの対応になります。 Uno はレンダリング層で置き換えてるので低レイヤーでの置き換えていることになります。

Native Style についても ControlTemplate の置き換えで実現しているようです。これは Generic.Native.xaml というソースに Style のリソースが定義されていますが、

<android:Style x:Key="NativeDefaultButton"
                TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <BindableButtonEx Text="{TemplateBinding Content}"
                                    IsEnabled="{TemplateBinding IsEnabled}"
                                    Foreground="{TemplateBinding Foreground}"
                                    ForegroundColor="White"
                                    DisableWhenNoCommand="false" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</android:Style>

BindableButtonEx は実体として Android.Support.V7.Widget.AppCompatButton そのものです。
つまり通常はパーツ単位で Android の View で入れ替えているのに対し、 Native Style を適用すると丸ごと Android のネイティブボタンに "View として" 置き換えているわけです。よくできています。
(これにより Native Style のボタンでは Background が変わっていないのもよくわかります。 Background が Binding されていません)

image.png

※全ての既定が Windows.UI.Xaml.UIElement の上の Uno.UI.UnoViewGroup クラス (Android の ViewGroup)

image.png

Uno Platform の展望

私が Uno に注目し始めた直接的な理由は UnoConf 2019 のライブを見た事からなのですが

その中でも個人的に特に期待をしているのが Backend の追加、特に Skia Backend を挙げているところです (macOS は現在の master にも入ってきているようです) 。

image.png

(1:38:25 あたり)

Skia Backend となると、レンダリングが全て自前実装になるので、レンダリングがプラットフォーム非依存になります。するとプラットフォーム実装に関するレンダリング実装の割合がかなり削減される (Skia が対応していればよい) ことになるので Windows 7 など非 UWP の Windows での動作も期待できるのではないかと思います。 IME 対応が壁になりそうに思いますが・・・

おわりに

Uno は WASM 対応が進んでいて、UWP を通して Xamarin.Forms のバックエンドになったり して面白いこともやってるなあという感じです。積極的に情報発信もしていて、やっていこう感結構あるので新たな選択肢として期待したいです。

.NET で自前レンダラーのクラスプラットフォーム UI フレームワークとして "Avalonia" があります。

Uno はどちらかというとモバイル寄りですが、 Avalonia はデスクトップ寄りでしょうか。こちらも見ていきたいところです。

Uno は今後次第ですが、自前レンダラーのクロスプラットフォーム UI フレームワーク、となるとどちらかが C# の Flutter になり得る可能性も 0 ではないかなと思いたいので要注目です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away