個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Xamarin に関する事を中心に書いています。 Microsoft MVP for Development Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

2月10日(土)に、品川でXamarin.iOS 、Xamarin.Androidのハンズオンを開催いたしました!

こんにちは、@hiro128_777です。

2月10日(土)に、品川でXamarin.iOS 、Xamarin.Androidのハンズオンを開催いたしました!

jxug.connpass.com

今回は30名の方々にご参加いただきました。

f:id:hiro128:20180219145241j:plain

メンターにも強力な方に来ていただき非常に助かりました。この場をお借りして御礼申し上げます。本当にありがとうございました。

Androidの部は講師を@mishi_csさんがご担当されました。以下のレポートを参照ください。

rksoftware.hatenablog.com

私はiOSの部を担当しました。毎度のことながら躓きが多かったのが「実機デバッグの環境構築」でした。

今回は、

  • キーチェーンアクセスのパスワードがログインパスワードと違っており、しかもかからなくなってしまっているため、再度設定を行う必要があった。
  • 原因不明でビルドできなかったが、実機を抜き差しすることでうまくいった

など、のトラブルが発生しました。両者とも、Xamarin.iOSを触ってみた場合には自力解決が難しいものでしたので、ハンズオンで体験、解決できたのはよかったです。


いつも通り、コーディングではあまり躓きは少なかった印象ですが、「難易度が高い」との感想を持たれた方が多かったようです。

アンケート結果

ハンズオンを最後まで完了できたか

f:id:hiro128:20180219145057p:plain


今回、iOSでは全員の方がアプリ起動を確認できましたが、全体ではうまく動かなかった方がいらっしゃいました。
今後も全員がアプリを動かせるようにサポートしていきます。

難易度

f:id:hiro128:20180219145209p:plain


難易度についてですが、67%の方が「簡単」「ちょうどいい」とご回答され、28%の方が「難しい」とご回答されました。


割合としては、前回、前々回と同様の状況です。


確かにちょっと難しいですが、習得する価値がある内容ですので、今後もなるべくわかりやすくご説明できるよう改善していきますが、レベル感としては現状を維持したいと考えています。


時間

f:id:hiro128:20180219145222p:plain


時間ですが、94%以上の方が「ちょうどいい」とご回答されましたので、ボリューム的には今のままを続けたいと考えております。

ハンズオン自体は、休憩などを省くと正味3時間程度でした。集中力的にも3時間程度がちょうどいい長さだと考えております。


役に立ったか

f:id:hiro128:20180219145035p:plain


なんと94%の方に「役に立った」とご回答を頂けました!
主催者としては非常にうれしい結果となりました!
今後全員の方に「役に立った」と感じていただけるよう努力していきます。



その他のご感想

その他のご感想としては、

  • Xamarin.Androidは比較的簡単だが、Xamarin.iOSはSwiftの知識が必要で、ちょっと難しい

というご意見を挙げられた方が多かったです。
これは確かにその通りで、Xamarin.iOSの方がハマりどころやApple独自のエコシステムなどの面でもハードルが高いため、ハンズオンで一度ハマりを経験することがお役に立つのではないかと考えております。


また、

  • 独学でやるより全然テンポよく学習できた

というご意見もいただきました。

ハンズオンの目的がまさに「これ」ですので、主催者としては大変嬉しいご感想でした。

皆様のご意見を参考に今後も有意義なハンズオンを開催できるように精進いたします。



最後にお忙しい中休日にお時間を作ってご参加頂いた皆様、本当にありがとうございました!



懇親会はAzureもくもく会さまと合同で行い、とても楽しい時間を過ごせました!!



また、JXUGのイベントでお会いできるのを楽しみにしております!

Visual Studio for Mac で iOSの実機UIテストを実行する(1) テストプロジェクトの作成・実行

はじめに

こんにちは、@hiro128_777です。

2月10日(土)に、品川でXamarin.iOS 、Xamarin.Androidのハンズオンを開催いたします!

Swift, Objective-C のコードを Xamarin.iOS に移植する際のポイントについてのハンズオンまたは、java のコードを Xamarin.Android に移植する際のポイントについてのハンズオンを選んで受講できますので、ご興味がある方はぜひご参加下さい!

jxug.connpass.com



では本題に入りましょう。


テストプロジェクトの作成


iOSの実機UIテストを実行するために、まずは、テストプロジェクトを作成します。

今回は私のハンズオン用サンプル「AVCamSample」を題材にします。
ソースは以下から入手できます。

