Help us understand the problem. What is going on with this article?

KotlinMPPでAndroid/iOS両対応のHTTPクライアントライブラリを作る

More than 1 year has passed since last update.

はじめに 

 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

retty
Retty株式会社はソーシャルメディア、スマートフォンを活かした「人を軸にお店を探せる」グルメサービスRettyを運営する会社です。
https://retty.me
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away