すまべん特別編「Xamarin2.0であそぼう」@関東でお話ししました

もう先々週になってしまいますが、4/19(土) に1年ぶりの関東でのすまべんを開催しました。 すまべん特別編は、通常開催のすまべんとは違い、特定領域にフォーカスした開催ということで、Xamarinにフォーカスしたイベントとなりました。

国内の Xamarin 界隈では情報発信量はんぱないあめい(@amay077)さんと、中の人でもある id:atsushieno さんにお話しいただきました。ありがとうございました。あと、ガチとネタがええ感じに混じり合うカオス感あふれるLTもすまべん関東らしい感じですごく楽しかった!

そして僕は、実際に Xamarin をチームに導入したときの話をしました。*1

*1:わりとえらそうに書いちゃってますが、本当は僕もいろいろデクったりして、みんなにすごい助けてもらってました...。

続きを読む

Xamarin Evolve 2014 にいきます!

f:id:iseebi:20140429191016p:plain

今年は何か特別な体験がしたいと思って、10月にアトランタで開催される Xamarin Evolve 2014 に行くことにしました。もう飛行機のチケットもホテルも確保しちゃってます。

Xamarin Evolve は、Xamarin の大きなカンファレンスイベントで、昨年に引き続き開催されることになりました。まあ、感覚的には WWDC とか Google I/O 的な感じですね。