github.com


ソリューションの右クリックメニューから、追加 -> 新しいプロジェクトを追加 を選択します。

f:id:hiro128:20180131212524p:plain


テンプレートから「UIテストアプリ」を選択し、「次へ」をクリックします。

f:id:hiro128:20180131212542p:plain


テストアプリの名前を「AVCamSample.UITest」とし、「作成」をクリックします。

f:id:hiro128:20180131212557p:plain



パッケージのアップデート


Xamarin.UITest パッケージを最新版にアップデートします。
NUnitはバージョン2系に依存しているようなのでアップデートしないでください。

f:id:hiro128:20180131212615p:plain


Test.csの作成

Test.csのコードを以下のように書き換えてください。

using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using Xamarin.UITest;
using Xamarin.UITest.iOS;
using Xamarin.UITest.Queries;

namespace AVCamSample.UITest
{
    [TestFixture]
    public class Tests
    {
        iOSApp app;

        [SetUp]
        public void BeforeEachTest()
        {
            app = ConfigureApp
                .iOS
                .EnableLocalScreenshots()
                .PreferIdeSettings()
                .InstalledApp("com.hiro128777.AVCamSample")// アプリのバンドル識別子
                .StartApp();
        }

        [Test]
        public void AppLaunches()
        {
            app.Screenshot("First screen.");
        }
    }
}


この時、下記のように「パッケージが見つからない」扱いになり、赤線が出るようであれば、

f:id:hiro128:20180131212631p:plain


一度ソリューションを閉じて開き直すと直ります。

f:id:hiro128:20180131212703p:plain


これで、テストプロジェクトが完成しました。


アプリ本体のプロジェクトに Xamarin.TestCloud.Agent パッケージを追加

アプリ本体のプロジェクトのパッケージの右クリックメニューから、「パッケージの追加」をクリックします。

f:id:hiro128:20180206143550p:plain


「TestCloud」で検索して、Xamarin.TestCloud.Agent パッケージを追加します。

f:id:hiro128:20180206143608p:plain


FinishedLaunchingメソッドにXamarin.TestCloud.Agentを起動するコードを追加します。

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
	// このコードを追加します
	#if ENABLE_TEST_CLOUD
	Xamarin.Calabash.Start();
	#endif
	// ここまで

	Window = new UIWindow(UIScreen.MainScreen.Bounds);

	var controller = new CameraViewController();
	var navController = new UINavigationController(controller);

	Window.RootViewController = navController;
	Window.MakeKeyAndVisible();
	Window.TintColor = UIColor.FromRGBA(1.0f, 1.0f, 0.0f, 1.0f);

	return true;
}

実機での起動を確認する

まずはテストプロジェクトを一度ビルドします。

単体テストのペインの「アプリのテスト」を右クリックし、「Add App Project」をクリックします。

f:id:hiro128:20180206143757p:plain


「AvCamSample」にチェックを入れ、「OK」をクリックします。

f:id:hiro128:20180206143820p:plain


ターゲットのデバイスに自分のiPhoneが表示されればOKです。

f:id:hiro128:20180206143833p:plain


これで実機テスト実行の準備が整いましたので、一度テストを走らせてみましょう。

「AvCamSample.UITest」 を右クリックし、「テストの実行」を選択します。

f:id:hiro128:20180206143843p:plain


テストが開始します。オールグリーンになればテスト成功です。

f:id:hiro128:20180206143935p:plain


成功すると、以下のようにスクリーンショットが撮れています。

f:id:hiro128:20180206144020p:plain


これで、実機テストが実行できるようになりました。



次回は実際のテストコードを記述してテストを作成していきます。

今回はここまでです。

Visual Studio for Mac に Apple ID でログインする

はじめに

こんにちは、@hiro128_777です。

2月10日(土)に、品川でXamarin.iOS 、Xamarin.Androidのハンズオンを開催いたします!

Swift, Objective-C のコードを Xamarin.iOS に移植する際のポイントについてのハンズオンまたは、java のコードを Xamarin.Android に移植する際のポイントについてのハンズオンを選んで受講できますので、ご興味がある方はぜひご参加下さい!

jxug.connpass.com



では本題に入りましょう。

Visual Studio for Mac でApple IDでログインする方法


Visual Studio for MacでiOSプロジェクトのinfo.plistを開くと「サインイン」ボタンがあります。

このボタンを押せば Apple ID でログインできるみたいなので試してみました。

