Xamarin.Essentials 入門 - #9 クリップボード
はじめに
Xamarin.Essentials のクリップボード API について記載します。この API では、アプリのクリップボードのテキストの取得・設定の API、クリップボードのデータが変更したときのイベントハンドラが提供されます。
使ってみよう
使い方
Xamarin.Essentials のクリップボードの API は、Clipboard
クラスで提供されており、以下のことができます。
// クリップボードにテキストが含まれているかを判定する var hasText = Clipboard.HasText; // クリップボードにテキストをコピーする await Clipboard.SetTextAsync("Hello World"); // テキストをクリップボードから取得する var text = await Clipboard.GetTextAsync() // クリップボードの内容が変更されたときのイベント処理 Clipboard.ClipboardContentChanged += OnClipboardContentChanged; void OnClipboardContentChanged(object sender, EventArgs e) { Console.WriteLine($"Last clipboard change at {DateTime.UtcNow:T}";); }
読んでみよう
Clipboard のコードを読んで、プラットフォーム固有の処理を見ていきます。
iOS
クリップボードの操作は、UIPasteboard
を利用して、クリップボードの操作をしていることが分かります。以下は、iOS プラットフォームのコードの抜粋です。
static Task PlatformSetTextAsync(string text) { UIPasteboard.General.String = text; return Task.CompletedTask; } static NSObject observer; static bool PlatformHasText => UIPasteboard.General.HasStrings; static Task<string> PlatformGetTextAsync() => Task.FromResult(UIPasteboard.General.String);
クリップボードの内容が変更されたときのイベント処理は、NSNotificationCenter.DefaultCenter.AddObserver
を利用して、クリップボードが変更を観測する Observer を登録しています。
static void StartClipboardListeners() { observer = NSNotificationCenter.DefaultCenter.AddObserver( UIPasteboard.ChangedNotification, ClipboardChangedObserver); } static void StopClipboardListeners() => NSNotificationCenter.DefaultCenter.RemoveObserver(observer); static void ClipboardChangedObserver(NSNotification notification) => ClipboardChangedInternal();
Android
クリップボードの操作は、ClipboardManager
を利用して、クリップボードの操作をしていることが分かります。以下は、Android プラットフォームのコードの抜粋です。
static Task PlatformSetTextAsync(string text) { Platform.ClipboardManager.PrimaryClip = ClipData.NewPlainText("Text", text); return Task.CompletedTask; } static bool PlatformHasText => Platform.ClipboardManager.HasPrimaryClip && !string.IsNullOrEmpty(Platform.ClipboardManager.PrimaryClip?.GetItemAt(0)?.Text); static Task<string> PlatformGetTextAsync() => Task.FromResult(Platform.ClipboardManager.PrimaryClip?.GetItemAt(0)?.Text);
イベント処理は、ClipboardManager.IOnPrimaryClipChangedListener
インタフェースを実装したイベントリスナークラスを作成し、ClipboardManager
クラスにイベントリスナーを登録、削除していることが分かります。
class ClipboardChangeListener : Java.Lang.Object, IOnPrimaryClipChangedListener { void IOnPrimaryClipChangedListener.OnPrimaryClipChanged() => Clipboard.ClipboardChangedInternal(); } static void StartClipboardListeners() => Platform.ClipboardManager.AddPrimaryClipChangedListener(clipboardListener.Value); static void StopClipboardListeners() => Platform.ClipboardManager.RemovePrimaryClipChangedListener(clipboardListener.Value);
UWP
クリップボードの操作では、Windows.ApplicationModel.DataTransfer.Clipboard
クラスの各種メソッドを利用して、アプリの情報を取得していることが分かります。以下は、UWP プラットフォームのコードの抜粋です。
static Task PlatformSetTextAsync(string text) { var dataPackage = new DataPackage(); dataPackage.SetText(text); WindowsClipboard.SetContent(dataPackage); return Task.CompletedTask; } static bool PlatformHasText => WindowsClipboard.GetContent().Contains(StandardDataFormats.Text); static Task<string> PlatformGetTextAsync() { var clipboardContent = WindowsClipboard.GetContent(); return clipboardContent.Contains(StandardDataFormats.Text) ? clipboardContent.GetTextAsync().AsTask() : Task.FromResult<string>(null); }
イベント処理も、Windows.ApplicationModel.DataTransfer.Clipboard
クラスのイベントハンドラに共通のイベント処理を登録していることが分かります。
static void StartClipboardListeners() => WindowsClipboard.ContentChanged += ClipboardChangedEventListener; static void StopClipboardListeners() => WindowsClipboard.ContentChanged -= ClipboardChangedEventListener; static void ClipboardChangedEventListener(object sender, object val) => ClipboardChangedInternal();
まとめ
- Xamarin.Essentials のクリップボード API では、以下の機能が提供される
- 内部では、以下のネイティブ固有のAPI を利用している
- クリップボード関連の操作
- iOS :
UIPasteboard
クラスを利用している - Android :
ClipboardManager
を利用している - UWP :
Windows.ApplicationModel.DataTransfer.Clipboard
クラスを利用している
- iOS :
- クリップボードの内容のイベント処理
- iOS :
NSNotificationCenter.DefaultCenter.AddObserver
を利用している - Android : イベント処理は、
ClipboardManager.IOnPrimaryClipChangedListener
インタフェースを実装したイベントリスナークラスを作成し、ClipboardManager
クラスにイベントリスナーを登録、削除している - UWP :
Windows.ApplicationModel.DataTransfer.Clipboard
クラスのイベントハンドラを利用している
- iOS :
- クリップボード関連の操作
参考
Xamarin.UITest Tips - Xamarin.Forms WebView 利用時のメモ
はじめに
とある案件で、Xamarin.iOS の WKWebView を利用したアプリを Xamarin.UITest で自動化することがあって、
Xamarin.UITest のドキュメントを確認すると、app.Query(c=>c.Class("WKWebView"))
で WKWebView を取得することができると記載されていました。
念のため、Xamarin.Forms の場合はどうなるか、確認してみました。
まとめ
Xamarin.Forms の場合でも iOS では、app.Query(x =>x.Class("WKWebView"))
のように Class
メソッドの引数に WKWebView
を指定して WebView を取得する必要がある。
試したこと
Xamarin.Forms で WebView が配置された簡単なサンプルアプリを Xamarin.UITest で WebView が取得できるかを確認しました。
REPL を起動して、app.Query(x => x.WebView())
で試してみましたが、予想通り何も取得できせんでした。
app.Query(c=>c.Class("WKWebView"))
で試してみると、下の図のように取得することができました。
参考:サンプル
以下のサンプルを利用しました。
サンプルの一部を抜粋しておきます。
<?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="WebViewSample.LoadingLabelXaml" Title="Loading Demo"> <StackLayout> <!--Loading label should not render by default.--> <Label x:Name="labelLoading" Text="Loading..." IsVisible="false" /> <WebView HeightRequest="1000" WidthRequest="1000" Source="https://dotnet.microsoft.com/apps/xamarin" Navigated="webviewNavigated" Navigating="webviewNavigating" /> </StackLayout> </ContentPage>
Xamarin.Essentials 入門 - #8 アプリのテーマ
はじめに
Xamarin.Essentials のアプリのテーマについて記載します。この API を利用することで、システムから要求されているテーマを取得することができます。
使ってみよう
使い方
Xamarin.Essentials のアプリのテーマの機能は、AppInfo
クラスで提供されています。
AppTheme appTheme = AppInfo.RequestedTheme;
返却される AppTheme
列挙体は以下のいずれかの値になります。
namespace Xamarin.Essentials { public enum AppTheme { Unspecified, // 指定されていない Light, // ライトテーマ Dark // ダークテーマ } }
読んでみよう
AppInfo のコードを読んで、プラットフォーム固有の処理を見ていきます。
iOS
テーマ情報の取得には、UITraitCollection
から UserInterfaceStyle
プロパティの値を取得して、システムから要求されているテーマを判定していることが分かります。以下は、iOS プラットフォームのコードの抜粋です。
static AppTheme PlatformRequestedTheme() { if (!Platform.HasOSVersion(13, 0)) return AppTheme.Unspecified; var uiStyle = Platform.GetCurrentUIViewController()?.TraitCollection?.UserInterfaceStyle ?? UITraitCollection.CurrentTraitCollection.UserInterfaceStyle; return uiStyle switch { UIUserInterfaceStyle.Light => AppTheme.Light, UIUserInterfaceStyle.Dark => AppTheme.Dark, _ => AppTheme.Unspecified }; }
なお、iOS 13 より前のバージョンの環境では、AppTheme.Unspecified
が返されます。
Android
Android.Content.Res.Configuration
クラスの UiMode
プロパティからシステムに要求されているテーマを判定しています。以下は、Android プラットフォームのコードの抜粋です。
static AppTheme PlatformRequestedTheme() { return (Platform.AppContext.Resources.Configuration.UiMode & UiMode.NightMask) switch { UiMode.NightYes => AppTheme.Dark, UiMode.NightNo => AppTheme.Light, _ => AppTheme.Unspecified }; }
UWP
アプリのテーマの取得には、Windows.UI.Xaml.Application
クラスの RequestedTheme
プロパティが利用されていることがわかります。このプロパティの値は、Windows.UI.Xaml.ApplicationTheme
列挙体で Dark
又は、Light
の値を持ちます。
static AppTheme PlatformRequestedTheme() => Application.Current.RequestedTheme == ApplicationTheme.Dark ? AppTheme.Dark : AppTheme.Light;
まとめ
- Xamarin.Essentials のアプリのテーマでは、以下の機能が提供される
- システムから要求されているアプリのテーマに関する情報を取得することができる
- 内部では、以下のネイティブ固有のAPI を利用している
- アプリ情報の取得(ビルド、名前、パッケージ名、バージョン文字列)
- iOS :
UITraitCollection
からUserInterfaceStyle
プロパティを利用している - Android :
Android.Content.Res.Configuration
クラスのUiMode
プロパティを利用している - UWP :
Windows.UI.Xaml.Application
クラスのRequestedTheme
プロパティを利用している
- iOS :
- アプリ情報の取得(ビルド、名前、パッケージ名、バージョン文字列)