Xamarin.Essentials 入門 - #7 アプリ情報
はじめに
Xamarin.Essentials のアプリ情報について記載します。この API を利用することで、アプリケーション名やバージョン情報を取得することができます。
使ってみよう
使い方
Xamarin.Essentials のアプリ情報の機能は、AppInfo
クラスで提供されており、以下のことができます。
- ビルド
- 名前
- パッケージ名
- バージョン文字列
- アプリケーションの設定の表示
// アプリ名 var appName = AppInfo.Name; // パッケージ名(Android)、Bundle Identifier (iOS) var packageName = AppInfo.PackageName; // アプリのバージョン文字列 (1.0.0) var version = AppInfo.VersionString; // アプリのビルド番号 var build = AppInfo.BuildString; // アプリの設定画面を開く AppInfo.ShowSettingsUI();
読んでみよう
AppInfo のコードを読んで、プラットフォーム固有の処理を見ていきます。
iOS
アプリ情報の取得には、NSBundle.MainBundle.ObjectForInfoDictionary
を利用して、アプリの情報を取得していることが分かります。以下は、iOS プラットフォームのコードの抜粋です。
static string PlatformGetPackageName() => GetBundleValue("CFBundleIdentifier"); static string PlatformGetName() => GetBundleValue("CFBundleDisplayName") ?? GetBundleValue("CFBundleName"); static string PlatformGetVersionString() => GetBundleValue("CFBundleShortVersionString"); static string PlatformGetBuild() => GetBundleValue("CFBundleVersion"); static string GetBundleValue(string key) => NSBundle.MainBundle.ObjectForInfoDictionary(key)?.ToString();
設定画面の表示は、Xamarin.Essentials の Launcher
を利用しています。
static async void PlatformShowSettingsUI() => await Launcher.OpenAsync(UIApplication.OpenSettingsUrlString);
Android
アプリ情報の取得には、Context
から ApplicationInfo
や PackageManager
を取得して、それぞれのメソッド、プロパティを利用して、アプリの情報を取得していることが分かります。以下は、Android プラットフォームのコードの抜粋です。
static string PlatformGetPackageName() => Platform.AppContext.PackageName; static string PlatformGetName() { var applicationInfo = Platform.AppContext.ApplicationInfo; var packageManager = Platform.AppContext.PackageManager; return applicationInfo.LoadLabel(packageManager); } static string PlatformGetVersionString() { var pm = Platform.AppContext.PackageManager; var packageName = Platform.AppContext.PackageName; using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData)) { return info.VersionName; } } static string PlatformGetBuild() { var pm = Platform.AppContext.PackageManager; var packageName = Platform.AppContext.PackageName; using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData)) { #if __ANDROID_28__ return PackageInfoCompat.GetLongVersionCode(info).ToString(CultureInfo.InvariantCulture); #else #pragma warning disable CS0618 // Type or member is obsolete return info.VersionCode.ToString(CultureInfo.InvariantCulture); #pragma warning restore CS0618 // Type or member is obsolete #endif } }
なお、__ANDROID_28__
が指定されている部分は、API 28 以降の場合に実行されるコードです。API レベル 28 移行では、PackageInfo.versionCode
が非推奨になったため、このようなコードが書かれています。
設定画面を開く機能では、Intent
のアクションに Settings
クラスの ActionApplicationDetailsSettings
定数(Android のACTION_APPLICATION_DETAILS_SETTINGSに相当)を設定、データとしてアプリのパッケージ名を設定して、Context
の StartActivity
が利用されています。
static void PlatformShowSettingsUI() { var context = Platform.GetCurrentActivity(false) ?? Platform.AppContext; var settingsIntent = new Intent(); settingsIntent.SetAction(global::Android.Provider.Settings.ActionApplicationDetailsSettings); settingsIntent.AddCategory(Intent.CategoryDefault); settingsIntent.SetData(global::Android.Net.Uri.Parse("package:" + PlatformGetPackageName())); var flags = ActivityFlags.NewTask | ActivityFlags.NoHistory | ActivityFlags.ExcludeFromRecents; #if __ANDROID_24__ if (Platform.HasApiLevelN) flags |= ActivityFlags.LaunchAdjacent; #endif settingsIntent.SetFlags(flags); context.StartActivity(settingsIntent); }
UWP
アプリ情報の取得には、Windows.ApplicationModel.Package
クラスを利用して、アプリの情報を取得していることが分かります。以下は、UWP プラットフォームのコードの抜粋です。
static string PlatformGetPackageName() => Package.Current.Id.Name; static string PlatformGetName() => Package.Current.DisplayName; static string PlatformGetVersionString() { var version = Package.Current.Id.Version; return $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"; } static string PlatformGetBuild() => Package.Current.Id.Version.Build.ToString(CultureInfo.InvariantCulture);
設定画面を開く機能では、Windows.System.Launcher.LaunchUriAsync
を利用しています。引数に ms-settings:appsfeatures-app
を渡して設定画面を開いています。
static void PlatformShowSettingsUI() => Windows.System.Launcher.LaunchUriAsync(new System.Uri("ms-settings:appsfeatures-app")).WatchForError();
まとめ
- Xamarin.Essentials のアプリ情報では、以下の機能が提供される
- アプリケーションに関する情報(ビルド、名前、パッケージ名、バージョン文字列)を取得することができる
- アプリケーションの設定画面を開くことができる
- 内部では、以下のネイティブ固有のAPI を利用している
- アプリ情報の取得(ビルド、名前、パッケージ名、バージョン文字列)
- 設定画面を開く
参考
Xamarin.UITest Tips - Xamarin.Forms CarouselView
はじめに
この記事では、Xamarin.UITest を利用して、Xamarin.Forms の CarouselView を操作する方法を解説します。
CarouselView のサンプルコード
Xamarin.UITest で操作する SwipeView には、Microsoft の Xamarin.Forms のサンプルの「Horizontal layout Data Template」を利用します。
画面中央に表示されているサルが表示されているの項目を、特定の名前のサルが表示されるまでスワイプする操作を Xamarin.UITest で行います。
Xamarin.UITest で CarouselView を操作する
CarouselView の UI 構造
Repl を利用して、UI の構造を調べてみると、サンプルの CarouselView は iOS と Android で異なるクラスで UI が構築されていることがわかります。
プラットフォーム | クラス名 |
---|---|
iOS | Xamarin_Forms_Platform_iOS_CarouselTemplatedCell |
Android | CarouselViewRenderer |
Xamarin.UITest で操作をする場合には、このクラスに対してクエリを行う必要があります。 また、CarouselView の中の UI 構造も各プラットフォームで異なるため、特定の名前のサルが表示されているかどうかを判定するために取得する UI 要素も異なってきます。
Android の場合
Android の場合は、CarouselViewRenderer
が持つ LabelRenderer
の Text にサルの名前が表示されています。特定の名前のサルが表示されているかどうかは、LabelRenderer
要素を取得して判断することになります。
[CarouselViewRenderer > ... > Platform_DefaultRenderer] id: "NoResourceEntry-6" [FrameRenderer > Platform_DefaultRenderer] id: "NoResourceEntry-8" [LabelRenderer] id: "NoResourceEntry-9" text: "Baboon" [ImageRenderer] id: "NoResourceEntry-10" [LabelRenderer] id: "NoResourceEntry-11" text: "Africa & Asia" [LabelRenderer] id: "NoResourceEntry-12" text: "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae."
iOS の場合
iOS の場合は、Xamarin_Forms_Platform_iOS_CarouselTemplatedCell
が持つ UILabel
の Text にサルの名前が表示されています。特定の名前のサルが表示されているかどうかは、UILabel
要素を取得して判断することになります。
[Xamarin_Forms_Platform_iOS_CarouselTemplatedCell > ... > Xamarin_Forms_Platform_iOS_Platform_DefaultRenderer] [Xamarin_Forms_Platform_iOS_LabelRenderer] [UILabel] label: "Baboon", text: "Baboon" [Xamarin_Forms_Platform_iOS_ImageRenderer > Xamarin_Forms_Platform_iOS_FormsUIImageView] [Xamarin_Forms_Platform_iOS_LabelRenderer] [UILabel] label: "Africa & Asia", text: "Africa & Asia" [Xamarin_Forms_Platform_iOS_LabelRenderer] [UILabel] label: "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.", text: "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae."
CarouselView を操作するコード
ここでは、名前が Tonkin Snub-nosed Monkey というサルが表示するまで、CarouselView をスワイプするサンプルを記載します。
- スワイプ操作には、
IApp.SwipeRightToLeft
利用します。 - 表示されるまでスワイプ操作を繰り返すには、
IApp.WaitFor
を利用します- このメソッドの引数に、
CarouselView
をスワイプして、表示されているサルの名前を取得し、表示したい名前のサルが表示されている場合に、処理を終了させます
- このメソッドの引数に、
サンプルは、以下のようになります。
Func<AppQuery, AppQuery> caroucelViewQuery; string croucelViewClassName; if(platform == Platform.Android) { croucelViewClassName = "CarouselViewRenderer"; caroucelViewQuery = x => x.Class(croucelViewClassName).Index(0).Descendant("LabelRenderer").Index(0); } else { croucelViewClassName = "Xamarin_Forms_Platform_iOS_CarouselTemplatedCell"; caroucelViewQuery = x => x.Class(croucelViewClassName).Index(0).Class("Xamarin_Forms_Platform_iOS_LabelRenderer").Index(1).Class("UILabel"); } app.WaitFor(() => { var foundItem = false; while(!foundItem) { var carouselItemTitleLabel = app.Query(caroucelViewQuery).FirstOrDefault(); if(carouselItemTitleLabel.Text == "Tonkin Snub-nosed Monkey") { foundItem = true; } else { app.SwipeRightToLeft(x => x.Class(croucelViewClassName).Index(0), swipeSpeed : 10000); } } return foundItem; }, timeout: TimeSpan.FromMinutes(1));
参考資料
Xamarin.UITest Tips - Xamarin.Forms SwipeView
はじめに
この記事では、Xamarin.UITest を利用して、Xamarin.Forms の SwipeView を操作する方法を解説します。
SwipeView のサンプルコード
Xamarin.UITest で操作する SwipeView には、Microsoft の Xamarin.Forms のサンプルの「Swipe direction」を利用します。
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SwipeViewDemos.SwipeViewDirectionPage" Title="SwipeView swipe direction demo"> <StackLayout Margin="20"> <SwipeView> <SwipeView.RightItems> <SwipeItems> <SwipeItem Text="Favorite" IconImageSource="favorite.png" BackgroundColor="LightGreen" Invoked="OnFavoriteSwipeItemInvoked" /> <SwipeItem Text="Delete" IconImageSource="delete.png" BackgroundColor="LightPink" Invoked="OnDeleteSwipeItemInvoked" /> </SwipeItems> </SwipeView.RightItems> <Grid HeightRequest="60" WidthRequest="300" BackgroundColor="LightGray"> <Label Text="Swipe left" HorizontalOptions="Center" VerticalOptions="Center" /> </Grid> </SwipeView> <SwipeView> <SwipeView.LeftItems> <SwipeItems> <SwipeItem Text="Favorite" IconImageSource="favorite.png" BackgroundColor="LightGreen" Invoked="OnFavoriteSwipeItemInvoked" /> <SwipeItem Text="Delete" IconImageSource="delete.png" BackgroundColor="LightPink" Invoked="OnDeleteSwipeItemInvoked" /> </SwipeItems> </SwipeView.LeftItems> <Grid HeightRequest="60" WidthRequest="300" BackgroundColor="LightGray"> <Label Text="Swipe right" HorizontalOptions="Center" VerticalOptions="Center" /> </Grid> </SwipeView> <SwipeView> <SwipeView.BottomItems> <SwipeItems> <SwipeItem Text="Favorite" IconImageSource="favorite.png" BackgroundColor="LightGreen" Invoked="OnFavoriteSwipeItemInvoked" /> <SwipeItem Text="Delete" IconImageSource="delete.png" BackgroundColor="LightPink" Invoked="OnDeleteSwipeItemInvoked" /> </SwipeItems> </SwipeView.BottomItems> <Grid HeightRequest="60" WidthRequest="300" BackgroundColor="LightGray"> <Label Text="Swipe up" HorizontalOptions="Center" VerticalOptions="Center" /> </Grid> </SwipeView> <SwipeView> <SwipeView.TopItems> <SwipeItems> <SwipeItem Text="Favorite" IconImageSource="favorite.png" BackgroundColor="LightGreen" Invoked="OnFavoriteSwipeItemInvoked" /> <SwipeItem Text="Delete" IconImageSource="delete.png" BackgroundColor="LightPink" Invoked="OnDeleteSwipeItemInvoked" /> </SwipeItems> </SwipeView.TopItems> <Grid HeightRequest="60" WidthRequest="300" BackgroundColor="LightGray"> <Label Text="Swipe down" HorizontalOptions="Center" VerticalOptions="Center" /> </Grid> </SwipeView> <SwipeView> <SwipeView.LeftItems> <SwipeItems> <SwipeItem Text="Delete" IconImageSource="delete.png" BackgroundColor="LightPink" Invoked="OnDeleteSwipeItemInvoked" /> </SwipeItems> </SwipeView.LeftItems> <SwipeView.RightItems> <SwipeItems> <SwipeItem Text="Favorite" BackgroundColor="LightGreen" Invoked="OnFavoriteSwipeItemInvoked" /> <SwipeItem Text="Share" BackgroundColor="LightYellow" Invoked="OnShareSwipeItemInvoked" /> </SwipeItems> </SwipeView.RightItems> <Grid HeightRequest="60" WidthRequest="300" BackgroundColor="LightGray"> <Label Text="Swipe left or right" HorizontalOptions="Center" VerticalOptions="Center" /> </Grid> </SwipeView> </StackLayout> </ContentPage>
Xamarin.UITest で SwipeView を操作する
SwipeView の UI の構造
Repl を利用して、UI の構造を調べてみると、SwipeView は iOS と Android で異なるクラスで UI が構築されていることがわかります。
プラットフォーム | クラス名 |
---|---|
iOS | Xamarin_Forms_Platform_iOS_SwipeViewRenderer |
Android | SwipeViewRenderer |
従って、Xamarin.UITest で UI 操作を行うコントロールを取得するには、各プラットフォームで異なるクラス名を利用して、Func<AppQuery, AppQuery>
の式を作る必要があります。
左にスワイプする
IApp.SwipeLeftToRight
メソッドを利用して、左にスワイプを行うことができます。
string className; if(platform == Platform.iOS) { className = "Xamarin_Forms_Platform_iOS_SwipeViewRenderer"; } else { className = "SwipeViewRenderer"; } app.SwipeRightToLeft(x => x.Class(className).Index(0));
右にスワイプする
IApp.SwipeLeftToRight
メソッドを利用して、左にスワイプを行うことができます。
string className; if (platform == Platform.iOS) { className = "Xamarin_Forms_Platform_iOS_SwipeViewRenderer"; } else { className = "SwipeViewRenderer"; } app.SwipeLeftToRight(x => x.Class(className).Index(1));
上にスワイプする
IApp
インタフェースには上にスワイプするメソッドがないので、SwipeView コントロールの座標を取得して、コントロールの中心座標から上の方向にIApp.DragCoordinates
を利用してドラッグすることで、上方向にスワイプを行うことができます。
// SwipeView の座標と高さを取得する string className; if (platform == Platform.iOS) { className = "Xamarin_Forms_Platform_iOS_SwipeViewRenderer"; } else { className = "SwipeViewRenderer"; } var control = app.Query(x => x.Class(className).Index(2)).FirstOrDefault(); var centerX = control.Rect.CenterX; var centerY = control.Rect.CenterY; var height = control.Rect.Height; // SwipeView の中心から高さの分だけ上方向にドラッグする app.DragCoordinates(centerX, centerY, centerX, centerY - height);
下にスワイプする
IApp
インタフェースには上にスワイプするメソッドがないので、SwipeView コントロールの座標を取得して、コントロールの中心座標から下の方向にIApp.DragCoordinates
を利用してドラッグすることで、下方向にスワイプを行うことができます。
// SwipeView の座標と高さを取得する string className; if (platform == Platform.iOS) { className = "Xamarin_Forms_Platform_iOS_SwipeViewRenderer"; } else { className = "SwipeViewRenderer"; } var control = app.Query(x => x.Class(className).Index(3)).FirstOrDefault(); var centerX = control.Rect.CenterX; var centerY = control.Rect.CenterY; var height = control.Rect.Height; // SwipeView の中心から高さの分だけ下方向にドラッグする app.DragCoordinates(centerX, centerY, centerX, centerY + height);