ARouter是什么
ARouter是阿里巴巴開源的Android平臺(tái)中對(duì)頁(yè)面、服務(wù)提供路由功能的中間件,提倡的是簡(jiǎn)單且夠用。
Github: https://github.com/alibaba/ARouter
介紹: https://yq.aliyun.com/articles/71687
簡(jiǎn)單使用示例
Activtiy跳轉(zhuǎn)
ARouter.getInstance().build("/test/activity2").withString("name", "老王").navigation();
獲取服務(wù)功能
ARouter.getInstance().navigation(HelloService.class).sayHello("mike");
((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");
主要代碼結(jié)構(gòu)
arouter-api: 上層主要代碼,包括入口類ARouter,主要邏輯代碼類LogisticsCenter,相關(guān)輔助類ClassUtils等
arouter-annotation: ARouter中主要支持的annotation(包括Autowired, Route, Interceptor)的定義,以及RouteMeta等基礎(chǔ)model bean的定義
arouter-compiler: ARouter中annotation對(duì)應(yīng)的annotation processor代碼(注解處理器:讓這些注解代碼起作用,Arouter中主要是生成相關(guān)代碼,關(guān)于annotation processor,詳細(xì)了解可參考 Java注解處理器, 這篇譯文介紹的非常完整。
arouter-gradle-plugin: 一個(gè)gradle插件,目的是在arouter中插入相關(guān)注冊(cè)代碼(代替在Init時(shí)掃描dex文件獲取到所有route相關(guān)類)
app: Demo代碼,包括Activity跳轉(zhuǎn),面向接口服務(wù)使用,攔截器的使用等詳細(xì)使用示例
核心源碼分析
ARouter.getInstance().build("/test/activity2").withString("name", "老王").navigation();
從最常用的跳轉(zhuǎn)開始分析,基本可了解到ARouter的運(yùn)轉(zhuǎn)原理。這行完成跳轉(zhuǎn)的代碼最終效果是攜帶參數(shù)跳轉(zhuǎn)到對(duì)應(yīng)的Activity,在Android層面來(lái)說(shuō)最后一定是通過(guò)調(diào)用startActivity或是startActivityForResult來(lái)完成跳轉(zhuǎn)。
分為幾步來(lái)看:
- ARouter調(diào)用Build生成Postcard,過(guò)程是怎樣的
- Postcard是什么
- Postcard調(diào)用navigation是怎樣執(zhí)行到startActivity的
生成Postcard過(guò)程
打開ARouter類,發(fā)現(xiàn)基本都是調(diào)用_ARouter類的方法。
ARouter類非常簡(jiǎn)單,只是通過(guò)Facade pattern包裝了_ARouter類的相關(guān)方法,方便調(diào)用和閱讀。
_ARouter類真正實(shí)現(xiàn)了相關(guān)入口功能,包括初始化和銷毀等方法,另外主要包括生成Postcard以及通過(guò)Postcard完成navigation的代碼 (這里先介紹生成Postcard生成部分,_ARouter詳細(xì)介紹見下方)
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService =
ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path));
}
}
這過(guò)程主要完成了2個(gè)步驟:
- 查找是否存在PathReplaceService,如果有調(diào)用PathReplaceService的forString方法獲取新的path (后面介紹完Service功能會(huì)更好理解這部分)
- 從path中解析出group值,調(diào)用帶有g(shù)roup參數(shù)的build方法
protected Postcard build(String path, String group) {
if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService =
ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return new Postcard(path, group);
}
}
在這個(gè)方法中就可以看到Postcard的構(gòu)造。
Postcard是什么
首先Postcard繼承RouteMeta,RouteMeta中存儲(chǔ)的是關(guān)于route的一些基礎(chǔ)信息,只定位于存儲(chǔ)route基礎(chǔ)信息。
public class RouteMeta {
private RouteType type; // Type of route
private Element rawType; // Raw type of route
private Class<?> destination; // Destination
private String path; // Path of route
private String group; // Group of route
private int priority = -1; // The smaller the number, the higher the priority
private int extra; // Extra data
private Map<String, Integer> paramsType; // Param type
private String name;
private Map<String, Autowired> injectConfig; // Cache inject config.
...
}
Postcard類則還包括了"明信片"的"寄出"(navigation方法),"是否支持綠色通道"(isGreenChannel方法),以及支持"寄出效果"(withTransition方法)等具體的功能。
public final class Postcard extends RouteMeta {
// Base
private Uri uri;
private Object tag; // A tag prepare for some thing wrong.
private Bundle mBundle; // Data to transform
private int flags = -1; // Flags of route
private int timeout = 300; // Navigation timeout, TimeUnit.Second
private IProvider provider; // It will be set value, if this postcard was provider.
private boolean greenChannel;
private SerializationService serializationService;
// Animation
private Bundle optionsCompat; // The transition animation of activity
private int enterAnim = -1;
private int exitAnim = -1;
...
public void navigation(Activity mContext, int requestCode, NavigationCallback callback){
ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}
...
public Postcard withString(@Nullable String key, @Nullable String value) {
mBundle.putString(key, value);
return this;
}
...
public Postcard withTransition(int enterAnim, int exitAnim) {
this.enterAnim = enterAnim;
this.exitAnim = exitAnim;
return this;
}
...
}
回到前面的介紹,在_ARouter的的build方法中通過(guò)path和group參數(shù)構(gòu)造出了一張可以"寄出"的"明信片"(new Postcard)。
Postcard.navigation到startActivity
接下來(lái)就是調(diào)用Postcard的navigation方法
public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {
ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}
可以看到其實(shí)是調(diào)用了ARouter的navigation, 內(nèi)部調(diào)用了_ARouter的navigation。接下來(lái)看看navigation的主要過(guò)程是怎樣的。
protected Object navigation(final Context context, final Postcard postcard, final int
requestCode, final NavigationCallback callback) {
try {
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
if (debuggable()) {
// Show friendly tips for user.
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.
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);
}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " +
exception.getMessage());
}
});
} else {
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
這個(gè)方法有點(diǎn)長(zhǎng),但主要包括3步流程。
-
調(diào)用LogisticsCenter.completion
主要是為Postcard找到對(duì)應(yīng)router,并且用router中信息填充Postcard對(duì)象。
如果該方法拋出NoRouteFoundException,則調(diào)用對(duì)應(yīng)Callback的onLost,如果沒(méi)有配置Callback則嘗試獲取是否存在DegradeService,如果存在調(diào)用DegradeService的onLost方法。(DegradeService的實(shí)現(xiàn)可以理解為兜底方案,比如native頁(yè)面沒(méi)有找到,用相應(yīng)H5頁(yè)面替代展示)
LogisticsCenter類的詳細(xì)介紹見下方。
-
調(diào)用Callback的onFound方法,然后判斷是否可以走“綠色通道”(即不支持?jǐn)r截)。
不能走“綠色通道”的都需要經(jīng)過(guò)攔截器攔截(后面會(huì)介紹攔截器原理),攔截器會(huì)返回繼續(xù)和中斷2種結(jié)果,繼續(xù)則會(huì)繼續(xù)執(zhí)行調(diào)用navigation方法(相當(dāng)于在跳轉(zhuǎn)前做了點(diǎn)額外動(dòng)作);
如果走了“綠色通道”的則直接調(diào)用_navigation方法。
_navigation方法中則可以看到,如果 postcard.getType() 是activity則調(diào)用startActivity或startActivityForResult,且支持動(dòng)畫和啟動(dòng)flags的設(shè)置,接著調(diào)用callback.onArrival。
如果種類是provider則提供提供provider對(duì)象,如果是Fragment則生成對(duì)象且賦值參數(shù)。
ARouter.getInstance().build("/test/activity2").withString("name", "老王").navigation();
至此,已梳理完上方代碼完成Activity跳轉(zhuǎn)的主要流程。
獲取接口對(duì)象
((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");
大體流程和上面完成Activity跳轉(zhuǎn)流程代碼類似,主要區(qū)別在于,
- LogisticsCenter.completion中給Postcard填充type時(shí),對(duì)應(yīng)的是RouteType.PROVIDER,并且在Warehouse中找到對(duì)應(yīng)的Provider賦值給Postcard。
- 在ARouter的_navigation方法中,發(fā)現(xiàn)Postcard類型是RouteType.PROVIDER則直接返回對(duì)應(yīng)Provider。
ARouter中Annotation的使用
Annotation在ARouter中有著非常重要作用,Annotation基本原理這里不做詳談。
ARouter中主要的Annotation有3個(gè):
Autowired
Route
Interceptor
對(duì)應(yīng)的Annotation定義代碼位置如下圖所示,位于arouter-annotation module中。

Autowired
Autowired主要完成界面跳轉(zhuǎn)過(guò)程中,Intent參數(shù)的自動(dòng)填充。
先看看Autowired是如何使用的,再看看Autowired是如何做到的。
如何使用
@Route(path = "/test/activity1", name = "測(cè)試用 Activity")
public class Test1Activity extends AppCompatActivity {
@Autowired(desc = "姓名")
String name = "jack";
@Autowired
int age = 10;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
ARouter.getInstance().inject(this);
...
//inject方法被調(diào)用后,被Autowired注解的變量則已從Intent中取出對(duì)應(yīng)參數(shù)賦值
}
}
如何實(shí)現(xiàn)
在arouter-compiler module中,查看對(duì)應(yīng)的AutowiredProcessor代碼,這是一個(gè)用來(lái)處理Autowired注解的注解處理器,主要目的是生成Java代碼,生成怎樣的Java代碼(如何生成的,可基于注解處理器原理詳細(xì)查看AutowiredProcessor),如下:
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
Test1Activity substitute = (Test1Activity)target;
substitute.name = substitute.getIntent().getExtras() == null ? substitute.name :
substitute.getIntent().getExtras().getString("name", substitute.name);
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
...
}
代碼路徑:

