ARout梳理

168 阅读6分钟

本文为过往笔记整理, 在此只作记录,不做严谨的技术分享。

ARout文档

探索 ARouter 原理

阿里 ARouter 全面解析,总有你没了解的

阿里开源路由框架ARouter的源码分析

阿里的ARouter,问几个你“不会”的问题! 利用APT实现Android编译时注解

“终于懂了” 系列:组件化框架 ARouter 完全解析-系列

587163-3ae53ea1047628d6.png

基本使用

集成

gradle配置

android {
    defaultConfig {
        ...
        //纯Java项目  
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
        //Kotlin
        kapt {
            arguments {
                arg("AROUTER_MODULE_NAME", project.getName())
            }
        }      
    }
}
​
//Java项目
annotationProcessor configDependencies.arout_compiler//Kotlin项目
apply plugin: 'kotlin-kapt'
kapt configDependencies.arout_compiler//不能用annotationProcessor,否则无效

IProvider

解耦,暴露服务

interface HelloProvider:IProvider{
    fun sayHello(name:String):String
}
​
// 实现接口
@Route(path = "/common/hello", name = "测试服务")
class HelloProviderImpl : HelloProvider {
    override fun sayHello(name: String): String {
        return "hello, $name"
    }
​
    override fun init(context: Context) {}
}
​
//获取服务:虽然方式一可以不用配置path路径,但还是要使用@Rout注解标注的,否则找不到
//方式一
ARouter.getInstance().navigation(HelloProvider::class.java)
?.initApp(this) 
//方式二
(ARouter.getInstance().build("/common/hello").navigation() as HelloProvider)
?.initApp(this)
​

PathReplaceService

替换URL

// 实现PathReplaceService接口
@Route(path = "/yourservicegroupname/pathReplaceService") 
class PathReplaceServiceImpl : PathReplaceService {
    /**
     * For normal path.
     * @param path raw path
     */
    override fun forString(path: String): String {
        if (path == "/login/loginActivity") {
            return "/share/shareActivity"
        }
        return path // 按照一定的规则处理之后返回处理后的结果
    }
​
    /**
     * For uri type.
     * @param uri raw uri
     */
    override fun forUri(uri: Uri?): Uri? {
        return null // 按照一定的规则处理之后返回处理后的结果
    }
​
    override fun init(context: Context?) {
    }
}
protected Postcard build(String path, String group, Boolean afterReplace) {
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
        if (!afterReplace) {
            //navigation会在providersIndex中寻找自定义路径替换服务
            PathReplaceService pService = ARouter.getInstance()
                                .navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
        }
        return new Postcard(path, group);
    }
}

PretreatmentService

预处理服务,早于拦截器

@Route(path = "/yourservicegroupname/pretreatmentService")
class PretreatmentServiceImpl : PretreatmentService {
    override fun onPretreatment(context: Context, postcard: Postcard): Boolean {
        if (postcard.path == "/share/ShareActivity") {
            val userInfo = DataSource.getInstance(ArouterApplication.application).getUserInfo()
            if (TextUtils.isEmpty(userInfo)) {
                Toast.makeText(application, "还没有登录",LENGTH_SHORT).show()
                return false// 跳转前预处理,如果需要自行处理跳转,该方法返回 false 即可
            }
        }
        return true
    }
​
    override fun init(context: Context) {}
}

在路由navigation之前进行干扰路由,比如干扰在分享之前判断有没有登录

protected Object navigation(Context ct,Postcard pd, int re, NavigationCallback ck) {
    PretreatmentService pretreatmentService = ARouter.getInstance()
                            .navigation(PretreatmentService.class);
    if (null != pretreatmentService 
        && !pretreatmentService.onPretreatment(context, postcard)) {
        // Pretreatment failed, navigation canceled.
        return null;
    }
    ...
}

DegradeService

全局降级策略,没有找到路由地址时调用

