[Android开发]一个轻量化路由Router库

LightRouter 的Github地址

当前项目是结合和 AndroidAOPModuleCommunication来使用的,主打一个轻量易用 ,本文不具体介绍这两个框架其他的用法,旨在介绍如何利用这两个框架配置出 类似于 ARouter 等框架的用法,如有需要点击下方链接可查看
这两者结合使用,可具备 Router 的以下几个功能
  • 基础的 Activity 跳转,Fragment 的获取
  • 通过 Url 打开页面
  • 跳转页面中间的拦截器
  • 解耦 各个 module 的 伪Application
  • 暴露服务

使用步骤

在开始之前可以给项目一个Star吗?非常感谢,你的支持是我唯一的动力。欢迎Star和Issues!

一、引入插件

1、在 项目根目录build.gradle里依赖插件

新版本写法

buildscript {
    dependencies {
        //必须项 👇
        classpath 'io.github.FlyJingFish.ModuleCommunication:module-communication-plugin:1.1.8'
    }
}
plugins {
    //必须项 👇下边版本号根据你项目的 Kotlin 版本决定👇
    id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
    //必须项 👇需要配合 AndroidAOP 使用
    id 'io.github.FlyJingFish.AndroidAop.android-aop' version '1.8.2' apply true
}

或老版本写法

buildscript {
    dependencies {
        //必须项 👇
        classpath 'io.github.FlyJingFish.ModuleCommunication:module-communication-plugin:1.1.8'
        //必须项 👇
        classpath 'io.github.FlyJingFish.AndroidAop:android-aop-plugin:1.8.2'
    }
}
plugins {
    //必须项 👇下边版本号根据你项目的 Kotlin 版本决定👇
    id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
}
// 👇加上这句自动为所有module“预”配置debugMode
apply plugin: "android.aop"

Kotlin 和 KSP Github 的匹配版本号列表

2、在 appbuild.gradle添加

//必须项 👇
plugins {
    ...
    id 'android.aop'//最好放在最后一行
}

3、在根目录gradle.properties 添加如下设置

对于当前路由项目来说 debugMode 就够用了,debugMode 打包速度快,如果您还用到 AndroidAOP 的其他功能,点此看具体用法

androidAop.debugMode=true 

4、在 使用路由的modulebuild.gradle里依赖插件

plugins {
    id 'communication.export'
}

5、引入依赖库

dependencies {
    //必须项 👇AndroidAOP 提供支持
    implementation 'io.github.FlyJingFish.AndroidAop:android-aop-core:1.8.2'
    implementation 'io.github.FlyHingFish.AndroidAop:android-aop-annotation:1.8.2'
    
    //使用路径的方式跳转则必须添加(使用通信module的则不加也可以)
    implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-route:1.1.8'
    
    //这一项在你配置 communication.export 时就已经自动引入,如没有配置则需引入
    implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-annotation:1.1.8'
    
    //使用拦截器(可选项)
    implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-intercept:1.1.8'
}

开始使用

路由主要用到下边两个注解

  • @Route 路由页面

  • @RouteParams 路由页面参数

示例
  • 一、配置页面
// activity 
@Route("/user/UserActivity")
class UserActivity : AppCompatActivity() {

    @delegate:RouteParams("params1")
    val params1 :String ? by lazy(LazyThreadSafetyMode.NONE) {
        intent.getStringExtra("params1")
    }

    @delegate:RouteParams("params2")
    val params2 :User ? by lazy(LazyThreadSafetyMode.NONE) {
        intent.getSerializableExtra("params2") as User
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)
        Log.e("UserActivity","params1=$params1,params2=$params2")
    }
}

//fragment
@Route("/user/UserFragment")
class UserFragment : Fragment() {
    @delegate:RouteParams("params1")
    val params1 :String ? by lazy(LazyThreadSafetyMode.NONE) {
        arguments?.getString("params1")
    }

    @delegate:RouteParams("params2")
    val params2 :User ? by lazy(LazyThreadSafetyMode.NONE) {
        arguments?.getSerializable("params2") as User
    }
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val binding = ActivityUserBinding.inflate(inflater,container,false)
        Log.e("UserFragment","params1=$params1,params2=$params2")
        return binding.root
    }

}
  • 在其他 module 调用