梳理下Autowired注解整個(gè)流程:
在Activity的變量上標(biāo)注,注解處理器會(huì)在編譯階段掃描有被Autowired注解標(biāo)注的變量,根據(jù)這個(gè)類和變量的情況生成一份Java代碼,其中最主要會(huì)有一個(gè)inject方法,完成對(duì)相關(guān)變量的解析賦值,然后在Activity的onCreate靠前位置調(diào)用對(duì)應(yīng)inject方法即可。這個(gè)注解主要目的在于省去了手動(dòng)編寫解析Intent參數(shù)的代碼。
(但為什么代碼是調(diào)用 ARouter.getInstance().inject(this); 后面會(huì)有說(shuō)明)
Route
Route注解標(biāo)注的類(頁(yè)面或服務(wù)類),可通過(guò)path跳轉(zhuǎn)到對(duì)應(yīng)界面或是獲取到具體服務(wù)。
如何使用
@Route(path = "/test/activity1", name = "測(cè)試用 Activity")
public class Test1Activity extends AppCompatActivity {
...
}
@Route(path = "/yourservicegroupname/hello")
public class HelloServiceImpl implements HelloService {
...
}
如何實(shí)現(xiàn)
在arouter-compiler module中,查看對(duì)應(yīng)的RouteProcessor代碼,用來(lái)處理Route注解的注解處理器,主要完成以下幾部分的生成代碼工作(主要為RouteProcessor中的parseRoutes方法):
獲取到所有的被注解Route的類,生成對(duì)應(yīng)的RouteMeta,分組放到groupMap中,key為group name, value為支持排序放入的的Set<RouteMeta>中。
遍歷groupMap中所有的Set<RouteMeta>的所有RouteMeta (所以是個(gè)雙層for循環(huán))生成對(duì)應(yīng)代碼。
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
String groupName = entry.getKey();
...
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
...
}
...
}
生成的代碼如下:
public class ARouter$$Group$$test implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
...
atlas.put("/test/activity4", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class,
"/test/activity4", "test", null, -1, -2147483648));
atlas.put("/test/fragment", RouteMeta.build(RouteType.FRAGMENT, BlankFragment.class,
"/test/fragment", "test", null, -1, -2147483648));
atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class,
"/test/webview", "test", null, -1, -2147483648));
...
}
}
- 生成rootMap,key為group name,value為剛才每個(gè)group對(duì)應(yīng)生成的java類的類名,根據(jù)rootMap生成對(duì)應(yīng)Java文件。
public class ARouter$$Root$$app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("test", ARouter$$Group$$test.class);
routes.put("yourservicegroupname", ARouter$$Group$$yourservicegroupname.class);
}
}
詳細(xì)關(guān)于這些生成類是如何被使用的,在后面LogisticsCenter中會(huì)有詳細(xì)介紹。
Interceptor
Interceptor 主要用于在跳轉(zhuǎn)過(guò)程中插入一些功能。
如何使用
@Interceptor(priority = 7)
public class Test1Interceptor implements IInterceptor {
Context mContext;
@Override
public void process(final Postcard postcard, final InterceptorCallback callback) {
if ("/test/activity4".equals(postcard.getPath())) {
// 這里的彈窗僅做舉例,代碼寫法不具有可參考價(jià)值
final AlertDialog.Builder ab = new AlertDialog.Builder(MainActivity.getThis());
ab.setCancelable(false);
ab.setTitle("溫馨提醒");
ab.setMessage("想要跳轉(zhuǎn)到Test4Activity么?(觸發(fā)了\"/inter/test1\"攔截器,攔截了本次跳
轉(zhuǎn))");
ab.setNegativeButton("繼續(xù)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onContinue(postcard);
}
});
ab.setNeutralButton("算了", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onInterrupt(null);
}
});
ab.setPositiveButton("加點(diǎn)料", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
postcard.withString("extra", "我是在攔截器中附加的參數(shù)");
callback.onContinue(postcard);
}
});
MainLooper.runOnUiThread(new Runnable() {
@Override
public void run() {
ab.create().show();
}
});
} else {
callback.onContinue(postcard);
}
}
這個(gè)例子是想在跳轉(zhuǎn)到 "/test/activity4" 對(duì)應(yīng)的Activity過(guò)程中彈出對(duì)話框,在用戶做出了相關(guān)動(dòng)作后再繼續(xù)跳轉(zhuǎn),點(diǎn)擊"繼續(xù)"則繼續(xù)執(zhí)行,點(diǎn)擊"算了"則取消跳轉(zhuǎn),點(diǎn)擊"加點(diǎn)料"則在跳轉(zhuǎn)過(guò)程中添加參數(shù)。
如何實(shí)現(xiàn)
上面在分析ARouter的navigation的跳轉(zhuǎn)過(guò)程中,分析_ARouter的navigation方法中有提到會(huì)去判斷是否走"綠色通道",如果沒(méi)有的話則要調(diào)用 interceptorService.doInterceptions 方法來(lái)經(jīng)過(guò)攔截器的處理。
來(lái)看看攔截器是如何處理的,主要代碼在InterceptorServiceImpl類中。主要方法有:
doInterceptions:供外部調(diào)用接口方法,會(huì)在異步線程中開啟攔截器的逐個(gè)調(diào)用,會(huì)去調(diào)用_excute方法,完成對(duì)攔截器IInterceptor的process方法的調(diào)用,通過(guò)CountDownLatch來(lái)控制是否所有攔截器都調(diào)用完成,且在超時(shí)時(shí)間內(nèi)。
_excute: 調(diào)用IInterceptor的process方法,在callback的onContinue方法中遞歸調(diào)用自己,但調(diào)整index值,使用下一個(gè)攔截器。
_ARouter介紹
ARouter類只是使用Facade patten對(duì)_ARouter類進(jìn)行了封裝,并沒(méi)有太多實(shí)際功能代碼,所以看看_ARouter中的具體實(shí)現(xiàn)代碼。
首先_ARouter是個(gè)單例類,但會(huì)在getInstance方法中判斷是否有進(jìn)行初始化(必須要先初始化)。
其次幾個(gè)主要的方法:
init: 這里面最重要是調(diào)用了LogisticsCenter.init,完成相關(guān)路由信息填充。
Inject: 獲取AutowiredService的實(shí)體,會(huì)調(diào)用到AutowiredServiceImpl的autowire方法,在這個(gè)方法中會(huì)根據(jù)傳入?yún)?shù)Activity的Name再加上注解處理器中約定的后綴字段獲得新的類名(也就是注解處理器生成的對(duì)應(yīng)的Java文件對(duì)應(yīng)的類名),利用反射方式生成新對(duì)象,調(diào)用其inject方法。
(如上面分析的類 Test1Activity$$ARouter$$Autowired的inject方法)。
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
...
@Override
public void autowire(Object instance) {
String className = instance.getClass().getName();
try {
if (!blackList.contains(className)) {
ISyringe autowiredHelper = classCache.get(className);
if (null == autowiredHelper) { // No cache.
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName()
+ SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
autowiredHelper.inject(instance);
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
blackList.add(className); // This instance need not autowired.
}
}
}
build: 生成對(duì)應(yīng)Postcard
navigation: 跳轉(zhuǎn)到對(duì)應(yīng)頁(yè)面或獲取對(duì)應(yīng)Service等
arouter-gradle-plugin module
這個(gè)module 是一個(gè)gradle plugin, 目的是幫助在com.alibaba.android.arouter.core.LogisticsCenter類的loadRouterMap方法中插入各個(gè)module注冊(cè)router代碼。(關(guān)于gradle plugin的機(jī)制,可通過(guò)深入理解Android之Gradle詳細(xì)了解)
/**
* arouter-auto-register plugin will generate code inside this method
* call this method to register all Routers, Interceptors and Providers
* @author billy.qi <a href="mailto:qiyilike@163.com">Contact me.</a>
* @since 2017-12-06
*/
private static void loadRouterMap() {
registerByPlugin = false;
//auto generate register code by gradle plugin: arouter-auto-register
// looks like below:
// registerRouteRoot(new ARouter..Root..modulejava());
// registerRouteRoot(new ARouter..Root..modulekotlin());
}
/**
* method for arouter-auto-register plugin to register Routers
* @param routeRoot IRouteRoot implementation class in the package: com.alibaba.android.arouter.core.routers
* @author billy.qi <a href="mailto:qiyilike@163.com">Contact me.</a>
* @since 2017-12-06
*/
private static void registerRouteRoot(IRouteRoot routeRoot) {
markRegisteredByPlugin();
if (routeRoot != null) {
routeRoot.loadInto(Warehouse.groupsIndex);
}
}
/**
* method for arouter-auto-register plugin to register Interceptors
* @param interceptorGroup IInterceptorGroup implementation class in the package: com.alibaba.android.arouter.core.routers
* @author billy.qi <a href="mailto:qiyilike@163.com">Contact me.</a>
* @since 2017-12-06
*/
private static void registerInterceptor(IInterceptorGroup interceptorGroup) {
markRegisteredByPlugin();
if (interceptorGroup != null) {
interceptorGroup.loadInto(Warehouse.interceptorsIndex);
}
}
在ARouter 1.4版本前,是通過(guò)掃描ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"這個(gè)packagename下獲取所有route相關(guān)類(包括分布在不同的module中的),然后遍歷分別調(diào)用對(duì)應(yīng)的loadInto方法加載到 Warehouse 的各自Index中(包括Warehouse.providersIndex,Warehouse.interceptorsIndex等),構(gòu)成不同類別的全局路由總表。
這段代碼目前仍存在,主要對(duì)應(yīng)LogisticsCenter.init方法中registerByPlugin變量為false時(shí)對(duì)應(yīng)的分支代碼。
這種方式的缺點(diǎn)在于是在運(yùn)行時(shí)去掃描dex文件中所有類找到需要的類反射來(lái)完成映射表的注冊(cè)。
從ARouter 1.4開始,引入AutoRegister機(jī)制(關(guān)于AutoRegister,可以在AutoRegister:一種更高效的組件自動(dòng)注冊(cè)方案了解詳情)?;驹硎牵涸诰幾g時(shí),掃描所有類,將符合條件的類收集起來(lái),并通過(guò)修改字節(jié)碼生成注冊(cè)代碼到指定的管理類中,從而實(shí)現(xiàn)編譯時(shí)自動(dòng)注冊(cè)的功能,不用再關(guān)心項(xiàng)目中有哪些組件類了。不會(huì)增加新的class,不需要反射,運(yùn)行時(shí)直接調(diào)用組件的構(gòu)造方法。
在ARouter中具體的實(shí)現(xiàn)如下:
arouter-gradle-plugin實(shí)現(xiàn)為gradle plugin, plugin name 是 PLUGIN_NAME = "com.alibaba.arouter",定義在ScanSetting中。在app module中的build.gradle中加入 apply plugin: 'com.alibaba.arouter',表示使用該plugin。
RegisterTransform中完成掃描以ROUTER_CLASS_PACKAGE_NAME = 'com/alibaba/android/arouter/routes/' 開頭的類,然后調(diào)用RegisterCodeGenerator類的方法完成向LogisticsCenter::loadRouterMap插入代碼。
通過(guò)反編譯apk出來(lái)的實(shí)際出來(lái)的代碼如下:
private static void loadRouterMap() {
registerByPlugin = false;
register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulekotlin");
register("com.alibaba.android.arouter.routes.ARouter$$Root$$arouterapi");
register("com.alibaba.android.arouter.routes.ARouter$$Root$$app");
register("com.alibaba.android.arouter.routes.ARouter$$Interceptors$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Interceptors$$app");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulekotlin");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$arouterapi");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$app");
}
這樣在編譯階段即可完成相關(guān)類的掃描工作,在ARouter初始化時(shí)只是完成路由總表的加載,省去在Dex文件中掃描類的步驟。
這里也貼下代碼README.md中給予的說(shuō)明
使用 Gradle 插件實(shí)現(xiàn)路由表的自動(dòng)加載 (可選)
apply plugin: 'com.alibaba.arouter'
buildscript {
repositories {
jcenter()
}
dependencies {
// Replace with the latest version
classpath "com.alibaba:arouter-register:?"
}
}
可選使用,通過(guò) ARouter 提供的注冊(cè)插件進(jìn)行路由表的自動(dòng)加載(power by AutoRegister), 默認(rèn)通過(guò)掃描 dex 的方式。
進(jìn)行加載通過(guò) gradle 插件進(jìn)行自動(dòng)注冊(cè)可以縮短初始化時(shí)間解決應(yīng)用加固導(dǎo)致無(wú)法直接訪問(wèn)dex 文件,初始化失敗的問(wèn)題,需要注意的是,該插件必須搭配 api 1.3.0 以上版本使用!
LogisticsCenter介紹
本想再詳細(xì)介紹下LogisticsCenter類,但發(fā)現(xiàn)經(jīng)過(guò)上面的一些介紹,LogisticsCenter的主要幾個(gè)方法已經(jīng)都解釋過(guò)。
loadRouteMap: 由arouter-gradle-plugin 插件module在編譯階段插入注冊(cè)Route相關(guān)代碼。
init: 調(diào)用loadRouteMap完成Warehouse中各個(gè)路由Index的加載,如果有plugin幫忙插入代碼則直接使用,如果沒(méi)有則通過(guò)運(yùn)行時(shí)掃描dex文件方式加載。
completion:前面分析navigation時(shí)有詳細(xì)介紹,在Route路由表中根據(jù)postcard中的path找到對(duì)應(yīng)的路由信息RouteMeta,利用RouteMeta中信息為Postcard賦值。