はじめに
Android/iOS、両プラットフォーム上で同じようなアプリを開発する際、明らかに同じような処理をKotlin/Swiftで実装することがあり、共通化したいなと思うところがありました。
例えば、通信部分やEntity、ValueObjectなど、OSが違っても共通になる処理については尚更です。こういった部分を二度も違う言語で実装するのは明らかに二度手間で余計な工数がかかりますし、バグが発生する可能性も増します。
なんとかこういった部分を共通化し、一度コードを書けば両デバイスで動かせる、それによって工数の削減をしたい。そういったモチベーションがあったため、KotlinMPP
について調査を行い、実際にそれを用いて両プラットフォームに一度で対応できるHTTPクライアントを作ってみました。
KotlinMPPとは
正式名称 Kotlin Multiplatform Project
Kotlin1.2及び1.3で実験的に提供されている機能です。Gradleでターゲットとなるプラットフォームにどんな方法でビルドをするかを記述することで、一つのKotlinのソースを各プラットフォーム向けに動作する形でビルドすることが出来ます。
例えば、AndroidではJVMで動作するようにビルドする、iOSではネイティブで動作するようにビルドする、といった次第です。
Android,iOSはもちろん、mac,Windows,JSをターゲットとすることが出来ます。
KotlinMPPを使ったHTTPクライアントライブラリ
サンプルプロジェクトを作ってみました。
5hyn3/KotlinMPPHttpClientSample
以下のような言語やビルドツール、ライブラリを組み合わせて作られています
-
kotlin
- 1.3.31
-
gradle
- 5.4.1
-
ktor-client
- 1.1.5
-
kotlinx.serialization
- 0.11.0
-
kotlinx.coroutin
- 1.2.1
テストが一つ記述されており、実際にAPIからjsonを取得し、パースしてkotlinのオブジェクトとして取得する部分までの動作を確認することが出来ます。実際にアプリに組み込んで動作を確認したい場合は以下を参考にしてください。
Multiplatform Project: iOS and Android
ビルド成果物としてjarとframeworkができるので、それらを扱う形になります。
現状、AndroidとiOSのみをターゲットに作っていますが、gradleに手を入れることでJSなどにも対応させることが出来ます。
苦労した点
以下サンプルプロジェクトを作った際に遭遇した大変だった点を書いていきます
バージョンごとにビルド時の挙動が違っており適切なバージョンの組み合わせを見つけるのが大変だった
主にGradleによるものです。色々なプロジェクトを参考にしてサンプルプロジェクトを作りましたが、バージョンがちょっとでも違うと全くビルドすら出来ませんでした。また、ライブラリが要求するGradleのバージョンが食い違っていたりして悩んだこともありました。
最終的に、現時点での最新版である5.4.1
を採用することで解決しました。本プロジェクト作成に費やした時間の8割くらいはここで適切なライブラリを選定することで消費されています。まだexperimentalなのでこのあたりはどうしてもしょうがないですね。
suspend
なmethodをSwiftから呼び出せない
現状Kotlin/Nativeはsuspend
なmethodをswiftから呼び出せるインターフェースを作ってくれないようです。suspend
をやめ、Deferred
インスタンスを返すようにすることでSwiftからもきちんと扱えるようになりました。こちらであればSwift側からも扱えるインターフェースが提供されており、問題なく呼び出すことが出来ます。
Kotlin/Nativeでビルドした際にランタイムでIncorrectDereferenceException
が発生する
本プロジェクトでは非プリミティブ型のトップレベル変数をメインスレッド外から触ろうとしたために発生しました。具体的にどこで発生したかというと、ここです。対処法としては@ThreadLocal
を付与して、スレッドローカルとして扱うことで対応を行いました。
終わりに
これでKotlinでコードを一つ書けばAndroid/iOS両方で動くライブラリを作ることが出来ました。これでより業務を加速し、同じことを二回も書くようなつまらない作業は減らして、もっと本質の部分に時間を使うことが出来るようになるといいなぁと思います。
参考
JetBrains/kotlin-mpp-example
Multiplatform Project: iOS and Android
kotlin-native /IMMUTABILITY.md
DroidKaigi/conference-app-2019
SimonSchubert/Newsout