跳转 Activity

//在 module-communication-route 可以使用路径跳转
ModuleRoute.builder("/user/UserActivity")
    .putValue("params1","lalla")
    .putValue("params2",user)
    .go(this)

//在自己的 module 下也可使用帮助类,帮助类也可跨模块调用需要使用 ModuleCommunication 的通信功能
`LibUser$$Router`.goUser_UserActivity(this,"hahah",user)

获取 Fragment

//在 module-communication-route 可以使用路径拿到 class ,反射新建fragment对象
val clazz = ModuleRoute.builder("/user/UserFragment")
    .getClassByPath()
val fragment : Fragment = clazz?.getDeclaredConstructor()?.newInstance() as Fragment

//在自己的 module 下也可使用帮助类,帮助类也可跨模块调用需要使用 ModuleCommunication 的通信功能
val fragment : Fragment = `LibUser$$Router`.newUser_UserFragment("lalala",user) as Fragment

按模块去加载页面,减少初始化

// builder 第一个参数传 module 名,这个名来自于帮助类 `LibUser$$Router` 的前半截 
ModuleRoute.builder("LibUser","/user/UserActivity")
    .putValue("params1","lalla")
    .putValue("params2",user)
    .go(this)

  • 想要让 ModuleRoute 起作用,还需配置以下信息

object CollectApp {
    private val allRouteClazz = mutableSetOf<BaseRouterClass>()

    /**
     * 这一步才可以收集到所有的路由路径信息
     */

    @AndroidAopCollectMethod
    @JvmStatic
    fun collectRouterClass(sub: BaseRouterClass){
        Log.e("CollectIntercept","collectRouterClass=$sub")
        allRouteClazz.add(sub)
    }


    fun onCreate(application: Application){
        Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
        //设置全部路由路径信息,这样ModuleRoute才可以起作用
        ModuleRoute.autoAddAllRouteClass(allRouteClazz)
    }
}
//初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        //一键初始化所有需要的信息
        CollectApp.onCreate(this)
    }
}

二、通过URL跳转
class SchemeDistributionActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val uri = intent.data
        uri?.let {
            ModuleRoute.builder(it)?.go()
        }
        finish()
    }
}

在 AndroidManifest.xml 中配置

<activity android:name=".SchemeDistributionActivity"
    android:exported="true">
    <!-- Scheme -->
    <intent-filter>
        <data
            android:host="test.flyjingfish.com"
            android:scheme="lightrouter"/>

        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>

ModuleRoute 会自动解析 uri ,会根据您当初设置的各项参数去解析跳转页面的参数,并且不限制类型,除了8种基本数据类型和String类型之外,其他的对象类型你只需要把对象数据转化为Json数据即可,例如

<script type="text/javascript">
    function onClick() {
        window.location.href =
            "lightrouter://test.flyjingfish.com/user/DetailActivity?age=10&name=hahahaha&aChar=a&user={\"id\":\"1111\",\"name\":\"哈哈😄\"}"
    }
</script>
三、拦截器的使用
  • 定义拦截器

class UserIntercept : RouterIntercept {
    //跳转页面时会先进入这里
    override fun onIntercept(proceed: Proceed) {
        Log.e("onIntercept","--UserIntercept--${proceed.path},params = ${proceed.paramsMap},byPath = ${proceed.byPath}")
        //调用下边这句才会进入下一个拦截器或跳转页面,支持异步获取网络数据后再调用
        proceed.proceed()
    }
    //返回序号,存在多个拦截器时会按照这个顺序依次进入拦截器
    override fun order(): Int {
        return 2
    }
}
  • 初始化拦截器
object CollectApp {
    private val allRouterIntercept = mutableSetOf<RouterIntercept>()

