Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

コンソールアプリケーションとしても振る舞えるXamarin.Macアプリケーションの作り方

More than 3 years have passed since last update.

Problem

GUIアプリケーションとして通常のフローで立ち上げることができる。
しかしターミナルなどから引数を与えて立ち上げたときはそのまま標準出力に結果を返して終了する。
そういうことをmacOSアプリでやりたくなったときに参考にしてください。
方法論としてXamarin特有というわけではありませんが,ここではXamarin.Macを使って解説します。

TL;DR

エントリポイント Main.cs で分岐します。

Prerequisites

  • Visual Studio for Mac Version 7.3 (build 799)
  • Xamarin.Mac 4.0.0.214

ここで作ったサンプルは GitHub:xamarin-mac-console-sample に公開してあります。

Solution

プロジェクトを作る

Xamarin.Macプロジェクトを適当に作ります。詳しい手順は割愛しますが,ウィンドウが立ち上がるようにしておいてください。
Screen Shot 2017-12-14 at 15.14.41.png

Main.csで引数をパースする

Main.cs はたいてい次のようになっているはずです。

Main.cs
using AppKit;

namespace ConsoleSample
{
    static class MainClass
    {
        static void Main(string[] args)
        {
            NSApplication.Init();
            NSApplication.Main(args);
        }
    }
}

NSApplication.Init を呼ぶと,NSNotificationCenter.DefaultCenterやら,NSFileManager.DefaultManagerなどNS*系の静的インスタンスが確保され使えるようになります。つまり呼ばないとNS*系のなにがしかは使えたり使えなかったりします。だいたい使えません。

NSApplication.Main を呼ぶとアプリケーションの起動シーケンスに入り,AppDelegateへ制御が移っていきます。その前に引数をパースして処理を分岐するのが本稿の目的とするところです。ということで適当にコマンドラインパーサーをNuGet経由で入れるなり,自前でパースするなりしましょう。ここではdotnet-corefxlabリポジトリで提供されているSystem.CommandLineを使います。雑ですがおおよそ次のようになるでしょう。

Main.cs
using System;
using System.CommandLine;
using AppKit;

namespace ConsoleSample
{
    static class MainClass
    {
        static void Main(string[] args)
        {
            var input = string.Empty;

            ArgumentSyntax.Parse(args, syntax =>
            {
                syntax.DefineOption("i|input", ref input, true, "Something interesting.");

                syntax.ErrorOnUnexpectedArguments = false;
            });

            if (string.IsNullOrEmpty(input))
            {
                NSApplication.Init();
                NSApplication.Main(args);
            }
            else
            {
                Console.WriteLine($"{input.Length} - {input}");
            }
        }
    }
}

プロジェクトの設定から引数を指定してデバッグする,ターミナルから引数を与えて起動するなどで動作を確認できます。ターミナルから起動したい場合は app/Contents/MacOS/ にエントリポイントがあります。
Screen Shot 2017-12-14 at 15.27.56.png
Screen Shot 2017-12-14 at 15.28.16.png

% ./ConsoleSample.app/Contents/MacOS/ConsoleSample -i Hello
5 - Hello

当然ながら,何も引数を与えなければウィンドウが立ち上がり,通常のアプリとして振る舞います。

Conclusion

Main.cs で起動前になんでもできることがわかりました。
ネイティブライブラリを読み込んでおいたり集約例外ハンドラを設置したりと,それなりのアプリケーションを作る際にはこの辺でいろいろ介入が必要になってくると思います。ぜひ覚えておいてください。

ailen0ada
Xamarin.Mac の人です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away