Slide 1

Slide 1 text

ABEMAのKotlin Multiplatform / / Flutter × Kotlin Multiplatform by CyberAgent # Takahiro Menju / takahirom

Slide 2

Slide 2 text

About me Takahiro Menju takahirom(@new_runnable) ABEMA Android DroidKaigi Conference App Leader Google Developers Expert for Android DroidKaigi/conference-app- まだまだ活発に開発しているので お待ちしてます🙏

Slide 3

Slide 3 text

.ABEMAのマルチデバイス対応 .Kotlin Multiplatformとは .Kotlin Multiplatformを始めるには .各チームでのアプローチ .どのように作るか .今後 .まとめ

Slide 4

Slide 4 text

ABEMAの マルチデバイス対応

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

UIも、OSも違う

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

UIも、OSも違う • それぞれのデバイスで、 仕様の実装がバラバラになるので ⼯数が膨らむ • それぞれのデバイスで、 バグが出たときに対応 • しかし、それぞれのデバイスで、 同じロジックはたくさんある

Slide 16

Slide 16 text

Kotlin Multiplatformとは

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Kotlin Multiplatformを始 めるには

Slide 21

Slide 21 text

⽅向性を提案する

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

⽅向性を提案する • ⽬的と課題を設定 • “クライアント全体としての開発の⾼速化と継続的な機能提供” • アプローチを⽐較する • Flutter、React Native、Kotlin Multiplatformなどを⽐較 • ⽅向性を⽰す • ロジックを共有できるUI / UX観点と開発やコミュニティ状況、 DXと将来性を鑑みて、現時点の⽅向としてKotlin Multiplatformを採⽤する提案を⾏った(by Yuji Hato @dekatotoro)

Slide 28

Slide 28 text

参考になるもの 公式のケーススタディ 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

Slide 29

Slide 29 text

各チームでのアプローチ

Slide 30

Slide 30 text

Kotlin Multiplatformを試しているチーム

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Kotlin Multiplatformを試しているチーム • さまざまなデバイスの対応を⾏うConsumer Electronics (CE)チーム • Webチーム • iOSとAndroidのエンジニアによる、Native チーム → 今⽇話すメインはこちら

Slide 34

Slide 34 text

CE(Consumer Electronics)チーム • Kotlin Multiplatformを使って設計を強制するというものを検 討中 • Kotlin MultiplatformでUseCase、Entityなどを実装 • Data層やUI層は各プラットフォームで実装する → これから導⼊して経過を⾒ていく UI UseCase / Entity Data Kotlin Multiplatform Platfrom Platfrom 簡略図

Slide 35

Slide 35 text

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- • など • 少しずつ改善されていこうとしている。

Slide 36

Slide 36 text

Nativeチームでの アプローチ

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Nativeチームの⾛り始め

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Nativeチームの⾛り始め

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

なぜAndroidエンジニアから ガッと作る形になったか

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

. AndroidとiOS両⽅がマルチプラットフォームライブラリで同時 に作業する • 今のNativeチームにマッチしている。✅ • 問題となるのは学習コスト。 • Android iOSエンジニアがお互いの技術を学ぶ Bootcampを⾏っており、ある程度のKotlinの知識が 浸透していた。✅ • 引き続き学習していく仕組みを整える必要がありそう

Slide 62

Slide 62 text

3. マルチプラットフォームライブラリの作業は専⽤チームが⾏う • 検討は⾏ったが、⼈の採⽤が難 しい🚫

Slide 63

Slide 63 text

ABEMAでの現在のアプローチ • ” .AndroidチームがMultiplatformのモジュールを開発する戦 略”を⾏い、 • ” . AndroidとiOS両⽅がマルチプラットフォームライブラリで 同時に作業する”に移⾏していく形 • AndroidのエンジニアのほうがKotlinやGradleに慣れている • iOSエンジニアが意外とKotlin Multiplatformに興味があって 良かった(良いチーム)

Slide 64

Slide 64 text

どのように作るか

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Kotlin Multiplatform Project 現在の構成 proto Android project apiclient apiclient-fake iOS project ios-abema-mpp

Slide 68

Slide 68 text

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 リポジトリ

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

なぜモジュールを分けるか

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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を利⽤する)、 バージョンがモジュール毎に存在する 依存モジュールが別のプロジェクトに勝⼿に変更されて、 勝⼿に壊れることがないようにしている。

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

実装上のテクニック

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

プラットフォームで拡張可能にする それぞれのプラットフォームのソースセットで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, )

Slide 81

Slide 81 text

1コードで各プラットフォームで テストを実⾏

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

expect/actualとinterfaceの使い 分け

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

CIビルド速度の改善

Slide 90

Slide 90 text

buildに1時間10分😇

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

Affected Module Detectorを有効化する Affected Module Detectorの仕組み A B C 変更

Slide 94

Slide 94 text

Affected Module Detectorを有効化する Affected Module Detectorの仕組み B C isProjectAffected = true A isProjectAffected = true isProjectAffected = false

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

公式にKotlin/Nativeのビルド時間改善の記事がある Tips for improving Kotlin/Native compilation time https://kotlinlang.org/docs/native-improving-compilation- time.html#gradle-configuration ‧~/.konanのキャッシュ ‧“build”などのタスクを避けて、必要なビルドだけ⾏う。 ‧メモリの設定 など

Slide 100

Slide 100 text

今後

Slide 101

Slide 101 text

やっていること、やりたいこと • 実際に⼯数を減らす • Kotlin Multiplatformの利⽤範囲の拡⼤ • ICONIXプロセスを⽤いたドメインオブジェ クトやUseCaseの作成、共通化 • 他のデバイスへの展開 • Kotlinの学習⽅法を考える

Slide 102

Slide 102 text

まとめ

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

Thank you