SRouter
A framework of componentization related to Android platform
Install / Use
/learn @SharryChoo/SRouterREADME
SRouter
SRouter 是一款对 Android 端的提供渐进式组件化服务的路由框架
功能介绍
- 支持路由模块动态装载与卸载
- 支持自定义页面跳转时的 Transaction 动画
- 支持通过 URL 进行路由寻址
- 支持通过接口中的模板方法进行路由寻址(与 Retrofit 类似)
- 提供局部和全局两种类型的拦截器, 以满足不同场景的 Hook 需求
- 局部拦截器包含路由拦截器、页面拦截器和模板方法拦截器
- 支持拦截器按照优先级排序
- 支持 Activity/Fragment 中 Intent 数据自动注入
- 支持回调获取目标页面的 ActivityResult
- 支持通过路由获取 原生/AppCompat/AndroidX 包下的 Fragment
- 支持添加寻址回调适配器, 可实现与 RxJava 无缝衔接
- 支持为 PendingIntent 构建转发 Intent, 可通过路由转发到目标页面
安装指南
Step 1
在工程的根目录的 build.gradle 中添加 jitpack 的 maven 仓库
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Step 2
在工程的 base 库中的 build.gradle 添加如下依赖
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
......
// SRouter 依赖
api "com.github.SharryChoo.SRouter:srouter-support:x.x.x"
}
请确保工程中的业务 module 和 app 库依赖于你的 base 库
Step 3
在使用到 SRouter 提供的注解的 module 中的 build.gradle 添加如下依赖
Java module
apply plugin: 'com.android.library'
android {
......
defaultConfig {
......
/**
* Java 的 Module 使用该方式进行编译时注解扫描, 不兼容 Kotlin 文件
*/
javaCompileOptions {
annotationProcessorOptions {
arguments = ["moduleName": "替换成当前 Module 唯一标示, 用于组件注册"]
}
}
}
}
dependencies {
......
// Java 的编译时注解处理依赖
annotationProcessor "com.github.SharryChoo.SRouter:srouter-compiler:x.x.x"
}
Kotlin module
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.targetSdkVersion
}
}
/**
* Kotlin 的 Module 使用该方式进行编译时注解扫描, 兼容 Java 文夹
*/
kapt {
arguments {
arg("moduleName", "替换成当前 Module 唯一标示, 用于组件注册")
}
}
dependencies {
......
// Kotlin 的编译时注解处理依赖
kapt "com.github.SharryChoo.SRouter:srouter-compiler:$sRouterVersion"
}
kapt 是支持 Java 代码的, 不用担心 kotlin 与 java 的混编问题
模块依赖关系

