Edited at

iOSアプリをKotlin/NativeとFlutterに移植する

この記事はリクルートライフスタイル Advent Calendar 2018の22日目の記事です。


はじめに

ホットペッパービューティーでネイティブアプリの開発をしている @yrhorita です。

この記事では、Kotlin/NativeとFlutterとで同じアプリケーションを作ってみたときのやり方や感想などを書いていきます。


想定シチュエーション


Swiftで書いたiOS版を展開していたプロダクトについて、PMが「そろそろPMFも見えてきたし、Android版も作り始めたいなー」と言い出した。

自分がエンジニアとして取りうる選択肢の第一はもちろんKotlinでAndroid版を作ることだが、それ以外にクロスプラットフォームという選択肢がどれだけ現実的か、せっかくなので少し試してから決めても良いのでは?



作るプロダクト



画像を眺めるアプリです。シングルカラムで、無限スクロールで見ていく感じ。

APIから取ってきたObjectリストにはそれぞれ画像のURLが書いてあり、セルごとに画像をリクエストして描画していくイメージです。

必要そうな処理は、APIリクエストしてjsonをパースする、URLから画像を取得し表示する、縦向きのシングルカラムのリストビューを表示する、スクロールに応じてページングしてAPIリクエストをする、あたりです。


やってみよう

今回考えるプラットフォームはAndroidとiOSに限定します。


共通の技術stack

画像はpixabayから取ってきます。APIキーが必要なので、これを所定のファイルから読み出します。


Flutter


完成版

https://github.com/yrhorita/advent-calendar-2018/tree/master/flutter_sample

Android
iOS



環境構築

flutter upgrade で出てくる指示に従っていけば良いのでとても楽ですね。


作り方

既存のiOSの資産を使わず、最初からゴリゴリ書いていくことにします。

IDEはVS Codeでもいいのですが、筆者はIntelliJファミリーが好きなのでAndroid Studioで書きました。

Flutterのwidgets libraryを見つつ、各アイテムにはシンプルなContainerを使えば良さそうということで選択。

シングルカラムのリストを実現できそうなクラスはいくつかありそうでしたが、ListView のbuilderを使っていくのがパフォーマンス観点で有利とあるので従ってみました。

APIクライアントやネットワーク越しに画像のキャッシュ含めて使いやすくしてくれるライブラリ(PicassoやKingfisherのような)は、 Flutter Packages で適当に探して入れました。

アーキテクチャについては、Flutter(というか、Dart?)といえばBLoCアーキテクチャのようですが、今回は 締切間近すぎて ベタっとmainファイルに書いてしまいました…


感想


Dart

Dartは書いたことがなかったのですが、Javaっぽいので書くこと自体はなんとかなりました。

Kotlinに飼いならされた身としてはセミコロンを忘れがちでしたが、Android StudioにDartプラグインを入れておけばかなり高速にwarningを出してくれるため、比較的ストレス少なく書けました。

Dartはシングルスレッドで動くのですがasync/awaitなど非同期処理のために必要な言語機能も揃っており、最近の静的型付け言語としてなかなかいい感じです。

強いて言えば、Optionalくらいは用意してくれてもよかった気はしますかね。


Flutter

Flutterでのネイティブアプリ開発はすごく楽で楽しいと思います。なんといってもHot Reload/Restartはすごく強力です。普段のAndroid/iOS開発ではビルドの待ち時間の数十秒~数分をどう有効活用するかを考えていましたが、Flutterであればその必要は殆どなくなりそうです。

LinearLayoutもUITableViewも知らなくても、OkHttpもAPIKitも使わなくても、上のようなアプリが書けてしまうということにも驚きます。Android/iOSのネイティブAPIを知らないままにクロスプラットフォームの開発をできてしまうのは、両ネイティブアプリ開発をやってきている人間としては面白いと同時にちょっと焦りますね :hugging:

Material Designを中心にWidgetが豊富に用意されているので、特殊なデザインがないアプリであれば本当に簡単に作ってしまえそうです。