「サインイン」ボタンをクリックします。

f:id:hiro128:20180130201034p:plain


「+」ボタンをクリックします。

f:id:hiro128:20180130201110p:plain


fastlaneをインストールしなさいと言われるのでインストールします。

f:id:hiro128:20180130201144p:plain


fastlaneのインストール


以下よりfastlaneをダウンロードして下さい。

https://download.fastlane.toolsdownload.fastlane.tools


「install」を実行します。

f:id:hiro128:20180130201416p:plain


「開発元が未確認のため開けません」と言われるので、

f:id:hiro128:20180130201430p:plain


システム環境設定のセキュリティとプライバシーを開き「このまま開く」をクリックします。

f:id:hiro128:20180130201446p:plain

f:id:hiro128:20180130201525p:plain


ターミナルが開いてインストールが始まります。

f:id:hiro128:20180130201551p:plain


まだインストールは続きます。

f:id:hiro128:20180130201539p:plain

すべて完了したら[プロセスが完了しました]と表示されるのでターミナルを閉じます。

これでインストールは完了です。

fastlaneの設定

インストール終了後.bash_profileにパスを書きます。

まず、.bash_profileが存在するかどうか確認します。

ls -la


存在しない場合、ファイル作成します。

touch .bash_profile


作成できたか確認しましょう

ls -la

f:id:hiro128:20180130201655p:plain


.bash_profileを開きます。

open ~/.bash_profile


テキストエディタが開くので下記を記述します。

export PATH="$HOME/.fastlane/bin:$PATH"


設定を反映させます。

source ~/.bash_profile


以上でfastlaneの設定が完了しました。

念のため、パスを調べてみましょう。

which fastlane

f:id:hiro128:20180130201741p:plain


正しくインストールパスが表示されれば成功です。

Apple ID でログインする


再度 Apple ID でログインします。

f:id:hiro128:20180130201836p:plain


パスワードを聞かれるので入力します。

f:id:hiro128:20180130202049p:plain


ところがサインイン完了しても何も起こりませんでした‥

試しにもういちどサインインしたら正常に表示されました。このあたりまだ不安定なのでしょうか。

f:id:hiro128:20180130202136p:plain


「詳細の表示」をクリックすると証明書、プロビジョニングプロファイル も認識されています。

f:id:hiro128:20180130210427p:plain


以上で、Visual Studio for Mac での Apple ID でのログインが完了しました。

これで、Visual Studio for Macでプロビジョニングプロファイルの設定ができます。

今回は以上です。

12月9日(土)に、大阪でXamarin.iOS のハンズオンを開催いたしました

こんにちは、@hiro128_777です。

12月9日(土)に、大阪でXamarin.iOS のハンズオンを開催いたしました!

jxug.connpass.com

今回は24名の方々にご参加いただきました。

メンター陣も東京開催に負けない強力な方に多数ご協力頂き非常に助かりました。この場をお借りして御礼申し上げます。本当にありがとうございました。

今回はiOSに特化したハンズオンでしたが、毎度のことながら躓きが多かったのが「実機デバッグの環境構築」でした。

今回は、

  • Xamarin.iOS とXcodeのバージョンが揃っていなくてビルドできない
  • 原因不明でビルドできなかったが、実機を抜き差しすることでうまくいった

など、原因はいろいろありましたが、なかなか初めてXamarin.iOSを触ってみた場合には解決が難しい内容が多かったので、ハンズオンで体験、解決できたのはよかったです。


いつも通りにコーディングではあまり躓きは少なかった印象です。

アンケート結果

ハンズオンを最後まで完了できたか

f:id:hiro128:20171214141021p:plain


今回、仕事の都合で環境を変更できず、ビルドできない方、Xamarin.iOS とXcodeのバージョンが揃っていないためバージョンアップに時間がかかり、再度までたどり着けなかった方がいらっしゃいました。


これについてはハンズオンの募集の時点で、推奨バージョンを指定することで、会場でのアップデートなどが発生しないように改善したいです。


難易度

f:id:hiro128:20171214141041p:plain


難易度についてですが、60%の方が「簡単」「ちょうどいい」とご回答され、40%の方が「難しい」とご回答されました。


Xamarin.iOSのハンズオンは題材的には多少難易度が高めですので、妥当な結果となりました。


確かにちょっと難しいですが、習得する価値がある内容ですので、今後も、実施していきたいと考えています。


時間

f:id:hiro128:20171214141116p:plain