チケットが他のイベントと比較しても超お高くて、6日から10日まで通しで参加すると2499ドル、前半のトレーニングをなしにして、8日からのカンファレンスだけにすると1799ドル。飛行機のチケットで13万くらいだったので、いろいろ込みにしたら50万近く吹っ飛ぶんじゃないかなあ...(汗

旅程は、カンファレンスのみにして、こんな感じ。

続きを読む

MvvmCrossのServiceを使って共通オブジェクトを作る

MvvmCrossには IoCコンテナ機能が備わっており、アプリ内で使う共有オブジェクトを自動的に管理してくれるようになっています。

主な仕組みとして、Serviceというものが用意されており、決まった名前でオブジェクトを定義すると、自動的に読み込まれるようになっています。また、プラグインで提供される各種オブジェクトも、IoCコンテナを経由して取得します。

本稿では、IoCコンテナの基本的な使い方を紹介します。なお、Hot Tuna Starter Packが導入されたプロジェクトが準備されているという想定です。

IoCコンテナに登録されるオブジェクト(Service)を作る

CoreプロジェクトにServicesフォルダを作り、その中に最後が「Service」で終わるインターフェイスと、それを実装するクラスを用意します。

SampleService

using System;
using Cirrious.CrossCore;

namespace CrossSample.Core.Services
{
    /// <summary>
    /// サンプルサービスのインターフェイス
    /// </summary>
    public interface ISampleService
    {
        void SampleMethod(string message);
    }

    /// <summary>
    /// サンプルサービスの実装クラス
    /// </summary>
    public class SampleService : ISampleService
    {
        public void SampleMethod(string message)
        {
            Mvx.TaggedTrace("SampleService", "Sample message: {0}", message);
        }
    }
}

App.cs 内にある、下記のコードが起動時に末尾が「Service」で終わるクラスを探して、IoCコンテナにすべて登録するようになっています。

public override void Initialize()
{
    // この行でServiceで終わるクラスを探して一括登録している
    CreatableTypes()
        .EndingWith("Service")
        .AsInterfaces()
        .RegisterAsLazySingleton();
        
    RegisterAppStart<ViewModels.FirstViewModel>();
}

IoCコンテナ内のオブジェクトをViewModelやServiceで使う

IoCコンテナ内にあるオブジェクトは、アプリ内ではじめて使われる場合にインスタンスが生成され、すでにインスタンスがある場合はそのインスタンスが利用されます。

ViewModelやServiceのコンストラクタに、IoCコンテナに入っているインターフェイスの引数を追加すると、インスタンス生成時にセットされるようになります。

渡された入ってきたインスタンスをプライベートフィールドやプロパティに確保しておいて、そこからアクセスするようにします。

using Cirrious.MvvmCross.ViewModels;
using CrossSample.Core.Services;

namespace CrossSample.Core.ViewModels
{
    public class FirstViewModel : MvxViewModel
    {
        private readonly ISampleService SampleService;

        public FirstViewModel(ISampleService sampleService)
        {
            // 初期化時に自動的に取得して指定されるので、受け取ります。
            SampleService = sampleService;
        }

         void Test()
        {
            SampleService.SampleMethod("Test called");
        }
    }
}

IoCコンテナを使ってオブジェクトを生成する

たとえば、IoCコンテナ以外のモデルオブジェクトで使いたいというときに使います。下記のようにモデルクラスを定義します。

using System;
using CrossSample.Core.Services;

namespace CrossSample.Core.Models
{
    public class LetterItem
    {
        private readonly ISampleService SampleService;

        public LetterItem(ISampleService sampleService)
        {
            SampleService = sampleService;
        }
    }
}

このように作ったクラスは、Cirrious.CrossCore.Mvx.IoCConstruct<T>() でオブジェクトを作成した際に、ViewModelやServiceと同じようにコンストラクタインスタンスが渡されるようになります。

// using Cirrious.CrossCore;
var item = Mvx.IoCConstruct<LetterItem>();

IoCコンテナ内のオブジェクトをその場で解決する

また、Mvx.Resolve<T>()を使って直接依存を解決する方法もあります。ただし、Singleton的になってあんまりよろしくないので、最後の手段としたほうがいいです。

var sampleService = Mvx.Resolve<ISampleService>();

「ハイブリッドアプリの習作」を勝手に補足

朝、TL で流れてきた ハイブリッドアプリの習作(DHJJ [Hatsune's Journal Japan] blog) というエントリをみて、手始めというところでは程よい題材かなと思うのですが、何点か推奨されない点があるので勝手に補足しようと思います。

Resources フォルダにコードを突っ込んではいけない

"Resources\Layoutの中に、いわゆるViewが入ります。形式はAXMLというやつでXAMLよりも正直しょぼいです。 Activity1.csが画面に対するコードビハインドを記述しているところになります。 なんとなくしっくりこないので、ちょっと名前を変えてみましょう。ついでに場所なんかも変えてみたりして。"

下記は上記センテンスにあった画像の、再現画像です。

f:id:iseebi:20140304143351p:plain

「なんとなくしっくりこない」ということで、Resources/Layout フォルダに .cs ファイルを移動してしまってますが、Assets フォルダや Resources フォルダ以下のフォルダは Android では特別な意味を持っています。 このフォルダに一定のルールで配置されているファイルを、リソースとしてビルドしていくということになっています。

また、ただ Layout 1つだけがあるわけではなく、Qualifier というものをつけることによって、環境によって使用されるリソースを切り替えるという仕組みもあります。 この仕組みについて詳しくは Android 公式リファレンス Providing Resources を参照してください。 Qualifier で解像度を加えると、下記のようになります。

f:id:iseebi:20140304143432p:plain

これだけでもすでに、意味合い的にはだいぶずれてきたというのはおわかりいただけるでしょうか。

なお、Java ではこのようなことをするとビルドエラーとなってしまいます。@atsushieno さんによると、Xamarin では、ビルドアクションの設定がきちんとされていればエラーにはならないそうです。しかしながら、意図せずソースコードがリソースに混入して流出するという事件が容易に予想できます。

「事故防止」「混乱防止」のためにも、Resources 以下にはリソースだけを置くこと。「郷に入れば郷に従え」です。

エミュレータは Genymotion を使おう

エミュレータが遅いと表示される」というところで「これは起動時に必ず出てしまうそうなので気にしないのがベストアンサー。」とされていますが、ベストアンサーは Genymotion を使うことです。Xamarin 公式ドキュメントの インストールガイド にも記載されています。

Genymotion は VirtualBox をベースとして動作する高速な Android エミュレータです。

また、このような技術の類似に、公式に提供されている方法として Intel HAXM があります。

ただし、どちらも Windows Phone 8 SDK が入っている環境の場合 Hyper-V とかち合ってしまうため、Hyper-V をオフにして OS を起動する必要があります。この切り替えはブートエントリ編集すればできますので、こちらの記事を参考にしてください。

Android の WebView に関するセキュリティリスク

Android の WebView には重大なセキュリティリスクがあります。自分のアプリだけでなく、他のアプリに対して情報を飛ばす等もできてしまいます。昨年末くらいから今年頭にかけて Android クラスタでは大騒ぎになっていました。

SDK Version 17 未満では、自分で addJavaScriptInterface しなくても、システムが addJavaScriptInterface しているため、JavaScript をオンにするだけでアウトです。このことを留意してJavaScript を有効にしないとか、中に表示される HTML を絶対に安全な物だけにするとか、対策をとっておく必要があります。


Xamarin は C#iOS / Android アプリが書けますが、その下には、Objective-C / Java とかわらない、各プラットフォーム固有のフレームワークがあり、それに伴ったしきたりがあります。それぞれのしきたりを理解するには、各プラットフォームの公式リファレンスだけでなく、Xamarinのリファレンスもよくまとまっていますし、ネイティブ向けに書かれた書籍が数多く出版されている状態なので、読み替えれば情報に困ることはないでしょう。

C# だけを書いてきた人たちも、まずはこういうところからスタートすると、よりよい iOS / Android アプリをかけるでしょう。

Xamarin+MvvmCrossでアプリ開発をはじめる準備 2014年3月版

XamarinでMvvmCrossを使ったアプリの開発をはじめるにあたって、PCLサポートが公式でない上にNuGetアドインが不安定だった時期にプロジェクトを直接編集して無理矢理導入するというパターンが多かったと思います。

しかし、ここ数ヶ月でXamarinでのPCLサポートやNuGetアドインのサポートが改善したことにより、これまでよりも簡単かつ直感的に初期設定ができるようになっています。

本稿では2014年3月時点で、Mac上Xamarin StudioでMvvmCrossを使ったiOS/Androidクロスプラットフォーム開発環境をセットアップする方法をご紹介します。

NuGetのセットアップ

まず、Xamarin StudioからNuGetを使用できるようにします。

Xamarin Studioを起動し、[Xamarin Studio]メニューから[アドインマネージャー]を選択します。

アドインマネージャー

[Gallery]タブの[リポジトリ]ドロップダウンリストから、[Manage Repositoies...]を選択します。

Manage Repositoies...

追加をクリックし、NuGetアドインのリポジトリ http://mrward.github.com/monodevelop-nuget-addin-repository/4.0/main.mrep を追加します。(NuGetアドインの本家ページは https://github.com/mrward/monodevelop-nuget-addin にあります)

リポジトリ追加

NuGet Package Managementが追加されるので、インストールします。

NuGet Package Management

プロジェクトの作成

作成するアプリのプロジェクトを作成します。

まず、共通ロジックとなるCoreプロジェクトを作成します。[ファイル]メニュー[新規]の中にある[ソリューション]を選び、[C#]の[Portable Library]を選択します。

プロジェクト名は、(アプリ名).Core、ソリューション名は(アプリ名)とします。ここではアプリ名をCrossTestAppとしました。 このとき、先にプロジェクト名をセットしてからソリューション名を編集してください。先にソリューション名を編集するとプロジェクト名を編集したときに連動して変更されてしまいます。

ソリューションの作成

引き続き、ソリューションにプロジェクトを追加していきます。ソリューションエクスプローラにある、ソリューションを右クリックし、[追加]の[新しいプロジェクトの追加]を選び、プロジェクト追加します。

スクリーンショット 2014-03-01 2.20.26.png

下記の2プロジェクトを追加します

  • 種類 C# -> Android -> Android Application
  • プロジェクト名 (アプリ名).Droid

Droid

  • 種類 C# -> iOS -> 空のプロジェクト
  • プロジェクト名 (アプリ名).Touch

なお、(アプリ名)の次につけるプロジェクト種類の名前は、MvvmCrossの他の仕組みとあわせて、下記のようにしておくとわかりやすいのでこれに沿うことを推奨します。

追加したプロジェクトの整理

追加したプロジェクト内のファイルはMvvmCrossと競合したり不要となるので調整していきます。

まず、Coreのオプションを表示し、[ビルド]ツリー[一般]を選び、[Current Profile]を[4.5 - Profile78]を選びます。

Profile78

また、Core に追加されているMyClass.csは削除しておきます。

Droidのプロジェクトでは、MvvmCrossのNuGetパッケージがセットアップするフォルダの名称に合わせるために、Resourcesフォルダ内の各フォルダ名を大文字に変更します。このとき単純に大文字にするだけだとすでに存在するとアラートが出るため、一度違う名前を経由して変更(layoutを_layoutにかえてから、Layoutにする等)します。

Droid

また、デフォルトのMainActivity.csは不要なので削除しておきます。

参照設定の定義

Droid、Touchのプロジェクトから参照設定を作成します。参照のフォルダをダブルクリックすると参照設定の画面が表示されますので[Projects]タブを選択し、Coreのプロジェクトを選択します。

参照設定

MvvmCrossのインストール

プロジェクトにMvvmCrossをインストールします。ソリューションを右クリックして[Manage NuGet Packages]を選択します。

Manage NuGet Packages

NuGetのパッケージ検索ダイアログが開きますので、MvvmCrossを検索し、[MvvmCross - Hot Tuna Starter Pack]を選択します。

MvvmCross

インストールするターゲットのプロジェクトを選択する画面が表示されるので、すべて選択してOKをクリックします。

スクリーンショット 2014-03-01 2.44.20.png

この処理を行うと、プロジェクトにライブラリが追加され、ひな形が一気に生成されます。

AppDelegateのコピー

Touchのプロジェクトに、AppDelegate.cs.txtが生成されますので、AppDelegate.csの内容をこのファイルの内容で上書きします。

作業が終われば、AppDelegate.cs.txtは不要となるので削除します。

とりあえず動かして確認する

以上でプロジェクトの初期設定は完了です。まずはそれぞれ動かしてみましょう。

スクリーンショット 2014-03-01 2.51.48.png

スクリーンショット 2014-03-01 3.08.47.png

無事に動きましたでしょうか。これでMvvmCrossを使った開発の準備が整いました。

PCLサポートがおかしい感じだったからXamarinとMonoを再インストールした

なぜか手元のMacBookに入れてあったXamarin StudioのPCLサポートがおかしくって、PCLのプロジェクト設定からXamarin.iOSとXamarin.Androidが消えたりとか、PCL参照設定できないわとひどい感じになってた。

f:id:iseebi:20140228073638p:plain

いろいろいじっててもなおらず、再インストールすることにした。

あまりアンインストールの手順がなかったのだけど、ちょうど id:ytabuchi
Mac で Xamarin 環境をクリーンに再インストールするには - Xamarin 日本語情報 という記事を書かれてたのでちょうどよく Xamarin の再インストールができた。

VSのlaunchd とかも残ってるかもなので、これも試しといた方がいいかも。(古いバージョンから追っかけてた人オンリー?今どうなってるかわからん)(Uninstalling - Xamarin)

sudo launchctl unload /Library/LaunchAgents/com.xamarin.mtvs.buildserver.plist
sudo rm -f /Library/LaunchAgents/com.xamarin.mtvs.buildserver.plist
sudo rm -rf /Developer/MonoTouch
sudo pkgutil --forget com.xamarin.monotouch.pkg

しかし、これやったあとに Xamarin Studio を入れても改善しなかった。


仕方がないので、Mono も再インストールすることにした。再度上記の手順をした後、Mono のサイトに書かれているアンインストール用のシェルスクリプトをファイルに作成して、sudo で実行。

http://www.mono-project.com/Mono:OSX#Uninstalling_Mono_on_Mac_OS_X

これで再度Xamarinのインストーラでインストールし、最新版までアップデートしたら問題なく動作した。

PCL未サポートのときにいろいろFramework内をいじってたりしたのが悪さしてたのかもしれない。

MacのXamarin Studioで2つ以上のソリューションを開く

MacのXamarin Studioで、複数のソリューションを開いて、相互に確認しながら作業を進めたいという状況はよくあると思います。

あるソリューションを開きながら、別のソリューションを開く方法としては、2つ手段があります。

1つのXamarin Studio内で2つ以上のソリューションを開く方法

あるソリューションを開いている状態から、さらに「ファイル」「開く」を選択し、ソリューションファイルを選択した際に「現在のソリューションを閉じる」を選択すれば、ソリューションツリー上に2つのソリューションを開くことができます。

f:id:iseebi:20140204222335j:plain

この方法を使えば、2つのソリューションの内容を串刺し検索したりでき便利です。

Xamarin Studioを2つ起動する方法

通常、Macアプリケーションは1アプリ1プロセスしか起動できないため、Xamarin Studioもこの制限を受けますが、下記のようにopenコマンドの-nオプションを使用するとこの制限を超えて起動することもできます。ターミナルを開いて打ち込んでください。

open -n /Applications/Xamarin\ Studio.app

開発環境としては、こちらのほうが分離されていてわかりやすいので、普段はこちらの方法で多重起動して、Mission Controlで切り替えています。