@Route(path = "/yourservicegroupname/DegradeServiceImpl")
class DegradeServiceImpl : DegradeService {
    override fun onLost(context: Context, postcard: Postcard) {
        Log.d("DegradeServiceImpl", "没有找到该路由地址:${postcard.path}")
    }
    override fun init(context: Context?) {}
}

navigation中未找到路径,exception catch中:

    if (null != callback) {
        callback.onLost(postcard);
    } else {
        // No callback for this invoke, then we use the global degrade service.
        DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
        if (null != degradeService) {
            degradeService.onLost(context, postcard);
        }
    }

@Interceptor

在跳转之间执行,多个拦截器会按优先级顺序依次执行

@Interceptor(priority = 8, name = "登录拦截")
class LoginInterceptor : IInterceptor {
    override fun process(postcard: Postcard, callback: InterceptorCallback) {
        val path = postcard.path
        if (path == "/share/shareActivity") {
            val userInfo = DataSource.getInstance(ArouterApplication.application).getUserInfo()
            if (TextUtils.isEmpty(userInfo)) {
                callback.onInterrupt(Throwable("还没有登录,去登陆"))
            } else {
                callback.onContinue(postcard)
            }
        }else{
            callback.onContinue(postcard)
        }
    }
​
    override fun init(context: Context?) {
        // 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
        Log.d("LoginInterceptor", "LoginInterceptor初始化了")
    }
}

@Autowired

@Autowired注解使用,得在类的初始化中使用ARouter.getInstance().inject(this)

  • 基本数据类型:正常存入Bundle
  • 自定义数据类型:自定义SerializationService解析为Json,以String方式存入Bundle。取值到json后再解析为自定义数据类型
//携带参数跳转 
ARouter.getInstance().build(ARoutTable.BASE_ACT_TARGET)
        .withString("info", "跳转携带参数")
        .withString("arg1", "arg1")
        .withInt("arg2", 2)
        .withBoolean("arg3", true)
        .withObject("testBean", TestBean("withObject"))
        .withObject("listBean", listBean)
        .withObject("mapStr", mapStr)
        .navigation()   
​
//目标类接收
@Autowired(name = "arg1")
String arg;
@Autowired
int arg2;
@Autowired
boolean arg3;
@Autowired
TestBean testBean;
@Autowired
List<TestBean> listBean;
@Autowired
Map<String, String> mapStr;
@Autowired
ModuleLoginProvider moduleLoginProvider;

存储参数:

//#Postcard
//基本数据类型
public Postcard withString(@Nullable String key, @Nullable String value) {
    mBundle.putString(key, value);
    return this;
}
//自定义类
public Postcard withObject(@Nullable String key, @Nullable Object value) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    mBundle.putString(key, serializationService.object2Json(value));//解析为json,作为String存储
    return this;
}
​
//#SerializationService
//传递自定义对象时,需新建SerializationService类,并自定义解析方式
@Route(path = ARoutTable.BASE_SERVICE_SERIALIZATION)
class JsonServiceImpl: SerializationService {
    private lateinit var mGson: Gson
​
    override fun init(context: Context?) {
        KLog.d("", "全局序列化服务")
        mGson = Gson()
    }
​
    //跳转传参时:将自定义类参数,转为json,以String类型存入Bundle
    override fun object2Json(instance: Any?): String {
        return mGson.toJson(instance).apply {
            KLog.d("", "instance: $instance, result: $this")
        }
    }
​
    override fun <T : Any?> json2Object(input: String?, clazz: Class<T>?): T {
        return mGson.fromJson(input, clazz).apply {
            KLog.d("", "input: $input, clazz: $clazz, result: $this")
        }
    }
  //inject注解时:将json转为自定义类型
    override fun <T : Any?> parseObject(input: String?, clazz: Type?): T {
        val result: T = mGson.fromJson(input, clazz)
        KLog.d("", "input: $input, clazz: $clazz, result: $result")
        return result
    }
}
​
​
//将对象转换为Json
[object2Json ] instance: TestBean{name='withObject'}, result: {"age":18,"name":"withObject"}
[object2Json ] instance: [TestBean{name='list_0'}, TestBean{name='list_1'}, TestBean{name='list_2'}, TestBean{name='list_3'}, TestBean{name='list_4'}, TestBean{name='list_5'}], result: [{"age":18,"name":"list_0"},{"age":18,"name":"list_1"},{"age":18,"name":"list_2"},{"age":18,"name":"list_3"},{"age":18,"name":"list_4"},{"age":18,"name":"list_5"}]
[object2Json ] instance: {str_key=str_value}, result: {"str_key":"str_value"}
​
//解析Json转为自定义类
[parseObject ] input: {"age":18,"name":"withObject"}, clazz: class com.varmin.modulebase.arout.TestBean, result: TestBean{name='withObject'}
[parseObject ] input: [{"age":18,"name":"list_0"},{"age":18,"name":"list_1"},{"age":18,"name":"list_2"},{"age":18,"name":"list_3"},{"age":18,"name":"list_4"},{"age":18,"name":"list_5"}], clazz: java.util.List<com.varmin.modulebase.arout.TestBean>, result: [TestBean{name='list_0'}, TestBean{name='list_1'}, TestBean{name='list_2'}, TestBean{name='list_3'}, TestBean{name='list_4'}, TestBean{name='list_5'}]
[parseObject ] input: {"str_key":"str_value"}, clazz: java.util.Map<java.lang.String, java.lang.String>, result: {str_key=str_value}

