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

ABEMAのKotlin Multiplatform

ABEMAのKotlin Multiplatform

7166bc2cbc462ab5fd1987a76d0fe709?s=128

takahirom

April 27, 2021
Tweet

Transcript

  1. ABEMAのKotlin Multiplatform / / Flutter × Kotlin Multiplatform by CyberAgent

    # Takahiro Menju / takahirom
  2. About me Takahiro Menju takahirom(@new_runnable) ABEMA Android DroidKaigi Conference App

    Leader Google Developers Expert for Android DroidKaigi/conference-app- まだまだ活発に開発しているので お待ちしてます🙏
  3. .ABEMAのマルチデバイス対応 .Kotlin Multiplatformとは .Kotlin Multiplatformを始めるには .各チームでのアプローチ .どのように作るか .今後 .まとめ

  4. ABEMAの マルチデバイス対応

  5. ABEMAのマルチデバイス対応 https://abema.tv/supported-device

  6. ABEMAのマルチデバイス対応 • Android https://abema.tv/supported-device

  7. ABEMAのマルチデバイス対応 • Android • iOS https://abema.tv/supported-device

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

  9. ABEMAのマルチデバイス対応 • Android • iOS • Android TV • Apple

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

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

    TV • Amazon Echo • などなど https://abema.tv/supported-device
  12. UIも、OSも違う

  13. UIも、OSも違う • それぞれのデバイスで、 仕様の実装がバラバラになるので ⼯数が膨らむ

  14. UIも、OSも違う • それぞれのデバイスで、 仕様の実装がバラバラになるので ⼯数が膨らむ • それぞれのデバイスで、 バグが出たときに対応

  15. UIも、OSも違う • それぞれのデバイスで、 仕様の実装がバラバラになるので ⼯数が膨らむ • それぞれのデバイスで、 バグが出たときに対応 • しかし、それぞれのデバイスで、

    同じロジックはたくさんある
  16. Kotlin Multiplatformとは

  17. Kotlin Multiplatform Multiplatform programming https://kotlinlang.org/docs/multiplatform.html

  18. Kotlin Multiplatform • Kotlinで書かれたコードを、複数の プラットフォームで動作させる仕組み Multiplatform programming https://kotlinlang.org/docs/multiplatform.html

  19. Kotlin Multiplatform • Kotlinで書かれたコードを、複数の プラットフォームで動作させる仕組み • 例えばSwiftのコードからKotlinで書かれた コードの実装を呼び出すことができる Multiplatform programming

    https://kotlinlang.org/docs/multiplatform.html
  20. Kotlin Multiplatformを始 めるには

  21. ⽅向性を提案する

  22. ⽅向性を提案する • ⽬的と課題を設定

  23. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供”

  24. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する

  25. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する • Flutter、React Native、Kotlin

    Multiplatformなどを⽐較
  26. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する • Flutter、React Native、Kotlin

    Multiplatformなどを⽐較 • ⽅向性を⽰す
  27. ⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する • Flutter、React Native、Kotlin

    Multiplatformなどを⽐較 • ⽅向性を⽰す • ロジックを共有できるUI / UX観点と開発やコミュニティ状況、 DXと将来性を鑑みて、現時点の⽅向としてKotlin Multiplatformを採⽤する提案を⾏った(by Yuji Hato @dekatotoro)
  28. 参考になるもの 公式のケーススタディ https://kotlinlang.org/lp/mobile/case-studies/ ビジネス的な視点がもっと必要があるなら以下が参考になる。 Building a Business Case for Kotlin

    Multiplatform & Mobile Code Sharing https://dev.to/touchlab/building-a-business-case-for-kotlin-multiplatform-mobile-code- sharing- m
  29. 各チームでのアプローチ

  30. Kotlin Multiplatformを試しているチーム

  31. Kotlin Multiplatformを試しているチーム • さまざまなデバイスの対応を⾏うConsumer Electronics (CE)チーム

  32. Kotlin Multiplatformを試しているチーム • さまざまなデバイスの対応を⾏うConsumer Electronics (CE)チーム • Webチーム

  33. Kotlin Multiplatformを試しているチーム • さまざまなデバイスの対応を⾏うConsumer Electronics (CE)チーム • Webチーム • iOSとAndroidのエンジニアによる、Native

    チーム → 今⽇話すメインはこちら
  34. CE(Consumer Electronics)チーム • Kotlin Multiplatformを使って設計を強制するというものを検 討中 • Kotlin MultiplatformでUseCase、Entityなどを実装 •

    Data層やUI層は各プラットフォームで実装する → これから導⼊して経過を⾒ていく UI UseCase / Entity Data Kotlin Multiplatform Platfrom Platfrom 簡略図
  35. 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- • など • 少しずつ改善されていこうとしている。
  36. Nativeチームでの アプローチ

  37. ロジックを共通化できない か?

  38. Nativeチームの⾛り始め

  39. Nativeチームの⾛り始め • Domain Objectを共通化できないか?

  40. Nativeチームの⾛り始め • Domain Objectを共通化できないか? • そもそも設計の段階で結構話し合いが⼤変になっていた😂

  41. Nativeチームの⾛り始め • Domain Objectを共通化できないか? • そもそも設計の段階で結構話し合いが⼤変になっていた😂 • iOS、Androidの既存のアーキテクチャの違い、 Repositoryの範囲は?どこまでUseCase?Entityを interfaceとdefault

    functionを使って分ける?Entity化 はどこからするか?
  42. Nativeチームの⾛り始め • Domain Objectを共通化できないか? • そもそも設計の段階で結構話し合いが⼤変になっていた😂 • iOS、Androidの既存のアーキテクチャの違い、 Repositoryの範囲は?どこまでUseCase?Entityを interfaceとdefault

    functionを使って分ける?Entity化 はどこからするか? → どうしようか。。
  43. Nativeチームの⾛り始め

  44. Nativeチームの⾛り始め • APIクライアントの実装からKotlin Multiplatformを導⼊していく

  45. Nativeチームの⾛り始め • APIクライアントの実装からKotlin Multiplatformを導⼊していく • 最初はAndroidエンジニアがガッ て作る

  46. なぜAPIクライアントから導⼊し たか

  47. なぜAPIクライアントから導⼊したか

  48. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる

  49. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる • 実績ができるので他の部分への導⼊も進みやすくなる

  50. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる • 実績ができるので他の部分への導⼊も進みやすくなる • 共通化できる部分が多く、今後も活かせる

  51. なぜAPIクライアントから導⼊したか • 同じサーバーを使っているので、iOSとAndroidの実装差異が少ないた め、議論が発⽣しにくい。そのため、スムーズに実装できる • 実績ができるので他の部分への導⼊も進みやすくなる • 共通化できる部分が多く、今後も活かせる • APIの定義

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

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

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

    リクエストやレスポンスのオブジェクト • APIのヘッダーなどの設定、エラーなどの処理 • FakeのAPI実装、テストや、まだAPI実装がないときに共通の Fakeを使ってクライアントで開発することができる。 • 将来的にAPIのレスポンスのEntityからドメインオブジェクトへの変 換もできる。
  55. なぜAndroidエンジニアから ガッと作る形になったか

  56. チームで⾏う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

  57. チームで⾏う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
  58. チームで⾏う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
  59. チームで⾏う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
  60. . AndroidチームがMultiplatformのモジュールを開発する戦略 • 新しいモジュールでは問題なくスムーズに導⼊ していくことができる。✅ • Kotlin Multipaltformの適応範囲を広げていく 場合、Androidのエンジニアが⼤部分を⾒るこ とになるので、継続的には現実的ではなさそ

    う。🚫
  61. . AndroidとiOS両⽅がマルチプラットフォームライブラリで同時 に作業する • 今のNativeチームにマッチしている。✅ • 問題となるのは学習コスト。 • Android iOSエンジニアがお互いの技術を学ぶ

    Bootcampを⾏っており、ある程度のKotlinの知識が 浸透していた。✅ • 引き続き学習していく仕組みを整える必要がありそう
  62. 3. マルチプラットフォームライブラリの作業は専⽤チームが⾏う • 検討は⾏ったが、⼈の採⽤が難 しい🚫

  63. ABEMAでの現在のアプローチ • ” .AndroidチームがMultiplatformのモジュールを開発する戦 略”を⾏い、 • ” . AndroidとiOS両⽅がマルチプラットフォームライブラリで 同時に作業する”に移⾏していく形

    • AndroidのエンジニアのほうがKotlinやGradleに慣れている • iOSエンジニアが意外とKotlin Multiplatformに興味があって 良かった(良いチーム)
  64. どのように作るか

  65. プロジェクト構成をどうするか

  66. Kotlin/kmm-sampleではどうしているか 同じGitHubのリポジトリで、 AndroidアプリとiOSアプリを管 理 1つsharedというモジュールを 作ってそれを使う

  67. Kotlin Multiplatform Project 現在の構成 proto Android project apiclient apiclient-fake iOS

    project ios-abema-mpp
  68. 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 リポジトリ
  69. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

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

    ios-abema-mpp Wire を利⽤し、Protocol Buffersの定義ファイルから ⽣成されたコードを置いている Ktor Clientを使ったAPI Client テストダブルやプロトタイプ実装 で使うfake iOS⽤のライブラリ 技術的詳細
  71. なぜモジュールを分けるか

  72. Kotlin Multiplatform Project proto Android project apiclient apiclient-fake iOS project

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

    ios-mpp マルチモジュールのさまざまな 利点を受けられる これらはスケールしたときに 影響が出てくる ‧並列でのビルド ‧必要がない依存関係が⼊らない
  74. 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
  75. 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を利⽤する)、 バージョンがモジュール毎に存在する 依存モジュールが別のプロジェクトに勝⼿に変更されて、 勝⼿に壊れることがないようにしている。
  76. 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
  77. 実装上のテクニック

  78. プラットフォームで拡張可能に

  79. OkHttpのインスタンスはAndroidでは⼀つに する必要がある! プラットフォームで拡張可能でない場合は共有 されなくなってしまう。

  80. プラットフォームで拡張可能にする それぞれのプラットフォームのソースセットで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, )
  81. 1コードで各プラットフォームで テストを実⾏

  82. commonTestで1コードで各プラットフォームで テストを実⾏できる commonTestフォルダにテストコードを置いて、 以下で実⾏するだけ。 ./gradlew allTests :iosX Test :jvmTest :allTests

  83. expect/actualとinterfaceの使い 分け

  84. 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()
  85. expect/actualを使ったクラスで共通処理をするには ڞ௨ॲཧΛ͜ͷexpectΫϥεͰॻ͜͏ͱ͢ΔͱҎԼͷΑ͏ʹΤϥʔʹͳͬͯ͠·͏ɻ ҰԠextension functionΛ࢖͑͹͔͚ͳ͘΋ͳ͍ɻ

  86. interfaceとexpect/actualの使い分け 公式ドキュメントには以下のような記述 がある。 “expect actualを使いすぎないように。いくつかのケースではinterfaceが拡 張性が⾼く、テストがしやすい。” https://kotlinlang.org/docs/mpp-connect-to-apis.html#rules-for- expected-and-actual-declarations

  87. interfaceとexpect/actualを⽐較する UPQMFWFMؔ਺ɺ ม਺ DPNNPO.BJO͔ Βͷݺͼग़͠Ͱ࣮ ૷Ϋϥεͷίϯε τϥΫλΛݺͼग़ ͤΔ͔ ςετͰͷஔ͖׵ ͑

    ڞ௨ॲཧΛॻ͘ FYQFDUBDUVBM ✅ ✅ 🚫 🚫 JOUFSGBDF 🚫 🚫 ✅ ✅
  88. interfaceとexpect/actualの使い分け 現状は以下のような形で使っている expect/actualを使う ‧プリミティブな関数やUtility ‧interfaceの実装クラスがプラットフォーム側にあるときにインスタンス化 するなどの設定を⾏うとき interfaceを使う ‧上記以外のとき

  89. CIビルド速度の改善

  90. buildに1時間10分😇

  91. Affected Module Detectorを有効化する https://github.com/dropbox/AffectedModuleDetector デフォルトのプラグインではAndroidのタスク⽤に作られていて、 Kotlin Multiplatformで使えるようにできていないため、⾃分でプラグインの実装を追加する サンプルリポジトリ https://github.com/takahirom/kotlin-multiplatform-affected-module-detector-sample 少し実装中にハマったので概念的なところを紹介。

  92. Affected Module Detectorを有効化する Affected Module Detectorの仕組み A B C implementation(project(“:B”))

    implementation(project(“:C”))
  93. Affected Module Detectorを有効化する Affected Module Detectorの仕組み A B C 変更

  94. Affected Module Detectorを有効化する Affected Module Detectorの仕組み B C isProjectAffected =

    true A isProjectAffected = true isProjectAffected = false
  95. Affected Module Detectorを有効化する これでビルドを制御するとどうなるか?? B C ビルドする A ビルドする ビルドしない

  96. Affected Module Detectorを有効化する これでビルドを制御するとどうなるか?? Cがビルドされていないので、Bがビルド失敗して、困る😇 B C Cがビルドされていないので モジュールBのビルドに失敗する A

  97. Affected Module Detectorを有効化する どうするか? Kotlin Multiplatformのビルドで⻑いのはlinkDebugIosなどタスクだが、こ れはModuleBのビルドに不要なので、そのタスクだけ無効化する。 B linkDebugIosなどだけ無効化 A

    C ビルドする ビルドする
  98. Affected Module Detectorを有効化する だいたいの変更で半分の時間でビルドできるようになった

  99. 公式にKotlin/Nativeのビルド時間改善の記事がある Tips for improving Kotlin/Native compilation time https://kotlinlang.org/docs/native-improving-compilation- time.html#gradle-configuration ‧~/.konanのキャッシュ

    ‧“build”などのタスクを避けて、必要なビルドだけ⾏う。 ‧メモリの設定 など
  100. 今後

  101. やっていること、やりたいこと • 実際に⼯数を減らす • Kotlin Multiplatformの利⽤範囲の拡⼤ • ICONIXプロセスを⽤いたドメインオブジェ クトやUseCaseの作成、共通化 •

    他のデバイスへの展開 • Kotlinの学習⽅法を考える
  102. まとめ

  103. まとめ • 複数のチームでKotlin Multiplatformに対するアプ ローチを⾏っている • Nativeチームではマルチモジュールによるアプローチ を⾏っている • まだ新しい技術で、いろいろ試⾏錯誤している。

    今後もさまざまなアプローチを⾏う予定になっている
  104. Thank you