時間ですが、85%以上の方が「ちょうどいい」とご回答されました。残りの方も「短い」とご回答いただいております。


ハンズオン自体は、休憩などを省くと正味3時間程度でした。集中力的にも3時間程度がちょうどいい長さだと感じました。短いという感想も目立ちましたので、今後はもう少し細かくご説明したいと感じました。


役に立ったか

f:id:hiro128:20171214141155p:plain


なんと93%の方に「役に立った」とご回答を頂けました!
主催者としては非常にうれしい結果となりました!



その他のご感想

その他のご感想としては、とにかく

  • もっと大阪でも開催してほしい

というご意見を挙げられた方が多かったです。
本当に切望されているのがわかりましたので、ご要望にお応えできるよう精進します!

また、

  • Webや本では分からないような勘所等が知れて良かった

というご意見もいただきました。

ハンズオンの目的がまさに「これ」ですので、主催者としては大変嬉しいご感想でした。

皆様のご意見を参考に今後も有意義なハンズオンを開催できるように精進いたします。

最後にお忙しい中休日にお時間を作ってご参加頂いた皆様、本当にありがとうございました!

大歓迎いただき懇親会も大盛り上がりで、とても楽しい時間を過ごせました!!

また、JXUGのイベントでお会いできるのを楽しみにしております!

Xamarin 今そこにある危機

はじめに


こんにちは、@hiro128_777です。


この記事は「Xamarin その1 Advent Calendar 2017」の14日目になります。


まず、はじめにお断りさせてください、今回テクニカルな内容は全くございません。


私はXamarinが大好きです。今更述べるまでもないですが、Xamarinにはたくさんの魅力があります。そして、もっともっと普及してほしいと思っています。
ですが、残念がら良いものが必ず普及するとは限らないのが世の中の常です。私は開発者なので私が感じるXamarinの魅力はあくまでも「開発者として感じる魅力」であると言えます。


そんな大好きなXamarinでも一歩引いてみると、その置かれている状況は決して楽観視できないと危機感を感じています。


そこで今回はその「楽観視できない状況」をXamarinが大好きな皆さまと共有することで現状を打開するためにこのような記事を書きました。


具体的に何が「楽観視できない状況」なの?


私は特に以下の3つの状況を「楽観視できない」と感じています

  • Microsoftが提供してる主力製品のアプリがそもそもXamarin製のものが少ない!
  • 若年層への浸透が薄い!
  • 自社開発時とは相性が良いが、開発会社への委託とは相性が悪い!

Microsoftが提供してる主力製品のアプリがそもそもXamarin製のものが少ない


Microsoftが提供しているOutlookやTeamsなどの主力製品のアプリ自体が現状Xamarin製ではありません。主力製品ではないものにはXamarin製のアプリもあります。例えば、Microsoft PixはXamarin製です。


つまり開発環境の提供は行なっていても、自社での製品への利用はあまり進んでいません。これは、単にXamarin買収のタイミングの問題かもしれませんが、シンプルに「なんで??」と疑問に思います。


この状況こそがXamarinの問題を如実に表しています。つまり、Xamarinはまだ主力製品に食い込む程の地位は得ていないのが現実です。


では、Xamarinが主力製品に食い込めないのはなぜでしょうか。真の理由は私にはわかりませんが、まだまだ普及率が低いのは大きな問題だと考えています。とにかく、普及率を上げていく必要があります。


そして普及率を上げようとすると次の問題が出てきます。


若年層への浸透が薄い


これは、勉強会に参加するとよく分かります。勉強会の参加される方々も30代以上の方が多く、20代の方は少ない状況です。(そもそも私自身がオッサンです。失礼しました。)ではなぜ若年層への浸透が薄いのでしょう。その理由も考えてみました。

未経験者がアプリ開発を始める際の第一の選択肢にならない


例えば、プログラム未経験の学生さんがスマートフォンのアプリ開発を行おうと思い情報を調べた時には、まずはネイティブの開発の情報を目にする可能性が高く、当然ながらネイティブ開発を第一の選択肢に考えます。その時点でXamarinというワードを目にしても、それがスマートフォンのアプリ開発のプラットフォームだとは気づかないか、気づいても面倒くさそうなのでスルーする可能性が高いでしょう。当然、そのままネイティブで開発を始める可能性が高いと言えます。