参数:解析、赋值

  • 把json数据通过SerializationService转换为自定义类对象
public class ARoutTargetActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;
​
  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    ARoutTargetActivity substitute = (ARoutTargetActivity)target;
    //基本数据类型赋值  
    substitute.arg = substitute.getIntent().getExtras() == null ? substitute.arg : substitute.getIntent().getExtras().getString("arg1", substitute.arg);
    substitute.arg2 = substitute.getIntent().getIntExtra("arg2", substitute.arg2);
    substitute.arg3 = substitute.getIntent().getBooleanExtra("arg3", substitute.arg3);
    //自定义数据类型解析  
    if (null != serializationService) {
      substitute.testBean = serializationService.parseObject(substitute.getIntent().getStringExtra("testBean"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestBean>(){}.getType());
    }
    if (null != serializationService) {
      substitute.listBean = serializationService.parseObject(substitute.getIntent().getStringExtra("listBean"), new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestBean>>(){}.getType());
    }
    if (null != serializationService) {
      substitute.mapStr = serializationService.parseObject(substitute.getIntent().getStringExtra("mapStr"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Map<String, String>>(){}.getType());
    }
    substitute.moduleLoginProvider = ARouter.getInstance().navigation(ModuleLoginProvider.class);
  }
}

源码分析

编译后源码

Java项目生成的代理类路径:

image-20210408174119984.png

Kotlin项目生成的代理类路径:

image-20210408174229812.png

编译后的文件如下,在运行中ARout框架即可找到这些类,运行、赋值、跳转...

