Xamarin.Essentials 入門 - #1 Xamarin.Essentials とは
はじめに
この記事は、Xamarin Advent Calendar 2019 の 23日目の記事です。 Xamarin.Essentials 入門というタイトルで、Xamarin.Essentials の使い方と読み方について記載しています。
Xamarin.Essentials とは
Xamarin.Essentials とは、何かを簡単に説明します。Xamarin.Essentials とは、プラットフォーム固有の機能(位置情報、ネットワークとの接続状態、デバイス情報など)を利用するためのクロスプラットフォーム API です。Microsoft により提供されていて、v1.3 では 33 の機能が提供されています。
「Xamarin とは」という記事や書籍でよく紹介されますが、Xamarin を使ってアプリケーションを開発する方法として、二つの方法が紹介されることがよくあります。
この図で述べられていることは、ユーザーインターフェース層におけるコードの共通化について述べられているのであって、図の中の Shared C# App Logic に相当する部分は、.NET Standard で実装できるように見えてしまいます。しかしながら、プラットフォーム固有の機能は、Xamarin.iOS や Xamarin.Android のクラスライブラリで提供されているため、.NET Standard で提供されるクラスライブラリだけではアプリを作ることは現実的ではありません。従って、「Shared C# App Logic」の部分からプラットフォーム固有の機能を利用するために、主に以下のような手法が用いられてきました。
- Bait and Switch の手法を利用する
- XamarinComponents のライブラリで用いられている手法
- Interface を作成し、DependencyService / DI Container 経由で呼び出す処理を実装する
これまで上記のような手法で実装されてきたプラットフォーム固有の機能を利用するためのライブラリが、Microsoft から提供されるようになったというわけです。
Xamarin.Essentials の使い方
使う前の事前準備は、以下の通りです。
- NuGet で Xamarin.Essentials をインストールする
- Visual Studio 2019 で作成されたプロジェクトでは、最初からインストールされているようです
- インストールする場合には、すべてのプロジェクトにインストールが必要
- 機能によっては、設定が必要な場合がある
- 詳細は、ドキュメント(Xamarin.Essentials)を参照
各機能でクラス・メソッドが提供されているので、それを利用します。例えば、Preferences 機能(設定の取得・保存機能)には、Preferences
クラスが提供されていて、利用するクラスに参照を追加して、Preferences
クラスのメソッドを利用します。
using Xamarin.Essentials; // set value Preferences.Set("my_key", "my_value"); // get value var myValue = Preferences.Get("my_key", "default_value");
Xamarin.Essentials のコードを読む
コードを読むと何かよいことがあるのか?
Xamarin.Essentials を利用するだけでなく、ぜひコードを読んでほしいと思っています。理由は、Xamarin.Essentials のソースコードは、プラットフォーム固有の機能を利用するときに、どのようなネイティブ API を利用したらよいかを学ぶのに役立つと思うからです。
例えば、Xamarin.Essentials の Preferences 機能(設定値の取得・保存用の API)のソースコードを読むと、iOS では NSUserDefaults
、Android では SharedPreferences
、UWP では ApplicationData
を利用していることが分かります。
Xamarin.Essentials のソースコードは、GitHub に公開されています。
ここでは、Xamarin.Essentials のソースコードを「読む」ときのポイントとなる事柄について説明します。
どのように読み進めればよいのか?
Xamarin.Essentials のコードは、機能単位でフォルダにまとめられています。
プラットフォーム固有の機能でどのようなネイティブの API が利用されているかは、機能に該当するフォルダの中身のコードを読めばよいことになります。ここでは、各機能のコードを読んでいく際に役に立つポイントを記載しておきます。ポイントは以下の三つです。
- マルチターゲットプロジェクト
- どうやって複数のフレームワークのコードをビルドしているのか
- どうやってプラットフォーム固有の処理を書いているのか
マルチターゲットプロジェクト
Xamarin.Essentials はマルチターゲットのクラスライブラリです。つまり、一つのクラスライブラリのプロジェクトで複数のプラットフォーム向けのアセンブリを作ることができます。Xamarin.Essentials のプロジェクトファイルを見てみましょう。ターゲットとなるフレームワークの設定部分を以下に抜粋しています。
<Project Sdk="MSBuild.Sdk.Extras/2.0.54"> <PropertyGroup> <TargetFrameworks>netstandard1.0;netstandard2.0;Xamarin.iOS10;Xamarin.TVOS10;Xamarin.WatchOS10;MonoAndroid60;MonoAndroid70;MonoAndroid71;MonoAndroid80;MonoAndroid81;MonoAndroid90;MonoAndroid10.0;tizen40;</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);uap10.0.16299;</TargetFrameworks> </PropertyGroup> <!-- .... --> </Project>
<TargetFrameworks>
タグの中にセミコロン区切りで指定されている文字列(Xamarin.iOS10
, MonoAndroid10.0
など)は、プロジェクトをビルドするときのターゲットとなるプラットフォームを意味します。
Xamarin.Essentials は、以下のプラットフォームをターゲットとしていることが分かります。
プラットフォーム | ターゲットフレームワークの設定値 |
---|---|
.NET Standard | netstandard1.0 または、netstandard2.0 |
Android | MonoAndroid60 などの MonoAndroidxx (xx は数字) の形式。 |
iOS | Xamarin.iOS10 |
UWP | uap10.0.16299 |
tvOS | Xamarin.TVOS10 |
watchOS | Xamarin.WatchOS10 |
tvOS | Xamarin.TVOS10 |
Tizen | tizen40 |
どうやって複数のフレームワークのコードをビルドしているのか
Xamarin.iOS や Xamarin.Android のような異なるプラットフォームの API を利用するコードを、どのようにビルドしているのか? それを知るには、
<ItemGroup> <!-- .... --> <Compile Include="**\*.shared.cs" /> <Compile Include="**\*.shared.*.cs" /> </ItemGroup>
<Compile Include="**\*.shared.cs" />
と <Compile Include="**\*.shared.*.cs" />
はファイル名に .shared.
が含まれるファイルをコンパイルするということを意味しており、この条件にマッチするソースコードはすべてのプラットフォームにおいてコンパイル対象になることが分かります。
<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) "> <Compile Include="**\*.ios.cs" /> <Compile Include="**\*.ios.*.cs" /> <Reference Include="System.Numerics" /> <Reference Include="System.Numerics.Vectors" /> <Reference Include="OpenTK-1.0" /> </ItemGroup>
Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) "
は、ターゲットプラットフォームが Xamarin.iOS
のときに有効になる設定です。<Compile Include="**\*.ios.cs" />
と <Compile Include="**\*.ios.*.cs" />
はファイル名に .ios.
が含まれるファイルをコンパイルするという意味です。各プラットフォームでビルド対象となるファイル名の関係を、以下にまとめます。
プラットフォーム | ビルド対象となるソースコード |
---|---|
.NET Standard | ファイル名に .shared. 、または .netstandard. が含まれるコード |
Android | ファイル名に .shared. 、または .android. が含まれるコード |
iOS | ファイル名に .shared. 、または .ios. が含まれるコード |
UWP | ファイル名に .shared. 、または .uwp. が含まれるコード |
tvOS | ファイル名に .shared. 、または .tvos. が含まれるコード |
watchOS | ファイル名に .shared. 、または .watchos. が含まれるコード` |
tvOS | ファイル名に .shared. 、または .tvos. が含まれるコード |
Tizen | ファイル名に .shared. 、または .tizen. が含まれるコード |
どうやってプラットフォーム固有の処理を書いているのか
どのようにプラットフォーム固有の処理を実装しているかについてですが、ポイントは以下となります。
- 部分クラス (partial class) を利用して、プラットフォーム固有の部分を別のファイルに記述する
例として、Preferences 機能のコードを見ていきます。
プラットフォームで共通にビルドされるコード(Preferences.shared.cs
)を以下に抜粋します。以下の二つの点に注目してください。
- 部分クラスを利用している
PlatformX
というメソッドが利用されているが、.shared.
のファイルの中にそのメソッドの処理はかかれていない
public static partial class Preferences { // ..... public static bool ContainsKey(string key, string sharedName) => PlatformContainsKey(key, sharedName); public static void Remove(string key, string sharedName) => PlatformRemove(key, sharedName); public static void Clear(string sharedName) => PlatformClear(sharedName); public static string Get(string key, string defaultValue, string sharedName) => PlatformGet<string>(key, defaultValue, sharedName); // ..... }
次にプラットフォーム固有のソースコードを見てみます。例として、Android プラットフォームのコード(Preferences.android.cs
)を抜粋します。
- 部分クラスを利用している
.shared.
のファイルに実装されていなかったPlatformX
というメソッドが実装されている
public static partial class Preferences { static readonly object locker = new object(); static bool PlatformContainsKey(string key, string sharedName) { // .... } static void PlatformRemove(string key, string sharedName) { // .... } static void PlatformClear(string sharedName) { // .... } static T PlatformGet<T>(string key, T defaultValue, string sharedName) { // .... } }
部分クラスを利用することで、ビルド時にターゲットとなるプラットフォームでビルド対象となるコードと、常にビルド対象となるコードが組み合わされてコンパイルされるように作られていることが分かります。
このように Xamarin.Essentials では、プラットフォーム固有の処理を分けてマルチターゲットのクラスライブラリを実装しているわけです。
おわりに
Xamarin.Essentials は使うのもよいのですが、コードを読むととても勉強になるライブラリなのではないかと思います。 理由は、プラットフォーム固有の機能を利用するときに、ネイティブでどの API を利用すればよいのかを学ぶことができるからです。
Xamarin を使っているエンジニアの中には、以前は C# で .NET のアプリを作っていて、Xamarin からモバイルアプリを作るようになった人もいるのではないでしょうか。そいういう人の中で、ネイティブの知識不足に悩んでいる方がいらっしゃるかもしれません。そういう人にとって、Xamarin.Essentials のソースコードが、ネイティブの知識を効率的に学んでいくための一つの教材になるのではないかと思っています。
今回の記事は、Xamarin.Essentials の概要について書きましたが、個々の機能についても少しづつまとめていきたいと思っています。