基础功能
一) 初始化
SRouter 的初始化操作通过 SRouter.init() 方法执行, 推荐在 BaseApplication 的 onCreate 中进行
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 在 BaseApplication 中调用 init 方法执行初始化操作
SRouter.init(this);
}
}
二) 模块的装载与卸载
SRouter 根据模块的唯一标识进行装载与卸载, 如下所示
// 装载想要使用的 Module
SRouter.registerModules(xxx, ...);
// 卸载要使用的 Module
SRouter.unregisterModules(xxx, ...);
请确保传入的模块标识与 module 中 build.gradle 中声明的描述一致
三) 声明寻址目标
SRouter 通过 @Route 注解声明一个 Class 为一个路由目标地址, 其可作用的 class 如下
- Activity
- Fragment/Fragment(androidx)/Fragment(v4)
- IService: 用于自己实现目标的服务逻辑
@Route(
authority = ModuleConstants.Personal.NAME,
path = ModuleConstants.Personal.PERSONAL_ACTIVITY,
desc = "路由描述"
)
class PersonalActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.personal_activity_personal)
}
}
- authority: 路由作用页面的所属的模块, 不必与当前类所在的 module 名一致, 用于渐进式组件分割
- path: 对应的路径
请确保 authority 与 path 的组合是唯一的
四) 寻址发起
1. 普通寻址
SRouter.request(ModuleConstants.Personal.NAME, ModuleConstants.Personal.PERSONAL_ACTIVITY)
// 设置 Activity 转场动画
.setActivityOptions(ActivityOptionsCompat.makeBasic())
// 跳转参数
.withString("key", "value")
// 跳转时延
.setDelay(1000)
// 执行跳转操作
.navigation(this)
2. URL 寻址
val url = "{Custom u scheme}://found/found_fragment?title=HelloWorld&amount=12.34"
SRouter.request(url)
......
.navigation(this)
url 跳转即 request 构造时不同, 其他使用方式一致
3. 模板方法寻址
SRouter 可通过 @RouteMethod 注解声明一个方法为寻址入口
public interface RouteApi {
/**
* @param context 若无 context 参数, 会使用 application context 跳转
*/
@RouteMethod(
authority = ModuleConstants.Personal.NAME,
path = ModuleConstants.Personal.PERSONAL_ACTIVITY,
)
ICall personalCenter(
Context context,
@QueryParam(key = "content") String content,
@RequestCode int requestCode,
@Flags int activityFlags
);
}
实例化模板方法
val routeApi = SRouter.createApi(RouteApi::class.java)
使用接口进行路由寻址
val cancelable: ICancelable = routeApi.personalCenter(this).call()
使用方式与 Retrofit 的模板接口类似, 使用这种方式可以更快捷、更精准的进行寻址操作
4. 中断寻址
如果你想控制路由跳转的时机, 以及中途取消等操作, 可以使用以下方式
// 获取可跳转的 ICall 对象
val call:ICall = SRouter.request(ModuleConstants.Personal.NAME, ModuleConstants.Personal.PERSONAL_ACTIVITY)
.setActivityOptions(ActivityOptionsCompat.makeBasic())
.newCall(this)
// 自定义跳转时机
val cancelable: ICancelable = call.post(object : IInterceptor.ChainCallback {
override fun onSuccess(response: Response) {
// 寻址成功, 获取 Response
}
override fun onFailed(throwable: Throwable?) {
// 寻址失败
}
override fun onCanceled() {
// 寻址被中途取消了
}
})
// 自定义取消时机
cancelable.cancel()
调用 ICall.call() 方法可以获取到一个 ICancelable 对象, 通过 ICancelable.cancel() 可以在路由寻址过程中执行中断操作
五) 获取寻址结果
1. 获取 ActivityResult
SRouter.request(xxx, xxx)
.setRequestCode(100)
......
.navigation(this) {it: Response ->
if (it.activityResult != null && it.activityResult.resultCode == Activity.RESULT_OK) {
val intent = it.activityResult.data
// todo something.
}
}
navigation 方法支持传入一个 Callback, 当路由成功后可以获取到 Response 对象, 在 Response 中可以获取到你想要的所有数据
- ActivityResult
- Fragment
- Request
2. 获取 Fragment
SRouter.request(xxx, xxx)
.setRequestCode(100)
......
.navigation(this) {it: Response ->
// 获取 Fragment
val fragment: Fragment = it.fragment
}
获取 Fragment 的方式与获取 ActivityResult 是一致的
- 需要指定 Fragment 的类型, 支持 V4 和 Androidx 包下的 Fragment
3. 获取服务
SRouter.request(xxx, xxx)
......
.navigation(this) {it: Response ->
// 获取 IService
val service: IService = it.service
// 同步建立连接, 获取数据
val obj = service.connect();
// 异步建立连接
it.service.connectAsync {
// TODO 获取数据
}
}
获取到 IService 服务之后, 可以调用 IService.connect() 建立连接, 也可以通过 IService.connectAsync() 异步建立连接
- 无论是同步还是异步建立连接, 最终都会返回 Object 对象, 因此 IService 也充当做跨模块提供数据来使用
拦截器使用
SRouter 的所有拦截器均在主线程执行, 提供了局部和全局两种类型的拦截器
- 局部拦截器包含路由拦截器、页面拦截器和模板方法拦截器
- 支持拦截器按照优先级排序
一) 拦截器的定义
拦截器的定义需要实现 IInterceptor 接口
public class PermissionInterceptor implements IInterceptor {
@Override
public void intercept(@NonNull Chain chain) {
// 责任链上下文 ChainContext
ChainContext chainContext = chain.chainContext();
// 路由发起时的 Context
Context context = chainContext.getBaseContext();
// 上游分发的 Request
Request request = chainContext.request;
// 向下分发
chain.dispatch();
}
}
- Chain: 描述分发的责任链
- Chain.chainContext(): 获取责任链的上下文
- 通过上下文对象可以获取上游的所有数据
- chain.dispatch(): 若需要继续往下分发, 需要主动调用该方法
拦截器实现完成之后, 还可以选择使用 @RouteInterceptor 标注, 拓展拦截器优先级排序的功能支持, 如下所示
@RouteInterceptor(
value = ModuleConstants.Personal.PERMISSION_INTERCEPTOR,
priority = 2
)
public class PermissionInterceptor implements IInterceptor {
......
}
- value: 拦截器的唯一标识符 URI
- priority: 拦截器的优先级
- range in [0, 10] 逐级递增, 路由跳转时会根据优先级进行排序
二) 拦截器的使用
SRouter 的拦截器根据使用场景, 可以分为如下几种类型
- 局部拦截器
- 路由拦截器
- 页面拦截器
- 模板方法拦截器
- 全区拦截器
接下来对其使用方式进行逐一介绍
1. 局部拦截器
1) 路由拦截器
路由拦截器是指在构建寻址请求时添加的拦截器
- 支持通过拦截器 URI 添加拦截器
- 通过 URI 添加的拦截器, 可以享受优先级排序
- 支持直接添加拦截器对象
- 这种方式当做最高优先级处理
SRouter.request(xxx, xxx)
// 添加拦截器的 URI
.addInterceptorURI(ModuleConstants.Personal.PERMISSION_INTERCEPTOR)
// 添加拦截器对象
.addInterceptor(new PermissionInterceptor())
......
2) 页面拦截器
页面拦截器集成在了 @Route 注解中, 只支持通过拦截器的 URI 进行添加
- 支持添加多个页面拦截器
@Route(
authority = ModuleConstants.Personal.NAME,
path = ModuleConstants.Personal.PERSONAL_ACTIVITY,
// 指定跳转到该页面, 要经过的拦截器
interceptorURIs = [ModuleConstants.login.LOGIN_INTERCEPTOR],
desc = "个人中心页面"
)
class PersonalActivity : AppCompatActivity() {
}
3) 模板方法拦截器
模板方法拦截器集成到了 @RouteMethod 注解中, 只支持通过拦截器的 URI 进行添加
- 支持添加多个页面拦截器
public interface RouteApi {
@RouteMethod(
authority = ModuleConstants.Personal.NAME,
path = ModuleConstants.Personal.PERSONAL_ACTIVITY,
// 在方法注解中添加静态拦截器
interceptorURIs = ModuleConstants.Personal.PERMISSION_INTERCEPTOR
)
ICall personalCenter(
Context context,
@QueryParam(key = "content") String content,
@RequestCode int requestCode,
@Flags int activityFlags
);
}
2. 全局拦截器
全局拦截器即添加之后作用于全局的拦截器, 使用方式如下
// 添加全局拦截器对象
SRouter.addGlobalInterceptor(xxx);
// 添加全局拦截器 URI
SRouter.addGlobalInterceptorUri(xxx);
全局拦截器可以用来记录路由寻址的数据或者用于进行埋点统计等
三) 执行流程图

拓展
一) 参数注入
如果你不想写 Intent 参数注入的代码, @Query 注解可以帮你完成这个操作
public class FoundFragment extends Fragment {
@Query(key = "title")
String title = "default_title";
@Query(key = "amount")
double amount = 1.0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SRouter.bindQuery(this);
......// 处理后续操作
}
}
二) 回调适配器
如果你习惯了 RxJava 的链式调用, 并为 navigation 是异步回调导致不能链式编写代码而苦恼, 那么这个回调适配器可能会解决你的问题
这里以将 ICall 适配成 RxJava 的 Observab
Related Skills
node-connect
349.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
