Mercari Advent Calendar 2018 の18日目は Mercari US Android チームの @panini がお送りします。
メルカリではアプリ開発でKotlinというプログラミング言語をよく使っています。
主のユースケースではKotlinはJVM上で使うのは一番有名だと思いますが、公式のKotlinJSとKotlin/NativeプロジェクトでJavaScriptとNative(C言語)の環境でもKotlin使えます!
Kotlin Multiplatform
Kotlin Multiplatformで、一つのコードベースで複数プラットフォーム対応出来るようになります。
Problem
僕はDRYコーディングは大事だと思っています。
プラットフォームごとにアプリ作っちゃうとbusiness logicは完全にrepeatしてるのであんまり効率は良くないですね。さらに、プラットフォームごとにlogicのバグも生み出すこともあるので、メンテは大変になる。
この問題は結構痛いので、ReactNativeやFlutterみたいなフレームワークを利用して1アプリ複数プラットフォーム対応出来るアプリは作りたくなりますが、やはりそうしちゃうとそれぞれのプラットフォームの特集ポイントは使えなくなる、もしくは if(platform == "iOS")
みたいなコードは出てきて、全体的にアプリの設計はぐちゃぐちゃになってしまいます。
共通にしたいのはlogicだけなので、logicだけ共通しているAndroid/iOSアプリを作ってみました!
Architecture
このプロジェクトは今の所あくまでMVP(Minimum Viable Product)なので、一番簡単に作れそうなアーキテクチャのMVVMにしました。
普通のMVVMではこういう作りになります。
ポイントは依存はView→ViewModelになっています。ViewModelはViewのことを知る必要はないので、ViewModelが例えばlibraryに入っていても問題はありません。
このプロジェクトで作りたい設計は以下の通りです。
Project structure
Kotlin multiplatform プロジェクトでは、Kotlin standard library以外のクラスは使えません。これはどういう意味かと言うと、普段使ってる java.lang
や java.util
クラスは一切使えません。時間を計算したい時には java.util.Date
も使えないし、ネットワーク通信したい時に java.net.Socket
も使えません。Kotlin standard libraryでSocketなどは提供されていないので、これは使うものにならないのでは?と思っているのでしょう。そこでKotlin Multiplatformの特徴ポイントが出てきます。
Multiplatformでは expect
と actual
というキーワードがあって、これはmultiplatform専用のインターフェイスで使われています。あるplatformのクラスを使いたい場合、Kotlinのほうで expect class Hoge
を定義する。これは「このクラスはplatformの方である」というフラグ!たとえば、Date
の場合はこうかけます。
expect class Date { fun getTime(): Long }
そして、platformごとに、このexpect
クラスをactual
で実装しないといけません。multiplatformのprojectがそれぞれのplatformにコンパイルしたタイミングで、expect
のクラスはactual
のクラスになります。
もちろん、このactual
クラスはplatform自体のクラスでも使えます
actual class Date = java.util.Date
Result
作ったプロジェクトはこちらのGithubになります!
細かい実装は次のブログで書きますが、思ったより簡単に実装出来て、Android/iOSで同じlogic使って、それぞれのplatformでUI作って、アプリを作りました。
Gotchas
実装自体はそこまで大変ではなかったが、いくつかハマる点がありましたのでここで紹介します。
Full KotlinのライブラリかMultiplatformのライブラリか自分でwrapper作るしか使えません。
これはそんなに問題ないかなーと思いました。logic layerではライブラリいらないでしょうと思っていたが、Androidの開発でよく使われてるRxJavaなどでも使えないので、ちょっと困りました。そして、RxJavaの作りはちょっと複雑ので、wrapper作るのもちょっと現実的ではないです。
Network通信 😇
Network通信もOkHttp+Retrofitのコンビ使いたくなりますが、これもJavaなのでアウトです。これは数週間どうするかいろいろ調べてみて、自分で実装しないと無理かなとなった時に Ktorがhttp clientも提供してるの気づいて、しかもmultiplatformなのでこれで救われました。
AndroidStudio
AndroidStudio3.3使っていますが、うまくmultiplatformのクラスなど認識しないので、IDE上でimport出来ないとautocompleteは動かないが、こんぱいるすると普通に動きますので一応使えます。今後3.4で試してみるつもりです
Conclusion
このプロジェクトは結構面白かったです。UIは各platformで書くことで、ReactNativeやFlutterよりは実装量は多いですが、各platformっぽいUIも作れるし、簡単にwebでも対応出来るのは大きなポイントです。
そして、このlogicのライブラリはアプリの一部として使えるので、microservice architectureとすごく相性が良いです。是非試してみてください!
明日 19 日目の執筆担当は @nekobato です。引き続きお楽しみください😸