その後、経験を積んだ後にXamarinを知りそのメリットに興味を持ったとしても、さらに学習コストを支払ってXamarinに手を出す方は少数派でしょう。
次のタイミングとしては、会社から「Xamarinを調査しなさい」、「Xamarinを覚えなさい」と言われたタイミングが多いと言えます。勉強会でもそういうお話はよく伺います。多数派の方々がXamarinに手を出すとしたらこのタイミングです。よって、ここまで来ないとXamarinの利用者は増えないということになります。


専門学校での採用が少ない。


プログラマーを職業として選ぶ方々には専門学校で学ぶ方も多くいらっしゃいます。毎年毎年、たくさんの方々が専門学校を卒業しプログラマーとして働き始めるわけですから、業界における影響は小さくありません。ところが、まだまだ企業ではネイティブ開発が多数派のため、入学当初から就職を視野に入れる専門学校では、Xamarinは標準の開発プラットフォームとして利用されにくい状況にあります。もちろん、先生たちはクロスプラットフォームの重要性を理解しており、チャレンジすべきであると考えている先生方もたくさんいらっしゃいますが(実際、そういうお話も聞きました)、2年間という短い期間でネイティブ開発を習得した上の追加の技術として習得してもらうには指導者も少なくなかなか困難です。


また、専門学校はオープンキャンパスなどで生徒さんを募りますが、 その際に高校の生徒さんやその親御さんたちにアピールする際も「Xamarinを使ったクロスプラットフォーム開発を指導しています」と言ってもその時点で生徒さんや親御さんがクロスプラットフォームの知識が十分にある可能性は低いため、ネイティブ開発を前面に出した方が圧倒的にアピール度は高いでしょう。


よって、現状どうしても専門学校では、ネイティブの開発が基本になるのではないでしょうか。


自社開発とは相性が良いが、開発会社への一括委託とは相性が悪い


まず、クロスプラットフォーム開発の初期コストは個別開発と比べて半額になるようなことはなく、結果として費用負担をする方が期待するほどは大きくは変わらないため、費用面のメリットだけを期待すると肩透かしをくらってしまうという弱点があります。


効果的にクロスプラットフォーム開発を行うということは対象のプラットフォーム全てのUXやAPIを理解した上で開発する必要があり、設計コストが非常に大きくなります。実装時にもプラットフォームごとの違いを考慮し共通化するという細かい配慮が必要となるため結果として初期コストは意外と下がりません。


それでも自社開発であれば、初期リリースを小さくすることで初期コストを抑えるなど色々工夫できるのですが、開発会社への一括委託でウォーターフォールで開発するようなケースでは全機能を一括開発する事も多いです。そうすると、開発コストは個別開発と大きく変わらない状況になりますが、開発会社への委託の場合には、Xamarin導入の動機には「共有化によるコストダウン」が掲げられている事も多く、「メリットが少ない」と判断されてしまうリスクが高くなってしまいます。


一方で、改修コストはかなり下がります。個別開発では、設計時に考慮はするもののコードによる縛りがないためどうしても実装の違いが大きくなるリスクが高いです。それにより改修時に影響範囲が大きくなり、想定外のコストが発生する危険性が高くなります。クロスプラットフォーム開発ではロジック部分であればそこはコード共有化で保証され、リスクは明らかに少なくなります。UI部分でもViewModelまでを基本的に共有化するため、実装の違いは小さく抑えられます。実装の違いが小さいということは、当然リリースまでのスピード面でも、優位性があります。


つまりライフサイクル全体のコストで考えればメリットは十分に享受でき、Xamarinは有力な選択肢となりますが、開発会社への一括委託ではイニシャルコストでは大きな差が出にくいため、その時点でXamarinを選択する動機が薄くなってしまうのも事実です。Xamarinを選ぶ企業は目先だけではなくしっかりライフサイクル全体で判断しているのでしょう。


そいういう意味でXamarinは日本のSI業界の商習慣との相性が悪いのです。もっと正確に言えば、これはXamarinに限ったことではありませんが、日本のSI業界の商習慣が世界基準の開発ツールの進化から取り残されているのです。とは言うものの、エンタープライズ業界での採用が進まなければ普及率は上がりませんので、ここも非常に悩ましいところです。

では、どうしたらいいのか?


極々当たり前のお話になってしまいますが、何よりもとにかく初めてモバイル開発に触れる時点での選択肢にXamarinが入るようにすることが何よりも重要だと思っています。


