より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

UnityContainer+Xamarinでスクリーンショット機能を実装する(iOS)

Xamarinでスクシーンショットを取る機能を追加したいときの話です。

私の場合はUnityContainerを用いて、iOSAndroidのプロジェクトで実体をUnityContainerに納めておき、Xamarinのプロジェクトからはインターフェースを指定して解決させるというものです。

xamarinhelp.com

上記の記事の内容をベースにして、UnityContainerを活用した形です。

共通インターフェースの宣言

IScreenShotService

    /// <summary>
    /// 画面キャプチャを取るサービスのインタフェースです。
    /// </summary>
    public interface IScreenShotService
    {
        /// <summary>
        /// 画面キャプチャを取ります。
        /// </summary>
        void Capture();
    }

iOS側のプロジェクトでやること

ScreenShotService.cs

    /// <summary>
    /// iOSでのスクリーンショットを行うクラスです。
    /// </summary>
    public class ScreenShotService : IScreenShotService
    {
        /// <inheritdoc />
        /// <remarks>
        /// Info.plistに以下を宣言する必要があります。
        /// iOS10はNSPhotoLibraryUsageDescription
        /// iOS11はNSPhotoLibraryAddUsageDescriptionの指定が必要。
        /// <para>
        /// <key>NSPhotoLibraryUsageDescription</key>
        /// <string>Please allow the application to display the photo library.</string>
        /// <key>NSPhotoLibraryAddUsageDescription</key>
        /// <string>Please allow the application to display the photo library.</string>
        /// </para>
        /// </remarks>
        public void Capture()
        {
            using (var capture = UIScreen.MainScreen.Capture())
            {
                capture.SaveToPhotosAlbum((image, error) =>
                {
                    Console.WriteLine("error:" + error?.LocalizedFailureReason + Environment.NewLine +
                                      error?.LocalizedDescription);
                });
            }
        }
    }

Main.cs

// ContainerはIUnityContainerのインスタンス
Container.RegisterInstance<IScreenShotService>(new ScreenShotService());

Xamarin側のプロジェクトでは

スクリーンショットを取る実装

// ContainerはIUnityContainerのインスタンス(もちろん、iOS側でRegisterInstanceしたオブジェクトを渡してください)
Container.Resolve<IScreenShotService>().Capture();

iOSではプライバシーキーの指定を忘れずに

これだけではダメで、Info.plistの編集が必要です。

Visual Studio 2019では対応していない(XCodeなら可能)ので、直接Info.plistを編集してください。

(中略)

    <key>NSPhotoLibraryUsageDescription</key>
    <string>Please allow the application to display the photo library.</string>
    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>Please allow the application to display the photo library.</string>

</dict>
</plist>

iOS11では画像をアルバム保存するアプリはPrivacyへの追記が必要になりました - Qiita

iOS10ではカメラアクセスなどの目的を明示しないと強制終了する - Qiita

上記の2記事を参考にさせていただいてますが、iOS12でもこれでOKです。もう仕様を変えないでくれ・・・。

最後に

スクリーンショットiOS標準で用意されてはいるので十分ですが、操作方法が2つのボタン同時押しであるためボタンがへこみそうだし、手軽さがありません。

私のXamarinの利用用途はプライベートの個人用アプリですが、スクリーンショット機能は私には重要です。

スクリーンショットはバグ管理に欠かせないからです。バグを憎んでもしょうがないのでTrelloで管理します。

Androidは、持ってないので、まだ試してません。