Android/iOSの分岐については、今回のサンプルアプリの中ではDartだけで実現しています。具体的には、dart:ioライブラリ内の Platform.isAndroid などで分岐させました。

本格的に分ける場合は、MethodChannelというAPIを使ってFlutterのクライアントからネイティブのhostとやり取りする形式になりそうです(参考)。PlatformViewを使えばWebViewやMapsなども使えそうですね(エアプ)。


参考にした記事


Kotlin/Native


環境構築

https://github.com/JetBrains/kotlin-native のREADMEに従ってセットアップします。1時間くらいかかると書いてありますが、筆者のMBPでは2時間かかりました。

- JDK 1.8.0_192, Xcode10.1

- Kotlin 1.3.11

- Kotlin/Native v1.1.0


Troubleshooting


  • ./gradlew dependencies:updateBuild file '/Users/yuri/go/src/github.com/JetBrains/kotlin-native/build.gradle' line: 44 でFailするとき


    • XcodeのCommand Line Toolsの設定ができていないかも


    • xcrun xcodebuild -version でバージョンが見られなければXcode上からPreferences->Locations->Command Line Toolsを選択する




作り方

既存のiOSアプリをKotlin/NativeのMultiplatform Projectに移植していくことを想定します。

iOSアプリ側から共通化できそうなコード(APIレスポンスを受けるクラスなど)や共通化できそうなインタフェース(APIリクエスト部分)をKotlin/Nativeのcommon moduleに切り出していきます。

HttpクライアントはKtor clientがMPP対応していていい感じだったので使ってみます。

…とやってみていたのですが、結局途中からはKotlinでAndroid版を作っていく作業になってしまったので、今回は割愛します。

途中までの作業は yrhorita/advent-calendar-2018 に置いておきますので興味のある方はご覧ください。

画像のURL取得まで終わっているので、あとはRecyclerViewなどに画像を表示しスクロールに応じてページングしていくだけです。


感想

iOS版だけの状況からKotlinによるAndroid版を作っていくような状況であれば、共通部分をKotlin化しながら作っていくことができるため、二重メンテのコストを下げつつマルチプラットフォーム展開ができるようになるのが良いなと思いました。

既存のiOS資産を活かしながら進めることができるのは魅力的ですね。

また、使い込むと「どこがプラットフォーム間で共通化できる/できないのか」をとにかく考えていくことになるため、ネイティブアプリ(クライアントサイドのプログラミング)における抽象化のトレーニングにもなりそうだと思いました。

思想として最初からcommon moduleと各プラットフォーム用のmoduleに分けている割り切りはとても現実的だなと感じます。今回はシンプルなアプリを作成したため共通化しうる部分も多かったですが、実際のアプリ開発では認証やWebView、他アプリ連携やバックグラウンド処理、プッシュ通知といった、プラットフォームごとに固有または癖がある処理が多数あります。

すべてにwrapperのlibraryがあれば良いですが、現実的には依存も増えてしまい難しい予感がします。

プラットフォーム固有の処理は割り切ってプラットフォームごとに記述し、あくまでプラットフォーム間で共通の処理だけcommon moduleで共通化していくという考え方で使っていくのが良さそうです。

筆者はAndroidもiOSもちょっとわかるのでなんとかなりましたが、両方が書けない場合の立ち上がりは結構苦しい気がしました。

それと、素のKotlinでAndroidアプリを書いていくのと比べたデメリット(Javaのassetsが使えないことなど)がiOSアプリとのコード共通化といったメリットと比べてそこまで大きいかと言われると、まだ疑問符がつくかなと思ってしまいます。

ただ、個人的にはKotlinで両OSアプリを書けるということがすべての疑問符を打ち消してくれる気がします!Kotlin最高!


終わりに

執筆中にKotlin/Native, Flutterともにめでたくv1.0.0がリリースされたので、一度書いた記事をまるっと書き直しました :joy: :tada:

連休の残り2日は弊社の開発マネージャー陣による記事が続く予定です。お楽しみに。

それでは、Happy Holidays!