//以分组名为key,存入该分组的管理类Class
public class ARouter$$Root$$ModuleBase implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("base", ARouter$$Group$$base.class);
    //...  
    routes.put("app", ARouter$$Group$$app.class);
    routes.put("auto", ARouter$$Group$$auto.class);
    routes.put("award", ARouter$$Group$$award.class);
  }
}
//当前base下:Activity、IProvider的class
public class ARouter$$Group$$base implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/base/act/target", 
              RouteMeta.build(RouteType.ACTIVITY, 
                              ARoutTargetActivity.class, 
                              "/base/act/target", "base", //分组
                              new java.util.HashMap<String, Integer>(){//Autowired注解的变量
                                  {put("arg3", 0); 
                                   put("arg2", 3); 
                                   put("listBean", 11); 
                                   put("arg1", 8); 
                                   put("mapStr", 11); 
                                   put("testBean", 11); }}, 
                              -1, 
                              -2147483648));
    atlas.put("/base/service/degrade", 
              RouteMeta.build(RouteType.PROVIDER, 
                              DegradeServiceImpl.class, //降级策略服务
                              "/base/service/degrade", "base", 
                              null, -1, -2147483648));
    atlas.put("/base/service/pretreatment", 
              RouteMeta.build(RouteType.PROVIDER, 
                              PretreatmentServiceImpl.class, //预处理服务
                              "/base/service/pretreatment", "base", 
                              null, -1, -2147483648));
    atlas.put("/base/service/serialization", 
              RouteMeta.build(RouteType.PROVIDER, 
                              JsonServiceImpl.class, //自定义类解析
                              "/base/service/serialization", "base", 
                              null, -1, -2147483648));
  }
}
//当前Module下的拦截器
public class ARouter$$Interceptors$$ModuleBase implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(5, LoginInterceptor.class);
  }
}
//当前Module下的IProvider服务
public class ARouter$$Providers$$ModuleBase implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
    providers.put("com.alibaba.android.arouter.facade.service.DegradeService", 
                  RouteMeta.build(RouteType.PROVIDER, 
                                  DegradeServiceImpl.class, 
                                  "/base/service/degrade", "base", 
                                  null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.facade.service.PretreatmentService", 
                  RouteMeta.build(RouteType.PROVIDER, 
                                  PretreatmentServiceImpl.class, 
                                  "/base/service/pretreatment", "base", 
                                  null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.facade.service.SerializationService", 
                  RouteMeta.build(RouteType.PROVIDER, 
                                  JsonServiceImpl.class, 
                                  "/base/service/serialization", "base", 
                                  null, -1, -2147483648));
  }
}

init()

  • 如果是arouter-register自动加载的路由表,设置registerByPlugin=true,不执行以下代码
  • 如果不是自动加载的路由表,则通过反射找到编译生成的文件,将文件内保存的信息存入Warehouse的各个map中
//ARout.java
public static void init(Application application) {
    if (!hasInit) {
        hasInit = _ARouter.init(application);
        if (hasInit) {
            _ARouter.afterInit();
        }
    }
}
​
//InterceptorServiceImpl是ARout内部实现类,会在navigation方法最后,遍历自定义拦截器进行处理
static void afterInit() {
    interceptorService = (InterceptorService) ARouter.getInstance()
        .build("/arouter/service/interceptor")
        .navigation();
}
//LogisticsCenter.java
public synchronized static void init(Context context, ThreadPoolExecutor tpe) {
    mContext = context;
    executor = tpe;
​
    try {
        long startInit = System.currentTimeMillis();
        //Gradle加载路由表,会把registerByPlugin设置为true;效率比扫描dex文件获取class快得多
        loadRouterMap();
        if (registerByPlugin) {
            logger.info(TAG, "Load router map by arouter-auto-register plugin.");
        } else {
            Set<String> routerMap;
            // debug 或 新的版本code/name
            if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                // These class was generated by arouter-compiler.
                //将编译产生的class文件中的类放到SP中,方便下次直接取
                //扫描dex文件过滤出ARout需要的class文件,过程慢
                /*ROUTE_ROOT_PAKCAGE = com.alibaba.android.arouter.routes*/
                routerMap = ClassUtils.getFileNameByPackageName(mContext,ROUTE_ROOT_PAKCAGE);
                if (!routerMap.isEmpty()) {
                    context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE)
                        .edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                }
                
                PackageUtils.updateVersion(context);  
            } else {
                logger.info(TAG, "Load router map from cache.");
                //从sp中直接取class类
                routerMap = new HashSet<>(getSharedPreferences(AROUTER_SP_CACHE_KEY, ...)
                                          .getStringSet(AROUTER_SP_KEY_MAP, new HashSet()));
            }
​
            logger.info(TAG, "Find router map finished, map size = " + routerMap.size()
                        + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
            startInit = System.currentTimeMillis();
​
            for (String className : routerMap) {
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + 
                                         SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                    //将ARouter$$Root$$ModuleName对应的配置存入groupsIndex
                    ((IRouteRoot) (Class.forName(className).getConstructor()
                                   .newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + 
                                                SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                    // 将ARouter$$Interceptors$$ModuleName存入interceptorsIndex
                    ((IInterceptorGroup) (Class.forName(className).getConstructor()
                                        .newInstance())).loadInto(Warehouse.interceptorsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + 
                                                SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    // 将ARouter$$Providers$$ModuleName存入providersIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor()
                                       .newInstance())).loadInto(Warehouse.providersIndex);
                }
            }
        }
​
        logger.info(TAG, "Load root element finished, cost " 
                    + (System.currentTimeMillis() - startInit) + " ms.");
​
       
}