それには専門学校などの授業のカリキュラムにXamarinが取り入れられる必要があります。それには企業での導入が進み、企業からの希望人材のスキルセットにXamarinが入る必要があります。ですが、それを待っていたらきっと時間切れになってしまいます。よって、まずは学校に普及するように働きかけた上で、それによってさらに企業での導入が進むようにしなければいけないでしょう。それには学校に対してこちらからアプローチをかけていくしかありませんが、なかなか簡単にはいきません。


もし、この記事を学校のご関係者の方々がご覧になっていましたら、是非、一度学校でのXamarinのハンズオンをご検討していただけませんでしょうか。


私はコミュニティ活動として無償での学校様でのハンズオンも行なっておりますので、ご興味あればtwitterでメッセージいただければご対応させていただきます。


Xamarinに取り組むということは強制的にクロスプラットフォームでアプリを考えなくてはならなくなりますので、自然とクロスプラットフォーム開発の様々なスキルが身につきます。これは、個別プラットフォーム開発を続ける限りなかなか身につかない貴重なスキルであり、必ず企業からも歓迎されるスキルです。



最後に

とりとめもなく色々書いてしましましたが、とにかくXamarinをもっともっと普及させていきたいです!
そのためにはこの記事をご覧いただいた皆様のご協力が不可欠です。よろしくお願いいたします!
私もできる限りのことをやっていきます!!


それでは明日は@himarin269さんです。よろしくお願いします!

11月10日(金)に、日本電子専門学校さんで、特別授業として、Xamarin.iOS, Xamarin.Android のハンズオンを開催いたしました!

こんにちは、@hiro128_777です。

11月10日(金)に、日本電子専門学校さんで、特別授業として、Xamarin.iOS, Xamarin.Android のハンズオンを開催いたしました!

26名の方々にご参加いただきました。

そして、日本電子専門学校の先生方にも多大なご協力を頂きました事、この場をお借りして御礼申し上げます。本当にありがとうございました。

また、メンターを勤めていただいた@mishi_csさん、ありがとうございました。

今回は全員 Mac でハンズオンを行いましたが、毎度の事ながら、躓きが多かったのが「環境構築」でした。

その他の躓きどころとしては、XAMLを手書きしたのでXAMLのシンタックスエラーが多く発生しましたが、コンパイラが指摘してくれないので、間違いを探すのにみなさん苦労したようです。


f:id:hiro128:20171110094233j:plain

学生さんへのXamarinの認知度

ハンズオン開始前に、「Xamarinを知って入る方はいらっしゃいますか?」とご質問したところ、なんと、知っていた方は誰もいませんでした‥

学校でネイティブ開発を学んでいらっしゃる学生さんへのXamarinの認知度はまだまだ低いことを痛感しました。

アンケート結果

難易度

f:id:hiro128:20171127191339p:plain

難易度についてですが、約76%の方が「ちょうどいい」とご回答され、約8%の方が「難しい」とご回答されました。

今回は約92%の方から「簡単」または「ちょうどいい」とご回答を頂けましたので、Xamarinが非常にわかりやすい開発環境であることが実証された結果となりました。


時間

f:id:hiro128:20171127191401p:plain

時間ですが、60%の方が「ちょうどいい」とご回答されました。36%の方が「長い」とご回答されました。

全員の環境構築を完了させるのに2時間程度かかりましたので、ハンズオン自体は、正味3時間程度でした。合計5時間だとやはり少し長く感じてしまうので、環境構築をもう少し早く完了できるように工夫したいです。

Xamarinに興味が持てましたか

f:id:hiro128:20171127191413p:plain

64%の方に「興味が出た」とご回答を頂けました!
20%の方が「興味が出なかった」とご回答しました。

まずは64%の方にXamarinに興味を持っていただけたのは、ハンズオンの主催者としては嬉しい限りです。

Xamarinを今後使ってみたいですか

f:id:hiro128:20171127191424p:plain

52%の方に「今後使ってみたい」とご回答を頂けました。
20%の方が「今後使いたくない」とご回答しました。
半数以上の方に今後Xamarinを使ってみたい!とご回答いただけたことは、Xamarin が普段、ネイティブ開発をされている方にも、十分訴求できるものであることがわかりました。


その他のご感想

その他のご感想としては、

  • 今後も触れてみたい
  • 環境構築は大変だが、コード自体は非常に簡単に書ける

というようなご意見が挙がりました。

今回のハンズオンのテーマとしては、学生さんのような「若い層へのXamarinの普及率を上げること」でしたので、小さな一歩ではありますが、成果をあげられたと感じております。

