Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ABEMAのKotlin Multiplatform

ABEMAのKotlin Multiplatform

takahirom

April 27, 2021
Tweet

More Decks by takahirom

Other Decks in Programming

Transcript

  1. About me Takahiro Menju takahirom(@new_runnable) ABEMA Android DroidKaigi Conference App

    Leader Google Developers Expert for Android DroidKaigi/conference-app- まだまだ活発に開発しているので お待ちしてます🙏
  2. ABEMAのマルチデバイス対応 • Android • iOS • Android TV • Apple

    TV • Amazon Echo https://abema.tv/supported-device
  3. ABEMAのマルチデバイス対応 • Android • iOS • Android TV • Apple

    TV • Amazon Echo • などなど https://abema.tv/supported-device
  4. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する • Flutter、React Native、Kotlin

    Multiplatformなどを⽐較 • ⽅向性を⽰す • ロジックを共有できるUI / UX観点と開発やコミュニティ状況、 DXと将来性を鑑みて、現時点の⽅向としてKotlin Multiplatformを採⽤する提案を⾏った(by Yuji Hato @dekatotoro)
  5. CE(Consumer Electronics)チーム • Kotlin Multiplatformを使って設計を強制するというものを検 討中 • Kotlin MultiplatformでUseCase、Entityなどを実装 •

    Data層やUI層は各プラットフォームで実装する → これから導⼊して経過を⾒ていく UI UseCase / Entity Data Kotlin Multiplatform Platfrom Platfrom 簡略図
  6. WEBチーム • Kotlin Multiplatformの検証中 • Playgroundのリポジトリを作って検証 • いくつかの技術的な問題があり未導⼊ • TypeScriptの定義で、enumが使えない

    • https://youtrack.jetbrains.com/issue/KT- • https://youtrack.jetbrains.com/issue/KT- • Ktorのサイズ⼤きい • https://youtrack.jetbrains.com/issue/KTOR- • など • 少しずつ改善されていこうとしている。
  7. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる • 実績ができるので他の部分への導⼊も進みやすくなる • 共通化できる部分が多く、今後も活かせる • APIの定義

    リクエストやレスポンスのオブジェクト • APIのヘッダーなどの設定、エラーなどの処理 • FakeのAPI実装、テストや、まだAPI実装がないときに共通の Fakeを使ってクライアントで開発することができる。
  8. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる • 実績ができるので他の部分への導⼊も進みやすくなる • 共通化できる部分が多く、今後も活かせる • APIの定義

    リクエストやレスポンスのオブジェクト • APIのヘッダーなどの設定、エラーなどの処理 • FakeのAPI実装、テストや、まだAPI実装がないときに共通の Fakeを使ってクライアントで開発することができる。 • 将来的にAPIのレスポンスのEntityからドメインオブジェクトへの変 換もできる。
  9. チームで⾏う3つのアプローチ • . AndroidチームがMultiplatformのモ ジュールを開発する。iOSの開発者はブ ラックボックスとして扱う Approaches to organizing teamwork

    for Multiplatform projects https://kotlinlang.org/docs/mobile/organize-process-around-kmm.html#approaches-to- organizing-teamwork-for-multiplatform-projects
  10. チームで⾏う3つのアプローチ • . AndroidチームがMultiplatformのモ ジュールを開発する。iOSの開発者はブ ラックボックスとして扱う • . AndroidとiOS両⽅がマルチプラット フォームライブラリで同時に作業する

    Approaches to organizing teamwork for Multiplatform projects https://kotlinlang.org/docs/mobile/organize-process-around-kmm.html#approaches-to- organizing-teamwork-for-multiplatform-projects
  11. チームで⾏う3つのアプローチ • . AndroidチームがMultiplatformのモ ジュールを開発する。iOSの開発者はブ ラックボックスとして扱う • . AndroidとiOS両⽅がマルチプラット フォームライブラリで同時に作業する

    • 3. マルチプラットフォームライブラリの作 業は専⽤チームが⾏う Approaches to organizing teamwork for Multiplatform projects https://kotlinlang.org/docs/mobile/organize-process-around-kmm.html#approaches-to- organizing-teamwork-for-multiplatform-projects
  12. ABEMAでの現在のアプローチ • ” .AndroidチームがMultiplatformのモジュールを開発する戦 略”を⾏い、 • ” . AndroidとiOS両⽅がマルチプラットフォームライブラリで 同時に作業する”に移⾏していく形

    • AndroidのエンジニアのほうがKotlinやGradleに慣れている • iOSエンジニアが意外とKotlin Multiplatformに興味があって 良かった(良いチーム)
  13. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-abema-mpp Android, iOS, Kotlin Multiplatformで リポジトリを分けて管理 (これは現在の状態からの移⾏のしやすさからこうなっている) Androidプロジェクト GitHub リポジトリ iOSプロジェクト GitHub リポジトリ Kotlin Multiplatform Project GitHub リポジトリ
  14. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-abema-mpp 細かくモジュールを分けている
  15. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-abema-mpp Wire を利⽤し、Protocol Buffersの定義ファイルから ⽣成されたコードを置いている Ktor Clientを使ったAPI Client テストダブルやプロトタイプ実装 で使うfake iOS⽤のライブラリ 技術的詳細
  16. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-mpp Web Ktorのサイズが⼤きくて⼊れられない さまざまなプラットフォームでの導⼊を想定したときに⼊れたい部分だけ ⼊れられた⽅が良い
  17. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-mpp マルチモジュールのさまざまな 利点を受けられる これらはスケールしたときに 影響が出てくる ‧並列でのビルド ‧必要がない依存関係が⼊らない
  18. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-mpp また構成するモジュールが 300を超える Android Jetpackの構成を 参考にしているため、 以下のような仕組みを参考にでき る ‧必要なモジュールだけテストや ビルド : AffectedMoudleDetector ‧必要なモジュールだけIDEに インポート : Android Jetpackの Playgroundについて https:// qiita.com/takahirom/items/ b e c e https://github.com/androidx/androidx/blob/ e d b bf fee b fec fc /buildSrc/src/main/kotlin/androidx/ build/dependencyTracker/AffectedModuleDetector.kt https://github.com/androidx/androidx/blob/ ce d fbed e fbc f /playground-common/README.md
  19. Kotlin Multiplatform Project proto . . -abd a Android project

    apiclient . . apiclient-fake . . iOS project ios-mpp . . Maven implementation(“tv.abema: ”) Maven implementation(“tv.abema:apiclient: . . ”) Maven implementation(“tv.abema:proto: . . -abd a”) 基本的にMavenで管理し(GitHub Packagesを利⽤する)、 バージョンがモジュール毎に存在する 依存モジュールが別のプロジェクトに勝⼿に変更されて、 勝⼿に壊れることがないようにしている。
  20. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

    ios-mpp iOSͰ͸CocoapodsͰϞδϡʔϧΛ·ͱΊͯࢀর͢Δ ৄ͘͠͸ҎԼʮiOSʹKMMΛಋೖ͢Δtipsʯby 𝚖𝚊𝚛𝚝𝚢-𝚜𝚞𝚣𝚞𝚔𝚒 (@marty_suzuki) https://speakerdeck.com/martysuzuki/iosnikmmwodao-ru-surutips Cocoapods
  21. プラットフォームで拡張可能にする それぞれのプラットフォームのソースセットでDIする。 ここでは単純にConstractor Injectionしている androidMain/kotlin内 public fun ApiClient( // τοϓϨϕϧؔ਺

    config: ApiClientAndroidConfig, ): ApiClient { return ApiClient(ApiClientAndroidImpl(config), config) } public class ApiClientAndroidConfig( public val okHttpClient: OkHttpClient, loggerEnabled: Boolean, ) : ApiClient.Config( loggerEnabled = loggerEnabled, )
  22. expect/actualだとテストが難しい場合がある actualを実装できるのは⼀つだけなので、 テストで置き換えするには以下のように全部openにする必要がある commonMain/ expect open class PlatformExpectActual() { open

    fun platform(): String } jvmMain/ actual open class PlatformExpectActual { actual open fun platform(): String = "jvm" } commonTestͷςετ val platform = object : PlatformExpectActual() { override fun platform(): String { return "test platform" } } Client(platform).doIt()