build()

  • 替换path或URI
protected Postcard build(String path, String group, Boolean afterReplace) {
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
        if (!afterReplace) {
            //navigation会在providersIndex中寻找自定义路径替换服务
            PathReplaceService pService = ARouter.getInstance()
                                .navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
        }
        return new Postcard(path, group);
    }
}

navigation()

LogisticsCenter.navigation():

  • 预处理
  • completion处理goupsIndex、routes、greenChannel()等信息
  • activity跳转或返回fragment/provider实例
protected Object navigation(final Context context, final Postcard postcard, 
                            final int requestCode, final NavigationCallback callback) {
    //预处理
    PretreatmentService pretreatmentService = ARouter.getInstance()
                          .navigation(PretreatmentService.class);
    if (null != pretreatmentService 
        && !pretreatmentService.onPretreatment(context, postcard)) {
        // Pretreatment failed, navigation canceled.
        return null;
    }
​
    try {
        //goupsIndex、routes、greenChannel
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {        
        if (debuggable()) {
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "There's no route matched!\n" +
                            " Path = [" + postcard.getPath() + "]\n" +
                            " Group = [" + postcard.getGroup() + "]", 
                                   Toast.LENGTH_LONG).show();
                }
            });
        }
​
        if (null != callback) {
            callback.onLost(postcard);
        } else {
            // No callback for this invoke, then we use the global degrade service.
            //降级策略:没有callback时调用
            DegradeService degradeService = ARouter.getInstance()
                            .navigation(DegradeService.class);
            if (null != degradeService) {
                degradeService.onLost(context, postcard);
            }
        }
        return null;
    }
​
    if (null != callback) {
        callback.onFound(postcard);
    }
​
    //是否通过拦截器
    if (!postcard.isGreenChannel()) {   
        // It must be run in async thread, maybe interceptor cost too mush time made ANR.
        interceptorService.doInterceptions(postcard, new InterceptorCallback() {
            /**
             * Continue process
             * @param postcard route meta
             */
            @Override
            public void onContinue(Postcard postcard) {
                _navigation(context, postcard, requestCode, callback);
            }
​
            /**
             * Interrupt process, pipeline will be destory when this method called.
             * @param exception Reson of interrupt.
             */
            @Override
            public void onInterrupt(Throwable exception) {
                if (null != callback) {
                    callback.onInterrupt(postcard);
                }
            }
        });
    } else {
        return _navigation(context, postcard, requestCode, callback);
    }
    return null;
}
​

LogisticsCenter.completion()

  • Warehouse.groupsIndex中的信息保存到Warehouse.routes中
  • IProvider、Fragment:greenChannel()跳过拦截器