もし、このブログをご覧になって「うちの学校でもハンズオンをやってほしい!」という方がいらっしゃいましたら、ご連絡いただければ、日本全国どこでも行きますので、遠慮なくダイレクトメッセージお願いします!

皆様のご意見を参考に今後も有意義なハンズオンを開催できるように精進いたします。

そして今後も Xamarin の普及に努めていきます!

Swift, Objective-C を Xamarin.iOS に移植する際のポイント(4) storyboard の制約の Xamarin.iOS C#コードへの移植方法

はじめに

こんにちは、@hiro128_777です。

12月9日(土)に、大阪でXamarin.iOS のハンズオンを開催いたします!

Xcode での開発経験がない方が、iOS の開発を Xamarin で始めてWebで情報を集めると、 Swift や Objective-C の情報はたくさん見つかりますが、Xamarin の情報は案外少ないことに気づきます。
そして、Swift や Objective-C のサンプルコードを見て、Xamarin に移植する必要が出てきますが、これは Xcode での開発経験がないと結構骨が折れる作業です。
そこで今回、Swift, Objective-C のコードを Xamarin.iOS に移植する際のポイントについてハンズオンを行うことにいたしましたので、ご興味がある方はぜひご参加下さい!

jxug.connpass.com


前回は、storyboard のUIエレメントの C#コードへの移植方についてご説明しました。

hiro128.hatenablog.jp

そこで、今回は、UIエレメントよりもさらに情報の少ない storyboard の制約のC#コードへの移植方法についてご説明します。

今回もApple公式の写真撮影のサンプルアプリを題材にします。

以下よりサンプルコードをダウンロードして下さい。
developer.apple.com

その中の、Main.storyboardファイルのコードを見てみましょう。

では早速移植していきましょう。

制約の移植

個別のUIエレメント内で完結する制約はUIエレメントを生成する箇所に記載していますので、ここでは、複数のUIエレメントの関係性の制約を移植します。

複数のUIエレメントの関係性の制約はMain.storyboardの161行目~188行目に記述されています。

1つ目の制約を見てみましょう。

<constraint firstItem="3eR-Rn-XpZ" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="125-kC-WZF"/>

firstItem, secondItemにそれぞれ文字列が入っていますが、これはそれぞれ特定のUIエレメントを指し示しています。

firstItem3eR-Rn-XpZを検索すると、20行目に、id="3eR-Rn-XpZ"とあります。

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3eR-Rn-XpZ" userLabel="Preview" customClass="PreviewView" customModule="AVCam" customModuleProvider="target">

よって3eR-Rn-XpZPreviewViewを指し示しています。

同様にsecondItemnyU-fN-aJhを検索すると、189行目に、id="nyU-fN-aJh"とあります。

<viewLayoutGuide key="safeArea" id="nyU-fN-aJh"/>

safeAreaとはiPhone Xを考慮した上下左右のマージンを取った領域です。今回はiOS10対応の移植なので、centerXつまり、左右の中心点を考える上では、Viewと同じ領域と考えて差し支えありません。

よってidをUIエレメントに置き換えて記述すると、以下のようになります。

C#

View.AddConstraint(NSLayoutConstraint.Create(PreviewView, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0));



同様にその他の制約を移植すると以下のようになります。
※一部制約変更しています。



元のstoryboardの制約

