これにはさまざまな手段が用意されている。
共有プロジェクトでは、#ifディレクティブが使える。また、以下に示すOnPlatformやCustom Rendererなども利用できる。
PCLプロジェクトでは次のような手段が利用できる。本稿では、先頭から3つを取り上げて解説していく。
共有プロジェクト(Shared Project)の中では、#ifディレクティブを使ってプラットフォームごとの処理を切り替えられる。
例として、プラットフォームごとに異なる文字列を表示してみよう。先ほど作った共有プロジェクトによるXamarin.Formsのプロジェクトを、以下のように変更する。
まず、共有プロジェクトの「MainPage.xaml」を開き、Labelコントロールに「Label1」と名前を付ける(次のコード)。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SharedPrj"
x:Class="SharedPrj.MainPage">
<!--<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />-->
<Label x:Name="Label1"
FontSize="Large" TextColor="Green"
VerticalOptions="Center"
HorizontalOptions="Center" />
</ContentPage>
続いて、コードビハインド「MainPage.xaml.cs」を開き、次のコードのように編集する。
……省略……
public MainPage()
{
InitializeComponent();
#if __IOS__
// iOS用のコード
Label1.Text = "Hello, iOS!";
#elif __ANDROID__
// Android用のコード
Label1.Text = "Hello, Android!";
#elif WINDOWS_UWP
// UWP用のコード
Label1.Text = "Hello, UWP!";
#elif WINDOWS_APP
// Windows 8.1用のコード
Label1.Text = "Hello, Windows!";
#elif WINDOWS__PHONE_APP
// Windows Phone 8.1用のコード
Label1.Text = "Hello, Windows Phone!";
#endif
}
……省略……
上のコードに登場する「__IOS__」などの条件付きコンパイルシンボルは、プロジェクトの作成時に自動生成されている。そのため、このように#ifディレクティブを使ってプラットフォームごとのコードを記述できるのだ。
なお、#ifディレクティブの中では、プラットフォーム固有のAPIも呼び出せる。プラットフォームごとにロジックを切り替えるには最強の方法といえるが、乱用するとコードが読みにくいものになりかねない。プラットフォームごとの処理はできるだけプラットフォームごとのプロジェクトにメソッドやクラスとしてまとめておき、共有プロジェクトの#ifディレクティブではそのメソッドを呼び出すだけにするといった工夫が必要だ。
上のコードを実行してみると次の画像のようになる。
この方法は、Xamarin.FormsのXAMLコードで頻繁に使われる。
OnPlatform<T>クラス(Xamarin.Forms名前空間)は、コードビハインドでもXAMLコードでも利用できる。PCLプロジェクトの場合には、OnPlatformでプラットフォーム依存のAPIは利用できない(共有プロジェクトでは利用できるが、コードビハインドでは#ifディレクティブを使った方が簡単だ)。
例えば、XAMLコードでLabelコントロールの色をプラットフォームごとに変えるには、次のコードのようにする。
<Label Text="Welcome to Xamarin Forms!"
x:Name="Label1" FontSize="Large">
<Label.TextColor>
<OnPlatform x:TypeArguments="Color"
iOS="Red" Android="Blue" WinPhone="Green"
/>
</Label.TextColor>
</Label>
また、コードビハインドで、プラットフォームごとに異なる文字列を設定するには、次のコードのようにする。
// 【1】一般的な書き方
string s = Device.OnPlatform("iOS", "Android", "Windows");
// 【2】名前付き引数で書くと、分かりやすい
string s = Device.OnPlatform(
iOS: "iOS",
Android: "Android",
WinPhone: "Windows"
);
// 【3】OnPlatform<T>クラスを直接インスタンス化してもよい
var s = new OnPlatform<string>()
{
iOS = "iOS",
Android = "Android",
WinPhone = "Windows",
};
OnPlatformの使い方については、「.NET TIPS:Xamarin.Forms:プラットフォームに応じて画面の一部を変えるには?」で詳しく解説している。
これはちょっと長い説明になるが、PCLプロジェクトでプラットフォームに依存するAPIを利用するロジックを書くには必須のテクニックである。
DependencyServiceクラス(Xamarin.Forms名前空間)は一種のDIコンテナであり、プラットフォームごとに実装したオブジェクトをPCL内から利用できる。DependencyServiceクラスを使うコーディングの手順は、次のようになる。
例として、OSのバージョンに関する文字列を取得してみよう。
1. インタフェースを定義する
まず、PCLプロジェクトにインタフェースを定義する。インタフェース名は自由に決めてよいが、ここでは「IPlatformInfo」インタフェースとし、次のコードのように記述する。
namespace Xamarin101
{
// DependencyServiceで使うインタフェース
public interface IPlatformInfo
{
// OSのバージョン文字列を返すプロパティ(読み取り専用)
string OsVersion { get; }
}
}
2. プラットフォームごとにインタフェースを実装する
上で定義したインタフェースの実装として、プラットフォームごとに「PlatformInfo」クラスを記述していく。
そのとき、ソースコードの冒頭にDependency属性の指定が必要だ。それは、「このアセンブリには、DependencyServiceで使うPlatformInfoクラスがありますよ」といった意味である。
まず、Androidの実装(次のコード)。
[assembly: Xamarin.Forms.Dependency(typeof(Xamarin101.Droid.PlatformInfo))]
namespace Xamarin101.Droid
{
// DependencyServiceで使う実装(Android)
public class PlatformInfo : IPlatformInfo
{
public string OsVersion
{
get { return Android.OS.Build.VERSION.Release; }
}
}
}
次のコードがiOSのものだ。
[assembly: Xamarin.Forms.Dependency(typeof(Xamarin101.iOS.PlatformInfo))]
namespace Xamarin101.iOS
{
// DependencyServiceで使う実装(iOS)
public class PlatformInfo : IPlatformInfo
{
public string OsVersion
{
get
{
var device = UIKit.UIDevice.CurrentDevice;
return $"{device.SystemName} {device.SystemVersion}";
}
}
}
}
そして、UWP用のコードは次のようになる。
using Windows.Security.ExchangeActiveSyncProvisioning;
[assembly: Xamarin.Forms.Dependency(typeof(Xamarin101.UWP.PlatformInfo))]
namespace Xamarin101.UWP
{
// DependencyServiceで使う実装(UWP)
public class PlatformInfo : IPlatformInfo
{
var devInfo = new EasClientDeviceInformation();
public string OsVersion
{
get { return devInfo.OperatingSystem; }
}
}
}
3. DependencyServiceを使う
最後に、PCLで次のコードのようにしてプラットフォームに依存するコードを使う。
// DependencyServiceから、IPlatformInfoオブジェクトを取得する
IPlatformInfo platformInfo = DependencyService.Get<IPlatformInfo>();
// 取得したオブジェクトを使う
string version = platformInfo.OsVersion;
なお、以上のDependencyServiceの使い方については、「.NET TIPS:Xamarin.Forms:プラットフォームに依存する処理を書くには?」で詳しく解説している。また、ユーザーデータの読み書きを、DependencyServiceではなくPCL Storageを使うことで簡単に実装する方法を「.NET TIPS:Xamarin.Forms:ユーザーデータを保存するには?」で解説している。
Copyright© Digital Advantage Corp. All Rights Reserved.