public synchronized static void completion(Postcard postcard) {
    RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
    //第一次为null,此时还没有将groupsIndex中以组名为key所对应的ARouter$$Group$$goupName中的act/iprovider保存到routes中
    if (null == routeMeta) {    
        Class<? extends IRouteGroup> groupMeta = Warehouse
                    .groupsIndex.get(postcard.getGroup());  
        if (null == groupMeta) {                      
        } else {
            try {
                //ARouter$$Group$$goupName信息保存到routes中
                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());              
            }
            completion(postcard);   // Reload从新调用
        }
    } else {
        postcard.setDestination(routeMeta.getDestination());
        postcard.setType(routeMeta.getType());
        postcard.setPriority(routeMeta.getPriority());
        postcard.setExtra(routeMeta.getExtra());
​
        Uri rawUri = postcard.getUri();
        if (null != rawUri) {  
            ...
        }
​
        //Provider、Fragment设置greenChannel()跳过拦截器
        switch (routeMeta.getType()) {
            case PROVIDER:  
                Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) 
                                        routeMeta.getDestination();
                IProvider instance = Warehouse.providers.get(providerMeta);
                if (null == instance) { 
                    IProvider provider;
                    try {
                        provider = providerMeta.getConstructor().newInstance();
                        provider.init(mContext);
                        Warehouse.providers.put(providerMeta, provider);
                        instance = provider;
                    } catch (Exception e) {
                        throw new HandlerException("Init provider failed! " + e.getMessage());
                    }
                }
                postcard.setProvider(instance);
                postcard.greenChannel();    // Provider should skip all of interceptors
                break;
            case FRAGMENT:
                postcard.greenChannel();    // Fragment needn't interceptors
            default:
                break;
        }
    }
}
private Object _navigation(final Context context, final Postcard postcard, 
                           final int requestCode, final NavigationCallback callback) {
    final Context currentContext = null == context ? mContext : context;
    switch (postcard.getType()) {
        case ACTIVITY:
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());
            ...
            // Navigation in main looper.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });
​
            break;
        case PROVIDER:
            return postcard.getProvider();
        case BOARDCAST:
        case CONTENT_PROVIDER:
        case FRAGMENT:
            Class fragmentMeta = postcard.getDestination();
            try {
                Object instance = fragmentMeta.getConstructor().newInstance();
                if (instance instanceof Fragment) {
                    ((Fragment) instance).setArguments(postcard.getExtras());
                } else if (instance instanceof android.support.v4.app.Fragment) {
                    ((android.support.v4.app.Fragment) instance)
                        .setArguments(postcard.getExtras());
                }
                return instance;
            }
        case METHOD:
        case SERVICE:
        default:
            return null;
    }
    return null;
}   

jar中加载路由表

自动加载路由表是通过arouter-register插件来实现的,主要通过在编译期给LogisticsCenter的loadRouterMap方法插入register方法调用的代码;反编译出来的代码确实在loadRouterMap方法处插入了register方法调用的代码,并且把registerByPlugin置为true,所以最终不会通过扫描dex文件来加载路由表类装载到map中。

通过这种方式,在init时便不会通过扫描dex文件的方式获取class类信息了,减小耗时会有明显提升

image-20210331175447745.png

原理

ARouter加载路由表原理

Tips

  • 插件跳转目标类 :ARout Helper插件
  • 问题排查:
​
  apply plugin: 'kotlin-android'
  apply plugin: 'kotlin-android-extensions'
  apply plugin: 'kotlin-kapt'
​
  //ARout
  javaCompileOptions {
      annotationProcessorOptions {
          arguments = [AROUTER_MODULE_NAME: project.getName()]
      }
  }
​
  kapt androidDepend.arouter_compiler
  //纯Java项目,如果.gradle已经配置了Kotlin相关的,需使用上面的kapt
  annotationProcessor  androidDepend.arouter_compiler
​
  路径以"/"开头
​
  • 其它模块Application初始化
class App:BaseApplication() {
    override fun initMain(application: Application?) {
        //第一次调用是,provide初始化
        ARouter.getInstance().navigation(IModuleWalletService::class.java)
    }
}
​
@Route(path = RoutTable.WALLET_SERVICE_MAIN)
class ModuleWalletService: IModuleWalletService {
    //第一次自动调用
    override fun init(context: Context?) {
        KLog.d("", "$context")
        (context as? Application).run { AppWallet().initMain(this) }
    }
}
​
class AppWallet: BaseApplication() {
    override fun initMain(application: Application?) {
        KLog.d("", "$application")
    }
}