<constraint firstItem="eI6-gV-W7d" firstAttribute="top" secondItem="9i1-NX-Qxg" secondAttribute="bottom" constant="8" id="6iA-0j-auu"/> /* iOS10対応のため変更あり */
<constraint firstItem="eI6-gV-W7d" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="ACB-oH-2jU"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="height" secondItem="eRT-dK-6dM" secondAttribute="height" id="AEV-ew-H4g"/>
<constraint firstItem="Pii-2r-R2l" firstAttribute="top" secondItem="eI6-gV-W7d" secondAttribute="bottom" constant="8" id="B43-ME-uK5"/>
<constraint firstItem="3eR-Rn-XpZ" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" id="Ice-47-M9N"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="top" secondItem="rUJ-G6-RPv" secondAttribute="top" id="NFm-e8-abT"/>
<constraint firstItem="FZr-Ip-7WL" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="OaZ-uO-vXY"/>
<constraint firstItem="FAC-co-10c" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="Oow-A6-mDp"/>
<constraint firstItem="9i1-NX-Qxg" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" constant="8" id="PNv-qh-VmU"/> /* 削除 */
<constraint firstItem="zf0-db-esM" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="Ris-mI-8lA"/>
<constraint firstItem="Pii-2r-R2l" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="SXi-MU-H9D"/>
<constraint firstItem="zf0-db-esM" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="W6q-xJ-jfF"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="height" secondItem="rUJ-G6-RPv" secondAttribute="height" id="aQi-F7-E2b"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="top" secondItem="FAC-co-10c" secondAttribute="bottom" constant="20" id="aSR-Je-0lW"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="top" secondItem="eRT-dK-6dM" secondAttribute="top" id="bQd-ro-0Hw"/>
<constraint firstItem="nyU-fN-aJh" firstAttribute="bottom" secondItem="uCj-6P-mHF" secondAttribute="bottom" constant="20" id="eWs-co-Aaz"/>
<constraint firstItem="3eR-Rn-XpZ" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="igk-MQ-CGt"/>
<constraint firstItem="rUJ-G6-RPv" firstAttribute="leading" secondItem="uCj-6P-mHF" secondAttribute="trailing" constant="20" id="lsk-Hm-rTd"/>
<constraint firstItem="nyU-fN-aJh" firstAttribute="centerX" secondItem="uCj-6P-mHF" secondAttribute="centerX" id="m8a-cF-Rf0"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="width" secondItem="rUJ-G6-RPv" secondAttribute="width" id="o8j-gw-35B"/>
<constraint firstItem="3eR-Rn-XpZ" firstAttribute="width" secondItem="8bC-Xf-vdC" secondAttribute="width" id="pSC-xP-dl0"/>
<constraint firstItem="uCj-6P-mHF" firstAttribute="width" secondItem="eRT-dK-6dM" secondAttribute="width" id="s8u-Y8-n27"/>
<constraint firstItem="FZr-Ip-7WL" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="sTY-i6-czN"/>
<constraint firstItem="9i1-NX-Qxg" firstAttribute="centerX" secondItem="nyU-fN-aJh" secondAttribute="centerX" id="wWj-VD-34F"/> /* 削除 */
<constraint firstItem="uCj-6P-mHF" firstAttribute="leading" secondItem="eRT-dK-6dM" secondAttribute="trailing" constant="20" id="zwj-TX-t6O"/>


移植後のC#の制約

View.AddConstraint(NSLayoutConstraint.Create(LivePhotoModeButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, View, NSLayoutAttribute.Top, 1.0f, 80f));// iOS10対応のため変更あり
View.AddConstraint(NSLayoutConstraint.Create(LivePhotoModeButton, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Height, NSLayoutRelation.Equal, RecordButton, NSLayoutAttribute.Height, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(CapturingLivePhotoLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, LivePhotoModeButton, NSLayoutAttribute.Bottom, 1.0f, 8.0f));
View.AddConstraint(NSLayoutConstraint.Create(PreviewView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, View, NSLayoutAttribute.Height, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, CameraButton, NSLayoutAttribute.Top, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(ResumeButton, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(CaptureModeControl, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(CameraUnavailableLabel, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterY, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(CapturingLivePhotoLabel, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0));
View.AddConstraint(NSLayoutConstraint.Create(CameraUnavailableLabel, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1.0f, 0));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Height, NSLayoutRelation.Equal, CameraButton, NSLayoutAttribute.Height, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, CaptureModeControl, NSLayoutAttribute.Bottom, 1.0f, 20f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, RecordButton, NSLayoutAttribute.Top, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(View, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, PhotoButton, NSLayoutAttribute.Bottom, 1.0f, 20f));
View.AddConstraint(NSLayoutConstraint.Create(PreviewView, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterY, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(CameraButton, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, PhotoButton, NSLayoutAttribute.Trailing, 1.0f, 20f));
View.AddConstraint(NSLayoutConstraint.Create(View, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, PhotoButton, NSLayoutAttribute.CenterX, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Width, NSLayoutRelation.Equal, RecordButton, NSLayoutAttribute.Width, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PreviewView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, View, NSLayoutAttribute.Width, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Width, NSLayoutRelation.Equal, RecordButton, NSLayoutAttribute.Width, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(ResumeButton, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterY, 1.0f, 0f));
View.AddConstraint(NSLayoutConstraint.Create(PhotoButton, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, RecordButton, NSLayoutAttribute.Trailing, 1.0f, 20f));

これで制約の移植が完了しました。

今回はここまでです。