### router-index.json example Source: https://github.com/limuyang2/krouter/blob/main/docs/router-plugin-architecture.md Shows the fixed field order and format of the router-index.json output. The suffix in the registry class name is illustrative; the real suffix is the first 24 hex chars of the SHA-256 of the validated moduleId. ```json { "schemaVersion": 1, "registryApiVersion": 1, "moduleId": "com.example:feature-home", "registries": [ "com.example.home.generated.ModuleRouterRegistry_0123456789abcdef01234567" ] } ``` -------------------------------- ### IRouterPushInterceptor.intercept Source: https://github.com/limuyang2/krouter/blob/main/README.md Defines a push interceptor that can rewrite the request parameters or target before proceeding. The example shows how to add an extra parameter to the request. ```APIDOC ## IRouterPushInterceptor.intercept ### Description Intercepts a push operation, allowing modification of the request parameters or target before the navigation proceeds. ### Method suspend fun intercept(chain: IRouterPushInterceptor.Chain): PushResponse ### Parameters - **chain** (IRouterPushInterceptor.Chain) - Required - The interceptor chain providing access to the request and the ability to proceed or interrupt. ### Request Example ```kotlin class SourcePushInterceptor : IRouterPushInterceptor { override suspend fun intercept( chain: IRouterPushInterceptor.Chain, ): PushResponse { val request = chain.request().newBuilder() .setExtra("source", "home") .build() return chain.proceed(request) } } ``` ### Response Returns a PushResponse indicating the result of the push operation. ### Notes - Interceptors can be bound to a page via `@Router(pushInterceptors = [...])`, globally via `@RouterGlobalPushInterceptor`, or externally via `@RouterOwnerPushInterceptor`. - Priority: lower numeric value executes first; global interceptors run before page interceptors for the same operation. - After rewriting the target type, the applicable interceptor chain is re-executed. - Call `chain.interrupt()` to abort the navigation. ``` -------------------------------- ### 运行 Desktop Demo:./gradlew :desktopApp:run Source: https://github.com/limuyang2/krouter/blob/main/README.md 启动 Desktop Demo 应用。需要 JDK 21。 ```bash ./gradlew :desktopApp:run ``` -------------------------------- ### 运行 Kotlin/JS Demo:./gradlew :webApp:jsBrowserDevelopmentRun Source: https://github.com/limuyang2/krouter/blob/main/README.md 以开发模式运行 Kotlin/JS 目标,浏览器测试需要 Chrome。 ```bash ./gradlew :webApp:jsBrowserDevelopmentRun ``` -------------------------------- ### 业务模块和宿主模块的 Gradle 插件配置 Source: https://github.com/limuyang2/krouter/blob/main/docs/router-plugin-architecture.md 业务模块使用 io.github.limuyang2.router.module 插件,可覆盖默认 moduleId;宿主模块使用 io.github.limuyang2.router 插件,并配置 registryPackage 和 registryName。两个配置块在同一个示例中展示,分别对应业务模块和宿主模块的构建脚本。 ```kotlin // 业务模块 plugins { id("io.github.limuyang2.router.module") // 原有 Kotlin、平台插件、KSP 插件保持由工程管理 } router { // 可选:覆盖默认 group:name,解决冲突或固定模块身份。 moduleId.set("com.example:feature-home") } // 宿主模块:宿主插件自动包含本模块的生产端能力 plugins { id("io.github.limuyang2.router") } router { registryPackage.set("com.example.generated") registryName.set("RouterAggregatedRegistry") } ``` -------------------------------- ### 运行 Android Demo:./gradlew :androidApp:assembleDebug Source: https://github.com/limuyang2/krouter/blob/main/README.md 构建 Android Demo 的 APK,构建完成后需手动安装 APK。需要 JDK 21 和对应的 Android SDK。 ```bash ./gradlew :androidApp:assembleDebug ``` -------------------------------- ### 使用 navigator.push 跳转 URL 与实例 Source: https://github.com/limuyang2/krouter/blob/main/README.md 在点击事件或业务方法中发起跳转。push 接受页面实例或 URL 字符串,URL 查询参数作为页面参数传入。 ```kotlin navigator.push(UserRoute(id = 42L)) navigator.push("demo://app/user?id=42") ``` -------------------------------- ### 运行 Wasm Demo:./gradlew :webApp:wasmJsBrowserDevelopmentRun Source: https://github.com/limuyang2/krouter/blob/main/README.md 以开发模式运行 Wasm 目标,浏览器测试需要 Chrome。 ```bash ./gradlew :webApp:wasmJsBrowserDevelopmentRun ``` -------------------------------- ### 初始化并注册模块:initRouter 与 RouterAggregatedRegistry Source: https://github.com/limuyang2/krouter/blob/main/README.md 在创建和使用 Navigator 之前调用 initializeNavigation(),先通过 initRouter 配置默认 scheme 和日志,再调用宿主生成的聚合入口 RouterAggregatedRegistry.registerAll()。initRouter 保留首次初始化配置,defaultScheme 默认值为 "route",模块注册必须在初始化之后。 ```kotlin import io.github.limuyang2.router.initRouter import io.github.limuyang2.router.generated.RouterAggregatedRegistry fun initializeNavigation() { initRouter { defaultScheme("demo") isLog(false) } RouterAggregatedRegistry.registerAll() } ``` -------------------------------- ### Configure host module with router plugin Source: https://github.com/limuyang2/krouter/blob/main/README.md Applies the host router plugin and KSP, adds feature module and runtime dependencies, and configures the aggregated registry package and name. ```kotlin plugins { id("io.github.limuyang2.router") version "1.0.0" id("com.google.devtools.ksp") version "<与 Kotlin 匹配的版本>" } dependencies { implementation(project(":feature-product")) implementation("io.github.limuyang2:router:1.0.0") add("kspAndroid", "io.github.limuyang2:router-ksp:1.0.0") add("kspIosArm64", "io.github.limuyang2:router-ksp:1.0.0") } // 聚合当前编译依赖的模块索引,生成 RouterAggregatedRegistry。 router { registryPackage.set("com.example.app.generated") registryName.set("RouterAggregatedRegistry") } ``` -------------------------------- ### Push 拦截器:改写参数或目标 (SourcePushInterceptor) Source: https://github.com/limuyang2/krouter/blob/main/README.md 实现 IRouterPushInterceptor 接口,通过 chain.request().newBuilder().setExtra(...) 改写请求参数,然后调用 chain.proceed(request) 继续执行。页面可通过 @Router(pushInterceptors = [...]) 绑定,全局拦截器通过 @RouterGlobalPushInterceptor 声明,Owner 外置绑定通过 @RouterOwnerPushInterceptor 声明。优先级数值越小越先执行,同一次操作先处理全局拦截器,再处理页面拦截器。改写目标类型后会重新执行适用的拦截器链,调用 chain.interrupt() 可中断跳转。 ```kotlin import io.github.limuyang2.router.IRouterPushInterceptor import io.github.limuyang2.router.PushResponse class SourcePushInterceptor : IRouterPushInterceptor { override suspend fun intercept( chain: IRouterPushInterceptor.Chain, ): PushResponse { val request = chain.request().newBuilder() .setExtra("source", "home") .build() return chain.proceed(request) } } ``` -------------------------------- ### 配置跳转选项的 navigator.push 调用 Source: https://github.com/limuyang2/krouter/blob/main/README.md 通过配置块设置 destination、preventDuplicates、isCleanStack、isPopCurrent 和 greenChannel。destination 非空时优先于 url;greenChannel 跳过 Push 拦截器但保留目标解析和实例唯一性检查。 ```kotlin navigator.push { destination = UserRoute(42L) preventDuplicates = true isCleanStack = false isPopCurrent = false greenChannel = false } ``` -------------------------------- ### Configure business module with router.module plugin Source: https://github.com/limuyang2/krouter/blob/main/README.md Applies the router.module plugin and KSP, adds the runtime library as api dependency, and configures KSP per target. Optionally overrides the default moduleId. ```kotlin plugins { id("io.github.limuyang2.router.module") version "1.0.0" id("com.google.devtools.ksp") version "<与 Kotlin 匹配的版本>" } kotlin { sourceSets { commonMain { dependencies { // 使用 api 暴露运行时库,宿主才能聚合本模块及其传递依赖的索引。 api("io.github.limuyang2:router:1.0.0") } } } } // KSP 按 target / compilation 配置,这里以 Android 和 iOS 为例;纯 JVM 模块可直接使用 ksp(...)。 dependencies { add("kspAndroid", "io.github.limuyang2:router-ksp:1.0.0") add("kspIosArm64", "io.github.limuyang2:router-ksp:1.0.0") } // 可选:覆盖默认 moduleId(默认取 group:name)。 router { moduleId.set("com.example:feature-help") } ``` -------------------------------- ### 接入 NavDisplay:App 组件 Source: https://github.com/limuyang2/krouter/blob/main/README.md 定义 App() 组合函数,创建 Navigator 并通过 CompositionLocalProvider 提供 LocalNavigator,然后使用 NavDisplay 显示导航界面。必须安装 rememberRouteResultNavEntryDecorator() 以支持 rememberRouteResult,其他 decorators 处理可保存状态和 ViewModel。 ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator import androidx.navigation3.ui.NavDisplay import io.github.limuyang2.router.LocalNavigator import io.github.limuyang2.router.Navigator import io.github.limuyang2.router.rememberRouteResultNavEntryDecorator @Composable fun App() { val navigator = remember { Navigator(HomeRoute()) } CompositionLocalProvider(LocalNavigator provides navigator) { NavDisplay( backStack = navigator.backStack, onBack = { navigator.pop() }, entryDecorators = listOf( rememberRouteResultNavEntryDecorator(), rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator(), ), entryProvider = entryProvider { navigator.pageProviderInstaller.forEach { install -> install(this) } }, ) } } ``` -------------------------------- ### Pop 拦截器:使用 redirect 改变页面选择 Source: https://github.com/limuyang2/krouter/blob/main/README.md 在 Pop 拦截器中调用 chain.redirect { to() } 改变页面选择。选择条件改变时重新解析目标;相同条件保留原绑定实例。 ```kotlin return chain.redirect { to() } ``` -------------------------------- ### Configure repositories in settings.gradle.kts Source: https://github.com/limuyang2/krouter/blob/main/README.md Adds Maven Central and Gradle Plugin Portal repositories for plugin management and dependency resolution. Required before applying KRouter plugins. ```kotlin // settings.gradle.kts pluginManagement { repositories { mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositories { mavenCentral() } } ``` -------------------------------- ### Pop 拦截器:检查已绑定的页面 (AuditPopInterceptor) Source: https://github.com/limuyang2/krouter/blob/main/README.md 实现 IRouterPopInterceptor 接口,通过 chain.request() 获取 PopRequest,可根据 removeTargets 属性检查实际将被关闭的页面,然后调用 chain.proceed() 继续。PopRequest 属性包括 operation(CURRENT、REMOVE 或 BACK_TO)、removeTargets、backToPage、hasResult 和 result。每个 Pop 拦截器阶段最多调用一次 proceed 或 redirect,也可通过 chain.interrupt() 中断。 ```kotlin import io.github.limuyang2.router.IRouterPopInterceptor import io.github.limuyang2.router.PopResponse class AuditPopInterceptor : IRouterPopInterceptor { override suspend fun intercept( chain: IRouterPopInterceptor.Chain, ): PopResponse { val request = chain.request() // 根据 request.removeTargets 检查实际将被关闭的页面。 return chain.proceed() } } ``` -------------------------------- ### navigator.pop { all(UserRoute::class) } Source: https://github.com/limuyang2/krouter/blob/main/README.md 移除所有匹配页面;全部命中时保留原根页。 ```APIDOC ## navigator.pop { all(UserRoute::class) } ### Description 移除所有匹配页面;全部命中时保留原根页。 ### Method pop ### Parameters - **all** (类型、类型集合或 URL) - 必填 - 指定要移除的页面。 ### Request Example ```kotlin navigator.pop { all(UserRoute::class) } ``` ### Response 无直接返回值。 ``` -------------------------------- ### 声明路由页面:HomeRoute 和 UserRoute Source: https://github.com/limuyang2/krouter/blob/main/README.md 定义两个路由页面,分别对应 URL demo://app/home 和 demo://app/user?id=42。HomeRoute 包含一个按钮,点击后导航到 UserRoute 并传递参数 id=42;UserRoute 显示用户 ID 并提供返回按钮。 ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import io.github.limuyang2.router.IRouterEntryProvider import io.github.limuyang2.router.LocalNavigator import io.github.limuyang2.router.anno.Router import io.github.limuyang2.router.anno.RouterParam @Router(scheme = "demo", host = "app", path = "/home") class HomeRoute : IRouterEntryProvider { @Composable override fun UI() { val navigator = LocalNavigator.current Button(onClick = { navigator.push(UserRoute(42L)) }) { Text("打开用户页面") } } } @Router(scheme = "demo", host = "app", path = "/user") class UserRoute( @param:RouterParam("id") val id: Long, ) : IRouterEntryProvider { @Composable override fun UI() { val navigator = LocalNavigator.current Column { Text("用户 ID:$id") Button(onClick = { navigator.pop() }) { Text("返回") } } } } ``` -------------------------------- ### navigator.pop { to() } Source: https://github.com/limuyang2/krouter/blob/main/README.md 保留最近的 HomeRoute,移除其上方绑定的页面。 ```APIDOC ## navigator.pop { to() } ### Description 保留最近的 HomeRoute,移除其上方绑定的页面。 ### Method pop ### Parameters - **to** (类型、URL 或页面实例) - 必填 - 指定要保留的目标页面。 ### Request Example ```kotlin navigator.pop { to() } ``` ### Response 无直接返回值。 ``` -------------------------------- ### navigator.pop { last(UserRoute::class) } Source: https://github.com/limuyang2/krouter/blob/main/README.md 移除最近一个 UserRoute,其上方其他页面保留。 ```APIDOC ## navigator.pop { last(UserRoute::class) } ### Description 移除最近一个 UserRoute,其上方其他页面保留。 ### Method pop ### Parameters - **last** (类型、类型集合、URL 或页面实例) - 必填 - 指定要移除的页面。 ### Request Example ```kotlin navigator.pop { last(UserRoute::class) } ``` ### Response 无直接返回值。 ``` -------------------------------- ### Pop 拦截器:使用 withResult 修改返回值 Source: https://github.com/limuyang2/krouter/blob/main/README.md 只修改返回值时保留原绑定目标,使用 chain.proceed(chain.request().withResult(newValue))。CURRENT 支持改写结果;BACK_TO 需要原请求已配置结果 key 和类型;REMOVE 不支持业务结果。 ```kotlin return chain.proceed(chain.request().withResult(newValue)) ``` -------------------------------- ### Directed Return: Register Consumer with key Source: https://github.com/limuyang2/krouter/blob/main/README.md Registers a Consumer with a specific key inside HomeRoute's UI. This Consumer will receive results directed to that key. ```kotlin // HomeRoute 的 UI 内。 val refreshResult = rememberRouteResult(key = "refresh") { result -> // 使用 result 刷新首页状态。 } ``` -------------------------------- ### navigator.push Source: https://github.com/limuyang2/krouter/blob/main/README.md 发起页面跳转,支持通过页面实例或 URL 指定目标,并可配置去重、清栈、关闭当前页等行为。 ```APIDOC ## navigator.push ### Description 发起页面跳转,支持通过页面实例或 URL 指定目标,并可配置去重、清栈、关闭当前页等行为。 ### Method push ### Parameters #### destination - **destination** (页面实例) - 可选 - 页面实例;非空时优先于 `url`。 #### url - **url** (String) - 可选 - 用于解析路由和查询参数的 URL。 #### extras - **extras** (Map) - 可选 - 额外参数,同名项覆盖 URL 参数。 #### preventDuplicates - **preventDuplicates** (Boolean) - 可选 - 阻止与栈顶页面类型相同的重复跳转。 #### isCleanStack - **isCleanStack** (Boolean) - 可选 - 成功跳转后移除旧页面,仅保留新页面。 #### isPopCurrent - **isPopCurrent** (Boolean) - 可选 - 成功打开新页面后关闭旧 current。 #### greenChannel - **greenChannel** (Boolean) - 可选 - 跳过 Push 拦截器,仍执行目标解析和实例唯一性检查。 ### Request Example ```kotlin navigator.push { destination = UserRoute(42L) preventDuplicates = true isCleanStack = false isPopCurrent = false greenChannel = false } ``` ### Response 无直接返回值。 ``` -------------------------------- ### Compose UI: rememberRouteResult with pushForResult Source: https://github.com/limuyang2/krouter/blob/main/README.md Recommended way to receive route results in Compose UI. Creates a Consumer via rememberRouteResult and binds it with resultTo in pushForResult. Handles all RouteResult states. Includes the target route that pops with a result. ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import io.github.limuyang2.router.IRouterEntryProvider import io.github.limuyang2.router.LocalNavigator import io.github.limuyang2.router.RouteResult import io.github.limuyang2.router.anno.Router import io.github.limuyang2.router.rememberRouteResult data class UserResult(val saved: Boolean) @Composable fun ResultExample() { val navigator = LocalNavigator.current var feedback by rememberSaveable { mutableStateOf("尚未收到结果") } val resultTo = rememberRouteResult { result -> feedback = when (result) { is RouteResult.Success -> "已保存:${result.value?.saved}" RouteResult.NoResult -> "没有返回业务值" RouteResult.Cancelled -> "结果请求已取消" is RouteResult.TypeMismatch -> "返回类型不匹配" } } Column { Text(feedback) Button( onClick = { navigator.pushForResult(EditUserRoute(), resultTo = resultTo) }, ) { Text("编辑用户") } } } @Router(scheme = "demo", host = "app", path = "/edit-user") class EditUserRoute : IRouterEntryProvider { @Composable override fun UI() { val navigator = LocalNavigator.current Button(onClick = { navigator.pop(UserResult(saved = true)) }) { Text("保存并返回") } } } ``` -------------------------------- ### navigator.pop() Source: https://github.com/limuyang2/krouter/blob/main/README.md 关闭绑定的当前页,不携带业务结果。 ```APIDOC ## navigator.pop() ### Description 关闭绑定的当前页,不携带业务结果。 ### Method pop ### Parameters 无参数。 ### Request Example ```kotlin navigator.pop() ``` ### Response 无直接返回值。 ``` -------------------------------- ### 异步返回时拦截器等待期间新增页面的栈变化 Source: https://github.com/limuyang2/krouter/blob/main/README.md 展示返回目标在进入拦截器前绑定,等待期间新增的页面不属于原请求。放行后关闭原来绑定的 B,保留等待期间打开的 C。 ```text [A, B] B 发起返回,拦截器等待 [A, B, C] 等待期间打开 C [A, C] 放行后关闭原来绑定的 B ``` -------------------------------- ### Directed Return: pop with to Source: https://github.com/limuyang2/krouter/blob/main/README.md Pops the current page and delivers a result directly to HomeRoute using the specified key. Pages above HomeRoute are closed during this operation. ```kotlin navigator.pop { to( result = UserResult(saved = true), key = "refresh", ) } ``` -------------------------------- ### Compose UI: pushForResult with URL and resultTo Source: https://github.com/limuyang2/krouter/blob/main/README.md Shows that the same Consumer created with rememberRouteResult can be used for URL-based navigation. The resultTo parameter is passed to pushForResult with a URL string. ```kotlin navigator.pushForResult("demo://app/edit-user", resultTo = resultTo) ``` -------------------------------- ### 定义带 @RouterParam 的路由页面 ArticleRoute Source: https://github.com/limuyang2/krouter/blob/main/README.md 使用 @Router 声明 scheme、host 和 path,@RouterParam 可标记构造参数或可变属性。URL 查询参数会注入对应字段,手动提供的同名 extras 优先于 URL 查询参数。 ```kotlin @Router(scheme = "demo", host = "app", path = "/article") class ArticleRoute( @param:RouterParam("id") val id: Long, ) : IRouterEntryProvider { @RouterParam("source") var source: String = "" @Composable override fun UI() { Text("文章:$id,来源:$source") } } ``` -------------------------------- ### navigator.pop(value) Source: https://github.com/limuyang2/krouter/blob/main/README.md 关闭绑定的当前页并返回业务值。 ```APIDOC ## navigator.pop(value) ### Description 关闭绑定的当前页并返回业务值。 ### Method pop ### Parameters - **value** (任意类型) - 必填 - 要返回的业务值。 ### Request Example ```kotlin navigator.pop(value) ``` ### Response 无直接返回值。 ``` -------------------------------- ### Non-Compose: pushForResult with onResult callback Source: https://github.com/limuyang2/krouter/blob/main/README.md For non-Compose business code, use the onResult callback parameter. The callback captures the closure at request time and is not replaced during recomposition. ```kotlin fun openEditor( navigator: Navigator, onResult: (RouteResult) -> Unit, ) { navigator.pushForResult(EditUserRoute(), onResult = onResult) } ``` -------------------------------- ### IRouterPopInterceptor.intercept Source: https://github.com/limuyang2/krouter/blob/main/README.md Defines a pop interceptor that can inspect the pages to be closed and optionally modify the result or redirect to a different target. ```APIDOC ## IRouterPopInterceptor.intercept ### Description Intercepts a pop operation, allowing inspection of the pages to be closed and modification of the result or target. ### Method suspend fun intercept(chain: IRouterPopInterceptor.Chain): PopResponse ### Parameters - **chain** (IRouterPopInterceptor.Chain) - Required - The interceptor chain providing access to the request and the ability to proceed, redirect, or interrupt. ### Request Example ```kotlin class AuditPopInterceptor : IRouterPopInterceptor { override suspend fun intercept( chain: IRouterPopInterceptor.Chain, ): PopResponse { val request = chain.request() // 根据 request.removeTargets 检查实际将被关闭的页面。 return chain.proceed() } } ``` ### PopRequest Properties - **operation** (String) - Required - One of `CURRENT`, `REMOVE`, or `BACK_TO`. - **removeTargets** (List) - Required - The bound instances to be removed, ordered from stack top to bottom at resolution time. - **backToPage** (Any?) - Optional - The target page to keep for `BACK_TO`; null for other operations. - **hasResult** (Boolean) - Required - Whether a business value was explicitly provided; explicit null also counts as true. - **result** (Any?) - Optional - The original business value; use with `hasResult` to interpret null. ### Redirect Example ```kotlin return chain.redirect { to() } ``` ### Proceed with Result Example ```kotlin return chain.proceed(chain.request().withResult(newValue)) ``` ### Response Returns a PopResponse indicating the result of the pop operation. ### Notes - `CURRENT` supports rewriting the result; `BACK_TO` requires the original request to have a result key and type configured; `REMOVE` does not support business results. - Each pop interceptor stage may call `proceed` or `redirect` at most once, or `chain.interrupt()` to abort. - When selection conditions change, targets are re-resolved; identical conditions preserve the originally bound instances. ```