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

ABEMAのKotlin Multiplatform

Avatar for takahirom takahirom
April 27, 2021

ABEMAのKotlin Multiplatform

Avatar for takahirom

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()