ARouter介绍
1. 概览
Android平台中对页面、服务提供路由功能的中间件,我的目标是 —— 简单且够用。
2. 功能
- 支持直接解析标准URL进行跳转,并自动注入参数到目标页面中
- 支持多模块工程使用
- 支持添加多个拦截器,自定义拦截顺序
- 支持依赖注入,可单独作为依赖注入框架使用
- 支持InstantRun
- 支持MultiDex(Google方案)
- 映射关系按组分类、多级管理,按需初始化
- 支持用户指定全局降级与局部降级策略
- 页面、拦截器、服务等组件均自动注册到框架
- 支持多种方式配置转场动画
- 支持获取Fragment
- 完全支持Kotlin以及混编
- 支持第三方 App 加固(使用 arouter-register 实现自动注册)
3. 典型应用
- 从外部URL映射到内部页面,以及参数传递与解析
- 跨模块页面跳转,模块间解耦
- 拦截跳转过程,处理登陆、埋点等逻辑
- 跨模块API调用,通过控制反转来做组件解耦
4. 接入
添加依赖配置
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [ moduleName : project.getName() ] } } } } dependencies { // 替换成最新版本, 需要注意的是api // 要与compiler匹配使用,均使用最新版可以保证兼容 compile 'com.alibaba:arouter-api:x.x.x' annotationProcessor 'com.alibaba:arouter-compiler:x.x.x' ... }
添加注解
// 在支持路由的页面上添加注解(必选) // 这里的路径需要注意的是至少需要有两级,/xx/xx @Route(path = "/test/activity") public class YourActivity extend Activity { ... }
Init SDK
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效 ARouter.openLog(); // 打印日志 ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) } ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
发起路由
// 1. 应用内简单的跳转(通过URL跳转在'进阶用法'中) ARouter.getInstance().build("/test/activity").navigation(); // 2. 跳转并携带参数 ARouter.getInstance().build("/test/1") .withLong("key1", 666L) .withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation();
Add Proguard
-keep public class com.alibaba.android.arouter.routes.**{*;} -keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;} # 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口 -keep interface * implements com.alibaba.android.arouter.facade.template.IProvider # 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现 -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
使用 Gradle 插件实现路由表的自动加载(选用)
apply plugin: 'com.alibaba.arouter' buildscript { repositories { jcenter() } dependencies { classpath "com.alibaba:arouter-register:1.0.0" } }
通过 ARouter 提供的注册插件进行路由表的自动加载,默认通过扫描 dex 的方式 进行加载通过 gradle 插件进行自动注册可以缩短初始化时间解决应用加固导致无法直接访问 dex 文件,初始化失败的问题,需要注意的是,该插件必须搭配 api 1.3.0 使用!
5. 使用
URL跳转
// 新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter即可 public class SchameFilterActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = getIntent().getData(); ARouter.getInstance().build(uri).navigation(); finish(); } }
<!-- AndroidManifest.xml --> <activity android:name=".activity.SchameFilterActivity"> <!-- Schame --> <intent-filter> <data android:host="m.aliyun.com" android:scheme="arouter"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> </intent-filter> </activity>
Router跳转
//Router 跳转 TestObj testObj = new TestObj("Rose", 777); ARouter.getInstance().build("/test/activity1") .withString("name", "老王") .withInt("age", 18) .withBoolean("boy", true) .withObject("obj", testObj) .navigation(); //参数自动注入 // 为每一个参数声明一个字段,并使用 @Autowired 标注 // URL中不能传递Parcelable类型数据,通过ARouter api可以传递Parcelable对象 @Route(path = "/test/activity") public class Test1Activity extends Activity { @Autowired public String name; @Autowired int age; @Autowired(name = "girl") // 通过name来映射URL中的不同参数 boolean boy; @Autowired TestObj obj; // 支持解析自定义对象,URL中使用json传递,需要序列化和反序列化服务接口支持 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); // ARouter会自动对字段进行赋值,无需主动获取 Log.d("param", name + age + boy); } } // 如果需要传递自定义对象,需要实现 SerializationService,并使用@Route注解标注(方便用户自行选择序列化方式),例如: @Route(path = "/service/json") public class JsonServiceImpl implements SerializationService { @Override public void init(Context context) { } @Override public <T> T json2Object(String text, Class<T> clazz) { return JSON.parseObject(text, clazz); } @Override public String object2Json(Object instance) { return JSON.toJSONString(instance); } }
多模块使用
只需要在对应Module的gradle文件添加如下配置即可
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [ moduleName : project.getName() ] } } } } dependencies { // 替换成最新版本, 需要注意的是api // 要与compiler匹配使用,均使用最新版可以保证兼容 compile 'com.alibaba:arouter-api:x.x.x' annotationProcessor 'com.alibaba:arouter-compiler:x.x.x' ... }
支持添加多个拦截器,自定义拦截顺序
可以在跳转前做些预处理操作
// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查 // 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行 @Interceptor(priority = 7) public class Test1Interceptor implements IInterceptor { Context mContext; @Override public void process(final Postcard postcard, final InterceptorCallback callback) { //拦截特定路由,必须调用callback.onContinue/onInterrupt中一个以归还控制权 if ("/test/activity4".equals(postcard.getPath())) { if(needIntercept){ if(needInterrupt){ //直接中断操作,不跳转了 callback.onInterrupt(null); }else{ //添加额外参数 postcard.withString("extra", "我是在拦截器中附加的参数"); callback.onContinue(postcard); } }else{ callback.onContinue(postcard); } } @Override public void init(Context context) { mContext = context; Log.e("testService", Test1Interceptor.class.getName() + " has init."); } }
支持依赖注入,可单独作为依赖注入框架使用
步骤1中其实已涉及到依赖注入
ARouter.getInstance().inject(this);
内部实现其实是也是主动调用了getIntent.getXxx方法而已
通过依赖注入解耦
服务管理(一) 暴露服务
// 声明接口,其他组件通过接口来调用服务 public interface HelloService extends IProvider { String sayHello(String name); } // 实现接口 @Route(path = "/service/hello", name = "测试服务") public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "hello, " + name; } @Override public void init(Context context) { } }
服务管理(二) 发现服务
public class Test { @Autowired HelloService helloService; @Autowired(name = "/service/hello") HelloService helloService2; HelloService helloService3; HelloService helloService4; public Test() { ARouter.getInstance().inject(this); } public void testService() { // 1. (推荐)使用依赖注入的方式发现服务,通过注解标注字段,即可使用,无需主动获取 // Autowired注解中标注name之后,将会使用byName的方式注入对应的字段,不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务) helloService.sayHello("Vergil"); helloService2.sayHello("Vergil"); // 2. 使用依赖查找的方式发现服务,主动去发现服务并使用,下面两种方式分别是byName和byType helloService3 = ARouter.getInstance().navigation(HelloService.class); helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation(); helloService3.sayHello("Vergil"); helloService4.sayHello("Vergil"); } }
6. 后续
后续会从源码角度分析ARouter的内部实现,让大家对其有更深入的了解