tafuji's blog

C#, Xamarin, Azure DevOps を中心に書いています。

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();

まとめ

参考