继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

KRouter 1.0 发布,支持参数注入和跨平台开发

摇曳的蔷薇
关注TA
已关注
手记 321
粉丝 54
获赞 169

因为时间紧张,KRouter 的第一个版本是在仓促中开发出来的,功能勉强可用而已。最近我有空闲时间重新设计和优化了它,增加了对 Kotlin Multiplatform 和参数注入的支持的功能。实现也被彻底重构了,用 KSP 替换了 ServiceLoader 来收集路由信息。它已经发布到了 Maven Central Repository。

GitHub - 0xZhangKe/KRouter: 轻量且简单的 Kotlin 路由器,基于 ServiceLoader 和 KSP 的。用于 Kotlin 模块间通信。……github.com

作为一个路由框架,它不仅要能够收集路由,还要能将收集到的路由信息提供给路由系统。这就是我为什么在第一个版本中使用了 ServiceLoader 的原因。所以在开发这个新版本时,我最初计划使用 KCP 修改字节码来实现这一功能。经过几天的研究,我发现这种方法还是不行。最后卡在了 KCP 无法读写依赖模块的类文件的问题上。我现在知道的是,KCP 只能读写当前模块的文件,不能读写依赖模块的类文件。KSP 也通过一些复杂的方式实现了类似的功能,相关的文档内容贫乏,不够详细,所以我决定放弃。如果有其他解决方法或建议,请不吝告知。

怎么用:

依然简单明了,与以前一样。

首先标注目标类:

@Destination("screen/main")  
class 主屏幕(@RouteParam("id") val id: String, @RouteParam("name") val name: String): 屏幕

然后,用 KRouter 查找相应的类。

val screen = KRouter.route<Screen>("screen/main?name=zhangke&id=123")
// 屏幕的路由配置

KRouter 目前支持三种注解标签:@Destination@RouteUri,和 @RouterParam

到的地方

正如其名,@Destination 注解标记了路由的目标类,也就是目的地,带有一个参数,表示路由目标地址。

    @目标(AnnotationTarget.CLASS::class)  
    @保留(AnnotationRetention.RUNTIME::class)  
    annotation class Destination(val route: String)

它可以这样用:

    @Destination("屏幕/资料详情/详情")  
    class ProfileDetailScreen 屏幕类
RouterParam

@RouterParam 注解用来标记路由中的参数。被这个注解标记的字段将会自动填充对应的路由参数值。

它还接收一个参数,表示路由中查询字段的名称。KRouter 会根据该字段名解析并赋值。

    // 路由参数注解,用于标记路由参数名称
    @Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)  
    @Retention(AnnotationRetention.RUNTIME)  
    annotation class RouteParam(val name: String)

这里有一个使用它的例子:

@Destination("screen/home/detail")  
class HomeDetailScreen(  
    @RouteParam("id") val id: String,  
) : Screen {  
    // 具有id参数的家庭详情屏幕
}

除了支持构造函数参数注入外,还支持属性注入。

    @Destination("screen/home/detail")  
    class HomeDetailScreen(  
        @RouteParam("id") val id: String,  // 页面标识id
    ) : Screen {  
        @RouteParam("title") var title: String? = null  // 标题
    }

目前,参数类型目前仅限于基本类型和 String。对于更复杂的类型,你可以将对象转换为 JSON 字符串,然后将其编码进路由。

请留意,KSP 当前无法获取参数和属性的默认值。因此,注入字段不能设置默认值。这意味着,如果你设置了注入字段的默认值,而路由中没有包含这个参数,那么这个默认值就会被忽略。

技术术语:路由URI

带有此注解的参数或属性将被赋值为完整的路由路径。由于@RouterParam仅适用于字段注入,对于更复杂的解析情况,可以使用@RouteUri来获取完整的路由路径。

KRouterModule模块

KRouterModule 是一个用于实现特定路由功能的接口,它。你可以通过 KRouter 类动态添加自定义模块。默认情况下,它会优先使用动态添加的模块;如果路由失败,则会退回到 KRouter 自带的路由。

接口 KRouterModule {  
   fun 路由(uri: String): Any?  // 路由到指定的URI并返回任意类型的结果
}
添加依赖

KRouter 提供了两个 KSP 插件。

  • krouter-collecting-compiler: 收集路由相关的数据,用于非主模块的。
  • krouter-reducing-compiler: 汇总来自各个模块的路由信息,仅用于主模块(如应用程序模块)。
    // 在非主模块中使用  
    ksp("io.github.0xzhangke:krouter-collecting-compiler:$latest_version")  
    // 在主模块中使用  
    ksp("io.github.0xzhangke:krouter-reducing-compiler:$latest_version")

此外,还有一个注解模块和运行时组件。

  • krouter-runtime: 运行时模块,提供 KRouterKRouterModule 注解及相关的注解支持。

  • krouter-annotation: 注解模块,仅包含注解,没有提供任何类。
    // 仅需使用注解的模块  
    implementation("io.github.0xzhangke:krouter-runtime:$latest_version")  
    // 需要路由功能的模块可以直接  
    implementation("io.github.0xzhangke:krouter-annotation:$latest_version")
实现细节

首先,collecting-compiler 插件(编译器)收集模块内所有路由目标类的信息,并生成一个属于当前模块的 KRouterModule。生成的类可能如下:

    public class RouterCollection_1726153189290() : KRouterModule {  
        override fun route(uri: String): Any? {  
            val routerUri = com.zhangke.krouter.internal.KRouterUri.create(uri)  
            return when (routerUri.baseUrl) {  
                "screen/home/detail" -> {  
                    com.zhangke.krouter.sample.home.HomeDetailScreen(  
                        id = routerUri.requireQuery("id"),  
                    )  
                }  
                "screen/home/landing" -> {  
                    com.zhangke.krouter.sample.home.HomeLandingScreen(  
                        router = uri,  
                    )  
                }  
                else -> null  
            }  
        }  
    }

所有依赖于 collecting-compiler 插件的模块,都会生成这样一个类。

然后,在主项目模块(通常是 app 模块),需要引入 reducing-compiler 插件。此插件生成一个固定包名和类名的类,收集 collecting-compiler 生成的全部类,并将这些类添加至新类中。

    public class AutoReducingModule() : KRouterModule {  

      private val moduleList: List<KRouterModule> = listOf<KRouterModule>(  
              com.zhangke.krouter.generated.RouterCollection_1726153189283(),  
              com.zhangke.krouter.generated.RouterCollection_1726153189290(),  
              com.zhangke.krouter.generated.RouterCollection_1726153189284(),  
              com.zhangke.krouter.generated.RouterCollection_1726153189709()  
          )  

      override fun route(uri: String): Any? = moduleList.firstNotNullOfOrNull { it.route(uri) }  
    }

运行时,KRouter 通过反射创建该类,并将路由处理交给该类中的实现来处理。这样就完成了整个路由的收集和实现。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP