画面遷移において、各画面(機能)のモジュールと:appモジュールの依存関係を疎にするため、ナビゲーションモジュールを作成します。
ナビゲーション(画面遷移)はCompose Navigationを導入して行います。
また、ナビゲーションモジュールには、後述するLocalNavControllerと:appモジュールから遷移するための遷移先NavGraph名だけを持たせますので、最小構成のbuild.gradle.ktsにします。
バージョンカタログにCompose Navigationと最小構成のbuild.gradle.ktsに必要なkotlinプラグインをバージョンカタログに追記します。
[versions]
:
navigation = "2.9.5" # https://mvnrepository.com/artifact/androidx.navigation/navigation-compose
[libraries]
:
navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }
[plugins]
:
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
:
追記後、『Sync Now』で内容をプロジェクトに反映させます。
最上位のbuild.gradle.ktsにkotlin.jvmの使用宣言を追記します。
plugins {
:
alias(libs.plugins.kotlin.jvm) apply false
:
}
追記後、『Sync Now』で内容をプロジェクトに反映させます。
ナビゲーションモジュールは、Android Studioのモジュール作成ウィザードを使わずにモジュールを作成します。
/coreディレクトリ直下にnavigationディレクトリを追加し、最小構成のbuild.gradle.ktsを作成します。
plugins {
alias(libs.plugins.kotlin.jvm)
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.java.get().toInt()))
}
}
dependencies {
implementation(platform(libs.compose.bom))
implementation(libs.compose.runtime)
implementation(libs.navigation.compose)
}
モジュール作成ウィザードを使わずにモジュールを作成したため、ビルド対象モジュールに手動で追記します。
:
rootProject.name = "Portal"
include(":app")
:
include(":core:navigation")
追記後、『Sync Now』で内容をプロジェクトに反映させます。
モジュール分割におけるNavControllerの管理を容易にするため、LocalNavControllerを利用します。
LocalNavControllerを利用すると、各画面がNavControllerを引数で受け取る必要がなくなるため、後述するNavGraphをDI(Hilt)に提供する方法との相性がよくなります。
※引数で受け取らないため、DI(Hilt)がNavControllerを意識する必要がなくなります。
LocalNavControllerとは、UIツリー内に確保したNavHostControllerを格納するローカルな変数のことで、その変数にアクセスするキーをアプリケーションが取得します。
各画面はそのキーを使用してNavHostControllerを取得することになります。
アクセスするキーを保存するため、:core:navigation内にsrc/main/kotlinディレクトリとパッケージjp.co.progress_llc.portal.core.navigationディレクトリ(パッケージ)を追加し、直下にLocalNavController.ktを作成します。
package jp.co.progress_llc.portal.core.navigation
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.navigation.NavHostController
val LocalNavController = staticCompositionLocalOf<NavHostController> {
error("No NavController provided")
}
NavGraphのNavHostへの登録は下記の手順で行います。
これにより、:appモジュールはNavHost登録時に各機能モジュールのNavGraph関数名を知る必要がなくなります。
:appモジュールは、各機能モジュールに遷移するためにNavGraph名を依存で知る必要はありますが、それ以外を知る必要はないため、各機能モジュールの独立性が担保され、開発やテストを各機能モジュール内に閉じて行うことができます。
ナビゲーションのコンテナNavHostを:appモジュールに作成します。
:appモジュールにNavHostの作成に必要な依存を追記します。
:
dependencies {
:
implementation(libs.navigation.compose)
implementation(project(":core:navigation")) :
:
}
追記後、『Sync Now』で内容をプロジェクトに反映させます。
:appモジュールにnavigationディレクトリ(パッケージ)を追加し、直下にAppNavHost.ktを作成します。
package jp.co.progress_llc.portal.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import jp.co.progress_llc.portal.core.navigation.LocalNavController
@Composable
fun AppNavHost(
navGraphs: List<NavGraphBuilder.() -> Unit>,
startDestination: String
) {
val navController = rememberNavController()
CompositionLocalProvider(LocalNavController provides navController) {
NavHost(
navController = navController,
startDestination = startDestination
) {
navGraphs.forEach { it() }
}
}
}