Kotlin Multiplatformプロジェクトの構成を選択する
既存のプロジェクトにKotlin Multiplatformを追加する場合や、新規プロジェクトを開始する場合、コードの構造化にはさまざまな方法があります。一般的に、1つ以上のKotlin Multiplatform共有モジュールを作成し、それらをAndroidおよびiOSアプリから利用します。
特定のケースに最適なアプローチを選択するには、以下の質問を考慮してください。
- Kotlin Multiplatformモジュールによって生成されたiOSフレームワークをiOSアプリからどのように利用しますか? 直接統合しますか、CocoaPods経由ですか、それともSwift Package Manager (SPM)を使用しますか?
- Kotlin Multiplatform共有モジュールは1つですか、それとも複数ですか? 複数の共有モジュールに対するアンブレラモジュールはどのようにすべきですか?
- すべてのコードをモノレポに格納しますか、それとも異なるリポジトリに格納しますか?
- Kotlin Multiplatformモジュールのフレームワークをローカル依存関係として利用しますか、それともリモート依存関係として利用しますか?
これらの質問に答えることで、プロジェクトに最適な構成を選択できます。
Kotlin MultiplatformモジュールをiOSアプリに接続する
iOSアプリからKotlin Multiplatform共有モジュールを使用するには、まずこの共有モジュールからiOSフレームワークを生成する必要があります。その後、それをiOSプロジェクトへの依存関係として追加します。
このフレームワークは、ローカルまたはリモートの依存関係として利用できます。
iOSプロジェクトにKotlin Multiplatformモジュールのフレームワークへの依存関係を追加するには、以下のいずれかの方法があります。
直接統合 (Direct integration)。iOSアプリのビルドに新しい「スクリプト実行フェーズ (run script phase)」を追加することで、フレームワークを直接接続します。Connect the framework to your iOS projectでXcodeでの設定方法を確認してください。
Android Studioウィザードでプロジェクトを作成する際に、この設定を自動的に生成するにはRegular frameworkオプションを選択します。
CocoaPods統合 (CocoaPods integration)。CocoaPodsを介してフレームワークを接続します。CocoaPodsは、SwiftおよびObjective-Cプロジェクトで広く利用されている依存関係マネージャーです。これはローカル依存関係またはリモート依存関係のどちらでも構いません。詳細は、Use a Kotlin Gradle project as a CocoaPods dependencyを参照してください。
ローカルのCocoaPods依存関係を持つワークフローを設定するには、ウィザードでプロジェクトを生成するか、スクリプトを手動で編集できます。
SPMの使用 (Using SPM)。Swiftコードの配布を管理するためのAppleのツールであるSwift Package Manager (SPM)を使用してフレームワークを接続します。JetBrainsはSPMの公式サポートに取り組んでいます。現在、XCFrameworksを使用してSwiftパッケージへの依存関係を設定できます。詳細は、Swift package export setupを参照してください。
モジュール構成
Kotlin Multiplatformプロジェクトで使用できるモジュール構成オプションは2つあります。単一モジュールまたは複数の共有モジュールです。
単一共有モジュール
最もシンプルなモジュール構成は、プロジェクト内に単一のKotlin Multiplatform共有モジュールのみを含みます。
Androidアプリは、通常のKotlinモジュールとしてKotlin Multiplatform共有モジュールに依存できます。しかし、iOSはKotlinを直接使用できないため、iOSアプリはKotlin Multiplatformモジュールによって生成されたiOSフレームワークに依存する必要があります。
メリット | デメリット |
---|---|
|
|
複数の共有モジュール
共有モジュールが大きくなるにつれて、それをフィーチャーモジュールに分割することをお勧めします。これにより、単一モジュールを持つことに関連するスケーラビリティの問題を回避できます。
Androidアプリは、すべてのフィーチャーモジュールに直接依存することも、必要に応じてその一部のみに依存することもできます。
iOSアプリは、Kotlin Multiplatformモジュールによって生成された1つのフレームワークに依存できます。複数のモジュールを使用する場合、使用しているすべてのモジュールに依存する追加のモジュール(_アンブレラモジュール_と呼ばれる)を追加し、その後、すべてのモジュールを含むフレームワーク(_アンブレラフレームワーク_と呼ばれる)を構成する必要があります。
アンブレラフレームワークバンドルには、プロジェクトのすべての共有モジュールが含まれており、iOSアプリにインポートされます。
メリット | デメリット |
---|---|
|
|
アンブレラモジュールを設定するには、すべてのフィーチャーモジュールに依存する別のモジュールを追加し、このモジュールからフレームワークを生成します。
Androidアプリは、一貫性のためにアンブレラモジュールに依存することも、個別のフィーチャーモジュールに依存することもできます。アンブレラモジュールには、しばしば有用なユーティリティ関数や依存性注入のセットアップコードが含まれています。
アンブレラフレームワークには、一部のモジュールのみをエクスポートできます。これは通常、フレームワークのアーティファクトがリモート依存関係として利用される場合に当てはまります。その主な理由は、自動生成されたコードが除外されるようにすることで、最終的なアーティファクトのサイズを抑えるためです。
アンブレラフレームワークアプローチの既知の制約として、iOSアプリがフィーチャーモジュールの一部のみを使用することはできず、すべてを自動的に利用するという点があります。この機能の改善案については、KT-42247およびKT-42250であなたのケースを記述してください。
以下の例でiOSアプリがアンブレラモジュールに依存していると示されている場合、それはこのモジュールから生成されたアンブレラフレームワークにも依存していることを意味します。
アンブレラフレームワークが必要な理由
異なるKotlin Multiplatform共有モジュールから生成された複数のフレームワークをiOSアプリに含めることは可能ですが、このアプローチは推奨しません。Kotlin Multiplatformモジュールがフレームワークにコンパイルされると、結果のフレームワークはそのすべての依存関係を含みます。2つ以上のモジュールが同じ依存関係を使用し、別々のフレームワークとしてiOSに公開されると、Kotlin/Nativeコンパイラは依存関係を複製します。
この重複は、いくつかの問題を引き起こします。まず、iOSアプリのサイズが不必要に肥大化します。次に、依存関係のコード構造が、重複した依存関係のコード構造と互換性がありません。これは、iOSアプリケーション内で同じ依存関係を持つ2つのモジュールを統合しようとすると問題を引き起こします。たとえば、異なるモジュールが同じ依存関係を介して渡す状態は、接続されません。これにより、予期しない動作やバグにつながる可能性があります。正確な制限の詳細については、TouchLabのドキュメントを参照してください。
Kotlinは共通のフレームワーク依存関係を生成しません。なぜなら、そうしないと重複が発生し、アプリに追加するすべてのKotlinバイナリは可能な限り小さくする必要があるからです。Kotlinランタイム全体とすべての依存関係からのすべてのコードを含めることは無駄です。Kotlinコンパイラは、特定のビルドに必要なものだけをバイナリから正確にトリムできます。しかし、他のビルドが何を必要とするかを知らないため、依存関係を共有しようとすることは実現不可能です。この問題の影響を最小限に抑えるための様々なオプションを検討しています。
この問題の解決策は、アンブレラフレームワークを使用することです。これにより、iOSアプリが重複した依存関係で肥大化するのを防ぎ、結果として得られるアーティファクトの最適化に役立ち、依存関係間の非互換性によって引き起こされる不満を解消します。
リポジトリ構成
新規および既存のKotlin Multiplatformプロジェクトで使用できるリポジトリ構成オプションは多数あり、単一のリポジトリを使用したり、複数のリポジトリを組み合わせたりすることができます。
モノレポ:すべてを1つのリポジトリに
一般的なリポジトリ構成は、モノレポ構成と呼ばれます。このアプローチは、Kotlin Multiplatformのサンプルやチュートリアルで使用されています。この場合、リポジトリにはAndroidアプリとiOSアプリの両方、および共有モジュール(アンブレラモジュールを含む複数のモジュールの場合もあり)が含まれます。
通常、iOSアプリは、直接統合またはCocoaPods統合を使用して、Kotlin Multiplatform共有モジュールを通常のフレームワークとして利用します。詳細およびチュートリアルへのリンクについては、Kotlin MultiplatformモジュールをiOSアプリに接続するを参照してください。
リポジトリがバージョン管理下にある場合、アプリと共有モジュールは同じバージョンを持ちます。
メリット | デメリット |
---|---|
|
|
既存のAndroidおよびiOSアプリがすでに異なるリポジトリに格納されている場合、それらをマージするのではなく、Kotlin Multiplatform部分をAndroidリポジトリに追加するか、別のリポジトリに追加できます。
2つのリポジトリ:Android + 共有 | iOS
別のプロジェクト構成は、2つのリポジトリを持つことです。この場合、Kotlin MultiplatformのリポジトリにはAndroidアプリと共有モジュール(アンブレラモジュールを含む)の両方が含まれ、XcodeプロジェクトにはiOSアプリが含まれます。
AndroidアプリとiOSアプリは個別にバージョン管理でき、共有モジュールはAndroidアプリと一緒にバージョン管理されます。
3つのリポジトリ:Android | iOS | 共有
もう1つのオプションは、Kotlin Multiplatformモジュール用に独立したリポジトリを持つことです。この場合、AndroidアプリとiOSアプリは個別のリポジトリに格納され、プロジェクトの共有コードには複数のフィーチャーモジュールとiOS用のアンブレラモジュールを含めることができます。
各プロジェクトは個別にバージョン管理できます。Kotlin Multiplatformモジュールも、AndroidまたはJVMプラットフォーム用にバージョン管理され、公開される必要があります。フィーチャーモジュールを個別に公開するか、アンブレラモジュールのみを公開してAndroidアプリがそれに依存するようにすることができます。
Androidアーティファクトを個別に公開することは、Kotlin MultiplatformモジュールがAndroidプロジェクトの一部であるシナリオと比較して、Android開発者にとって追加の複雑さをもたらす可能性があります。
AndroidチームとiOSチームの両方が同じバージョン管理されたアーティファクトを利用する場合、それらはバージョンパリティ(バージョン同等性)で動作します。チームの観点から見ると、これは共有されたKotlin MultiplatformコードがAndroid開発者によって「所有されている」という印象を避けます。フィーチャー開発のためにすでにバージョン管理された内部KotlinおよびSwiftパッケージを公開している大規模プロジェクトでは、共有Kotlinアーティファクトの公開は既存のワークフローの一部となります。
多数のリポジトリ:Android | iOS | 複数のライブラリ
複数のプラットフォーム上の複数のアプリ間で機能を共有する必要がある場合、Kotlin Multiplatformコードを含む多数のリポジトリを持つことを好むかもしれません。例えば、製品全体で共通のロギングライブラリを、独自のバージョン管理を持つ別のリポジトリに格納することができます。
この場合、複数のKotlin Multiplatformライブラリリポジトリを持つことになります。複数のiOSアプリが「ライブラリプロジェクト」の異なるサブセットを使用する場合、各アプリは、ライブラリプロジェクトに必要な依存関係を持つアンブレラモジュールを含む追加のリポジトリを持つことができます。
ここでは、各ライブラリもAndroidまたはJVMプラットフォーム用にバージョン管理され、公開される必要があります。アプリと各ライブラリは個別にバージョン管理できます。
コード共有ワークフロー
iOSアプリは、Kotlin Multiplatform共有モジュールから生成されたフレームワークを_ローカル_または_リモート_依存関係として利用できます。ローカル依存関係を使用するには、iOSビルドでフレームワークへのローカルパスを提供します。この場合、フレームワークを公開する必要はありません。あるいは、フレームワークを含むアーティファクトをどこかに公開し、iOSアプリが他のサードパーティ依存関係と同様にリモート依存関係として利用するようにすることもできます。
ローカル:ソース配布
ローカル配布とは、iOSアプリがKotlin Multiplatformモジュールのフレームワークを公開することなく利用する形式です。iOSアプリは、フレームワークを直接統合するか、CocoaPodsを使用できます。
このワークフローは、通常、AndroidおよびiOSチームのメンバーが共有のKotlin Multiplatformコードを編集したい場合に使用されます。iOS開発者はAndroid Studioをインストールし、KotlinとGradleの基本的な知識が必要です。
ローカル配布方式では、iOSアプリのビルドがiOSフレームワークの生成をトリガーします。これにより、iOS開発者はKotlin Multiplatformコードへの変更をすぐに確認できます。
このシナリオは通常、2つのケースで使用されます。1つ目は、アーティファクトを公開する必要がないため、モノレポプロジェクト構成のデフォルトのワークフローとして使用できます。2つ目は、リモートワークフローに加えて、ローカル開発用に使用できます。詳細については、ローカル開発のためのローカル依存関係のセットアップを参照してください。
このワークフローは、すべてのチームメンバーがプロジェクト全体のコードを編集する準備ができている場合に最も効果的です。これには、共通部分への変更を行った後、AndroidとiOSの両方の部分が含まれます。理想的には、すべてのチームメンバーがAndroid StudioとXcodeをインストールし、共通コードに変更を加えた後に両方のアプリを開いて実行できるようにすることです。
メリット | デメリット |
---|---|
|
|
リモート:アーティファクト配布
リモート配布とは、フレームワークアーティファクトがCocoaPodまたはSPMを使用してSwiftパッケージとして公開され、iOSアプリによって利用されることを意味します。Androidアプリはバイナリ依存関係をローカルまたはリモートで利用できます。
リモート配布は、既存のプロジェクトにテクノロジーを徐々に導入するためによく使用されます。これはiOS開発者のワークフローやビルドプロセスを大きく変えません。2つ以上のリポジトリを持つチームは、主にプロジェクトコードを格納するためにリモート配布を使用します。
まず、リモート配布ワークフローを大幅に簡素化する一連のビルドツールであるKMMBridgeを使用することをお勧めします。あるいは、同様のワークフローを自分でセットアップすることも常に可能です。
メリット | デメリット |
---|---|
参加していないiOSチームメンバーは、Kotlinでコーディングしたり、Android StudioやGradleのようなツールの使用方法を学ぶ必要がありません。これにより、チームへの参入障壁が大幅に下がります。 |
|
ローカル開発のためのローカル依存関係のセットアップ
多くのチームは、Kotlin Multiplatformテクノロジーを採用する際、iOS開発者にとって開発プロセスを同じに保つためにリモート配布ワークフローを選択します。しかし、このワークフローではKotlin Multiplatformコードの変更が困難です。
Kotlin Multiplatformモジュールから生成されたフレームワークへのローカル依存関係を持つ追加の「ローカル開発」ワークフローをセットアップすることをお勧めします。
開発者が新しい機能を追加する際には、Kotlin Multiplatformモジュールをローカル依存関係として利用するように切り替えます。これにより、共通のKotlinコードに変更を加え、iOSからその動作をすぐに確認し、Kotlinコードをデバッグすることができます。機能が準備できたら、リモート依存関係に戻し、それに応じて変更を公開できます。まず共有モジュールへの変更を公開し、その後でアプリに変更を加えます。
リモート配布ワークフローではCocoaPods統合またはSPMを使用し、ローカル配布ワークフローではフレームワークを直接統合します。
CocoaPodsを使用している場合、代わりにローカル配布ワークフローにCocoaPodsを使用することもできます。TouchLabのドキュメントに記載されている環境変数を変更することで、それらを切り替えることができます。