    /**
     * 这一步才可以收集到所有的拦截器
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectIntercept(sub: RouterIntercept){
        Log.e("CollectIntercept","collectIntercept=$sub")
        allRouterIntercept.add(sub)
    }

    fun onCreate(application: Application){
        Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
        //设置全部的拦截器让其起作用
        RouterInterceptManager.addAllIntercept(allRouterIntercept)
    }
}
//初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        //一键初始化所有需要的信息
        CollectApp.onCreate(this)
    }
}

四、为每个 module 配置 伪Application
// 自己定义一个 IApplication 
interface IApplication {
    fun onCreate(application: Application)
}
// 在各自 module 下实现这个接口
class UserApplication:IApplication {
    override fun onCreate(application: Application) {
        Log.e("IApplication",""+UserApplication::class.java.name)
    }
}
object CollectApp {
    private val allIApplication = mutableSetOf<IApplication>()

    /**
     * 收集所有的 module 的 IApplication 类
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectIApplication(sub: IApplication){
        Log.e("CollectIntercept","collectIApplication=$sub")
        allIApplication.add(sub)
    }

    fun onCreate(application: Application){
        Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
        //循环调用各个 module 的 IApplication.onCreate
        allIApplication.forEach {
            it.onCreate(application)
        }
    }
}
//初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        //一键初始化所有需要的信息
        CollectApp.onCreate(this)
    }
}
五、暴露服务
  • 定义接口
@ExposeInterface
interface LoginHelper {
    fun getLogin():Login
}
  • 定义实现类
@ImplementClass(LoginHelper::class)
class LoginHelperImpl:LoginHelper {
    override fun getLogin(): Login {
        return Login("username:1111")
    }
}
  • 使用
val loginHelper = ImplementClassUtils.getSingleInstance<LoginHelper>(LoginHelper::class)
val login = loginHelper?.getLogin()

按照其他多数路由框架的设计思路, LoginHelper 是放在 公共 module 的,LoginHelperImpl 则是放在提供服务的 module ,但 ModuleCommunication,可以将LoginHelper也放在提供服务的 module 下,有兴趣可以去看看

  • 不用反射获取到服务
object CollectApp {
    /**
     * 收集所有的 module 的 @ExposeInterface 共享实现类
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectBindClass(sub: BindClass<*>){
        Log.e("CollectIntercept","collectBindClass=$sub")
        ImplementClassUtils.addBindClass(sub)
    }

    fun onCreate(application: Application){
        
    }
}
//初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        //一键初始化所有需要的信息
        CollectApp.onCreate(this)
    }
}
六、集中配置初始化

上边所有功能都需要初始化,所有的初始化都可以放在一个类里边去,这样便于集中管理。这样写完之后,之后你再加任何 @Route拦截器伪Application非反射服务,都是自动生效的

object CollectApp {
    private val allRouterIntercept = mutableSetOf<RouterIntercept>()
    private val allIApplication = mutableSetOf<IApplication>()
    private val allRouteClazz = mutableSetOf<BaseRouterClass>()

    /**
     * 这一步才可以收集到所有的拦截器
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectIntercept(sub: RouterIntercept){
        Log.e("CollectIntercept","collectIntercept=$sub")
        allRouterIntercept.add(sub)
    }

    /**
     * 这一步才可以收集到所有的路由路径信息
     */

    @AndroidAopCollectMethod
    @JvmStatic
    fun collectRouterClass(sub: BaseRouterClass){
        Log.e("CollectIntercept","collectRouterClass=$sub")
        allRouteClazz.add(sub)
    }

    /**
     * 收集所有的 module 的 IApplication 类
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectIApplication(sub: IApplication){
        Log.e("CollectIntercept","collectIApplication=$sub")
        allIApplication.add(sub)
    }

    /**
     * 设置此项是为了 ImplementClassUtils 不用反射
     */
    @AndroidAopCollectMethod
    @JvmStatic
    fun collectBindClass(sub: BindClass<*>){
        Log.e("CollectIntercept","collectBindClass=$sub")
        ImplementClassUtils.addBindClass(sub)
    }

    fun onCreate(application: Application){
        Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
        //设置全部的拦截器让其起作用
        RouterInterceptManager.addAllIntercept(allRouterIntercept)
        //设置全部路由路径信息,这样ModuleRoute才可以起作用
        ModuleRoute.autoAddAllRouteClass(allRouteClazz)
        //循环调用各个 module 的 IApplication.onCreate
        allIApplication.forEach {
            it.onCreate(application)
        }
        //设置这一项跳转页面可以不需要上下文
        ModuleRoute.setApplication(application)
    }
}
//初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        //一键初始化所有需要的信息
        CollectApp.onCreate(this)
    }
}

混淆规则

混淆规则遵循以下两个库的混淆规则:

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值