こんにちは。 経費精算サービス「マネーフォワード クラウド経費」の開発チームでiOSエンジニアをしている河島です。
本日、ICカードリーダー by マネーフォワードのiOS版アプリをストアに公開しました。 交通系ICカードから利用履歴を取得して表示したり、マネーフォワードのサービスと連携して家計簿や経費精算などに役立てていだだけるアプリになっているので、よろしければダウンロードして使っていただけると嬉しいです。
今回はそのICカードリーダーアプリの開発について共有してみようと思います。
経緯
マネーフォワードでは、以前からICカードリーダー by マネーフォワードのAndroidアプリを提供しており、ユーザーの皆様から経費精算などに便利だと好評いただいておりました。
iOS版が欲しいというご要望もあったのですが、FeliCaから必要な情報を取得するAPIが公開されておらず開発が難しい状況でした。
そんな中、今年のWWDC 2019でiOS 13が発表され、CoreNFCにFeliCaから情報を読み取るAPIが追加されていることに気付きました。
これはもしかするとICカードリーダーのiOS版アプリを開発できるのではないかと思い、早速技術検証をしてみることにしました。 ありがたいことに、弊社には既にAndroid版のコードが存在するので、参考にしながらICカードから明細を読み込むコードを書いてみたところ、実際に履歴を読み取ることができたので正式に開発プロジェクトがスタートしました。
どうせ出すならiOS 13と同時にリリースした方がかっこいいだろうということで、チームで協力して急ピッチで作業を進めました。
SwiftUIの採用
今年のWWDCでもっともインパクトがあったのはSwiftUIやCombineだと思いますが、iOS 13以降でしか動作せず、既存のプロダクトに適用するのは難しそうかなと思っていました。
ただ、同じく追加されたFeliCa関連のAPIもiOS 13以降対応だったため、ICカードリーダーアプリを作るのであれば、iOS 13以上が必須という状況になりました。 これはSwiftUIを実際の製品開発で利用できる良いチャンスだと思い、SwiftUIで開発を検討してみることにしました。
Appleが公開しているチュートリアルをやってみると、簡単に画面のコードがかけるなという印象でした。 このチュートリアルを一通りなぞれば、Viewの作り方やアニメーション、既存のUIKitとの組み合わせなど、基本を一通り学ぶことができたのは良かったです。
今回の開発ではiOS 13のリリースに間に合わせるためにスピードも重視する必要があったのですが、SwiftUIだとスピード感を持って開発できそうだと思い、採用することにしました。
iOS 13向けの開発について
普段開発しているクラウド経費のiOSアプリでは、ReactorKitというライブラリ(Fluxっぽいアーキテクチャ)を採用していたり、RxSwiftやAlamofireなどOSSのライブラリを導入していたりしますが、今回のICカードリーダーアプリ開発では、それらのライブラリを一切導入せずにすみました。
ViewまわりはCombine.ObservableObject
を継承したクラスに状態を持たせ、@SwiftUI.ObservedObject
として監視する平凡な作りになっていて、通信周りなどではURLSession
とCombine
を組み合わせて利用しています。
Swiftの言語自体の進化や、iOS SDKが充実してきたことで、Appleが提供するSDKのみでおおよそ事足りるようになったのだなと実感しました。
依存ライブラリがないのと、アプリ自体の規模が比較的小さいことで、コンパイル時間が短く、特にキャッシュなど工夫せずともCIの待ち時間も1回が2〜3分程度で、長くても5分程度ですみました。
こういった面も、スピード感を持って開発できた要因の一つだと思います。
SwiftUIの大変なところ
現状のSwiftUIには様々なバグや不足しているAPIなどまだまだ残っているなという印象です。
公式チュートリアルをなぞってみると、すごく簡単にアプリを作れそうな気がしてくるのですが、実際にやってみると痒いところに手が届いていないところもあり、バグか仕様かわからない挙動なども残っていたりして調査に時間がかかることもありました。
例をあげると以下のようなものになります。 (もしかすると何か気づいてないやり方があるのかもしれませんが・・・)
TextField
で複数行入力できないTextField
に@State
を渡した時に日本語変換ができない (iOS 13.1 betaで改善はみられる)UIActivityIndicator
の代わりが用意されていない
これらの問題は、対応するUIKitのView (UITextView
, UITextField
, UIActivityIndicator
)をUIViewRepresentable
でラップすることで対応しています。
また、今回は利用しなかったものの、標準UIパーツで画面を構成したい場合などに困りそうなのが、以下のようなものです。
UIRefreshControl
の代わりが用意されてないUITableView
の.insetGrouped
に対応する ListStyle がない- ナビゲーションバーの細かな調整 (色を変えたりとか検索欄がくっついたバーにしたいとか)
これらも結局はUIKitと組み合わせて、UIViewControllerRepresentable
やUIViewRepresentable
でラップすることで対応することになりそうです。
そのため、SwiftUIではできなくても、大体の問題はUIKitを利用すればできることだったりするので、現状はUIKitを適宜組み合わせて利用する必要がありそうです。 (SwiftUIで完結させたいところではあるのですが・・・。)
iOS 13.0のbetaが出るたびに上記にあげたようなものがいろいろ治ってないかなーと楽しみにしていたのですが、betaの頃から内容ほとんど変わらずiOS 13.0の正式版が出てきたなという感じがしました。
また、iOS 13.0とiOS 13.1とでレイアウトなど挙動が異なる部分もあり、今後もOSのバージョンアップでレイアウト崩れが起きないか若干不安があるかなという印象です。
まとめ
iOS 13をターゲットにしてSwiftで開発する場合、標準のiOS SDKがかなり充実していることを実感しました。 SwiftUIはまだ成熟していないフレームワークですが、とっつきやすく、細かいところに目をつぶれば楽しく書けたように思います。 現状はSwiftUIだけで完結するわけではなく、質の高いアプリを目指すには適宜UIKitを組みわせる必要がありそうだなと感じました。
ただ、UIKitとの連携は割と簡単にできますし、SwiftUIの記述のしやすさ・読みやすさなどのメリットを考えると、SwiftUIという選択肢は現時点でも楽しく開発できてよかったなと思いました!
最後に
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【採用サイト】 ■マネーフォワード採用サイト ■Wantedly
【マネーフォワードのプロダクト】 ■お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android
■ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』