眠いしお腹すいたし(´・ω・`)

C#関連を主に書きます。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

DroidKaigi2017アプリ for Xamarin.AndroidをXamarin.iOSに少し移植してみた。

この記事は Xamarin その1 Advent Calendar 2017 - Qiita の20日目の記事です。

はじめに

2017年は色々ありました。

転職してちょっとだけ都会に引っ越してみたりAzureを本格的に使い始めてみたり・・・それくらいかな?

今年も平常運転でクリスマスは1人なのでCivilization6でもやってるとお思います。

前提

今回の記事は

tamafuyou.hatenablog.com

この記事の続きになっているのですが

実は私の中ではこの記事のさらに前提があります。

Xamarin.Forms とコンソールアプリでモデル層を共通化してみた // Speaker Deck

今年3月に生まれて始めて登壇というものをさせていただいたのですが

この内容の実証実験と言いますか

この登壇資料を作っていた時に考えていた事を実装で組み込んでいます。

やってみた事

少し前にDroidKaigi2017アプリをXamarin.Androidに移植してみる、という挑戦を行いました。

これは単純にその当時で割と新し目の設計であるDroidKaigiアプリを学ぶ事でAndroidネイティブの知識を得ると同時にXamarin.Androidをやってみる事でXamarin Nativeというのはどういう特性があって何が良くて何が厳しいのか、自分の視点で考えてみようという目的がありました。

その実装を行うなかでどうせXamrinするなら所謂MVなんちゃらのM(Model)を3月の登壇内容を前提として設計を行ってみてXamarin.iOS版を作ってみるという方向に動きました。

そして今回、Xamarin.Androidとモデル層を共通化してXamarin.iOSを実装して見た形になります。

今回の取り組みに関する知識の前提

  • Androidネイティブ少しわかる
  • iOSネイティブはXamarin.Formsで使う範囲内くらいわかる
  • Swiftはちょっとだけわかる
  • Objective-Cは見たくない
  • C#/.NET Frameworkは少々わかる
  • Xamarin.Forms(Android/iOS)はそこそこ知ってる方だと思ってた時期がありました

今回の成果物

github.com

https://sleepyandhungry1984.tumblr.com/post/168746685717/droidkaigi2017アプリfor-xamarin-ios
sleepyandhungry1984.tumblr.com

謝罪

まだ余裕あるかなぁとかグダグダやってたら全然時間なくなってしまって執筆の時点で実装が不十分です。

年内はリファクタなどを行うかと思います。

解説

共通部分

DroidKaigi2017forXamarin/src/DroidKaigi2017.Service at master · yuka1984/DroidKaigi2017forXamarin · GitHub

モデル層の共有部分はSharedプロジェクトにて共有化を行なっています。

私はSharedプロジェクトをよく用います。

XamarinによるAndroid/iOS共通開発では..NET StandardLibrary(PCL)での共有プロジェクトにする意味はないだろうと考えています。 逆にStdLibとXamarin.Android/iOS間でのnugetパッケージでの不都合などが起きやすいと思います。

Serviceクラスとリポジトリクラスに分かれていて所謂クリーンアーキテクチャのような構成になっているかと思います。

Serviceクラスの特徴として流れの1方向性を意識した作りにあります。

DroidKaigi2017forXamarin/SessionServices.cs at master · yuka1984/DroidKaigi2017forXamarin · GitHub

公開プロパティはIObservableでありかつステートを持つことが可能であるReadOnlyReactivePropertyとReadOnlyReactiveCollectionを使用します。

そしてサービスに対するリクエストは戻り値のないasync/awaitでの実装でありデータの流れの1方向性となっています。

なぜ1方向性にするか、これは双方向性の繋がりの場合だと仕様変更・複数画面間での共有にて悲惨な問題が起きやすいという経験への対策になります。

またこのパターンの場合、View間の同期問題への対策を行うこともできます。

今回作成した動画の後半を見てもらえるとわかるのですが異なるページであってもデータの変更が伝搬するためView側で意識せずに状態の動機を行うことができます。

ただ、この実装にも問題はあり一つのサービスを多くの画面が共有するような状況で、かつ流れるデータが複雑な時にモデル層の変更のリスクが高くなってります。

今後はこの課題に対する解決策を考えていけたらと思っています。

Repositoryはただのデータの保存庫であり実装としてはCRUD的な作りとなっています。

Azure Mobile Appsのデータテーブルを使用しています。

これらのクラス類は前回のXamarin.Android編にて作成したままで変更はほぼありませんでした。(バグを直しただけ)

iOS部分

私はiOSネイティブ開発への理解度や知識が高くないため、今回作成したものはかなりメチャクチャではないかと思っています。 次こそはちゃんとiOS開発を学びたいと思います。

今回作成するにあたってViewModelを作った方が良いのか?とか考えていたのですが、単純に時間がなかったためViewControllerに直接サービスクラスを持って、そのままコードで操作するような作りとなりました。

storyboardを使いこなせる知識もなかったため、コードでゴリゴリ書いています。

感覚的にはXAMLです( ̄ー+ ̄) ニヤリ…

DroidKaigi2017forXamarin/FirstViewController.cs at master · yuka1984/DroidKaigi2017forXamarin · GitHub

こちらはセッション一覧画面にのコードになるのですが、今回はUICollectionViewを使い縦横スクロールのLayoutは

xyk.hatenablog.com

こちらを参考(C#移植)に作成しました。

DroidKaigi2017アプリのように13タイルや21タイルを組み込もうとするともう少し手を入れなければならないのですが、時間と技量と才能が足りなかったため今回は全て1*1タイルでの実装となりました。

この辺は特に難しいことはなくISessionServiceのSessionsプロパティを用いてCollectionを展開しSessionsの変更がおこなわれた場合UICollectionViewをReloadDataしている形になります。

またIMySessionServiceにてMySession情報が更新された時にもReloadDataをしています。

セルがロングタップされた場合にはIMySessionServiceにMySession情報の変更を依頼しています。

全ては1方向になっているので基本的には画面からのイベントはServiceへの依頼へと射影していきます。

画面は異なりますがMySession画面もほぼ同様の作りとなります。

MySession画面はUITableViewをベースにしています。

詳細画面に関しては

DroidKaigi2017forXamarin/DetailViewController.cs at master · yuka1984/DroidKaigi2017forXamarin · GitHub

これも特に難しくなくレイアウトしてセッション情報が流れてきたら更新する、という作りになっています。

おわりに

Xamarin.iOSを触ってみてやっぱりC#いいなぁという気持ちになりました。

もちろんSwiftやKotlinのような新しい言語の方が機能的に優れているのは間違い無いのですが

慣れた言語でバックエンドもフロントエンドも全部作れるって楽なんですよねぇ(´д`)〜з

それではまた〜ヾ(´д`)ノシ