计算机技术实战

纸上得来终觉浅,绝知此事要躬行。

Download this project as a .zip file Download this project as a tar.gz file

ARouter解析

目录

准备工作

因为ARouter使用ASM字节码注入,初始化流程涉及到的关键地方,源码是看不到的,所以需要找到生成后的class或jar。

查看build log

ARouter::Register >>> Insert register code to file /ARouter/app/build/intermediates/transforms/com.alibaba.arouter/debug/41.jar
ARouter::Register >>> Insert init code to class >> com/alibaba/android/arouter/core/LogisticsCenter.class

反编译41.jar

使用Java Decompiler反编译41.jar,源码中LogisticsCenter的loadRouterMap()方法:

    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());
    }

字节码注入之后是:

    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");
    }

原理解析:

首先com.alibaba.arouter插件配置三个接口:

    def transformImpl = new RegisterTransform(project)
    ArrayList<ScanSetting> list = new ArrayList<>(3)
    list.add(new ScanSetting('IRouteRoot'))
    list.add(new ScanSetting('IInterceptorGroup'))
    list.add(new ScanSetting('IProviderGroup'))
    RegisterTransform.registerList = list
    //register this plugin
    android.registerTransform(transformImpl)

在所有模块的com/alibaba/android/arouter/routes/包下,找到实现了上述三个接口的类,将类名作为参数传递给register,再插入到loadRouterMap()方法中,形成了如上的样子。

注册

注册分为3种:

  1. IRouteRoot
  2. IProviderGroup
  3. IInterceptorGroup
    private static void register(String className) {
        if (!TextUtils.isEmpty(className)) {
            try {
                Class<?> clazz = Class.forName(className);
                Object obj = clazz.getConstructor().newInstance();
                if (obj instanceof IRouteRoot) {
                    registerRouteRoot((IRouteRoot) obj);
                } else if (obj instanceof IProviderGroup) {
                    registerProvider((IProviderGroup) obj);
                } else if (obj instanceof IInterceptorGroup) {
                    registerInterceptor((IInterceptorGroup) obj);
                } else {
                    logger.info(TAG, "register failed, class name: " + className
                            + " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
                }
            } catch (Exception e) {
                logger.error(TAG,"register class error:" + className);
            }
        }
    }

注册完成的信息分别放在:

  1. Warehouse.groupsIndex
  2. Warehouse.providersIndex
  3. Warehouse.interceptorsIndex

跳转

主要原理是使用注解生成path和Class的映射关系:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$module implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/module/1", RouteMeta.build(RouteType.ACTIVITY, TestModuleActivity.class, "/module/1", "module", null, -1, -2147483648));
    atlas.put("/module/3", RouteMeta.build(RouteType.ACTIVITY, TestModule3Activity.class, "/module/3", "module", null, -1, -2147483648));
  }
}

调用api:

ARouter.getInstance().build("/module/1")
                        .withString("key1", "value1")
                        .navigation();

使用Bundle传递参数,然后在_ARouter类跳转:

    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:
                // Build intent
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());

                // Set flags.
                int flags = postcard.getFlags();
                if (-1 != flags) {
                    intent.setFlags(flags);
                } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

                // Set Actions
                String action = postcard.getAction();
                if (!TextUtils.isEmpty(action)) {
                    intent.setAction(action);
                }

                // Navigation in main looper.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });

                break;
            default:
                return null;
        }

        return null;
    }

startActivityForResult

    ARouter.getInstance().build("/test/activity2").navigation(this, 666);

旧版转场动画

    ARouter.getInstance()
        .build("/test/activity2")
        .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
        .navigation(this);

新版转场动画

    if (Build.VERSION.SDK_INT >= 16) {
        ActivityOptionsCompat compat = ActivityOptionsCompat.
                makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

        ARouter.getInstance()
                .build("/test/activity2")
                .withOptionsCompat(compat)
                .navigation();
    } else {
        Toast.makeText(this, "API < 16,不支持新版本动画", Toast.LENGTH_SHORT).show();
    }

拦截器

使用@Interceptor注解,会在对应module下生成:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(7, Test1Interceptor.class);
  }
}

对于实现了IProvider的接口,会生成PROVIDER类型的RouteMeta:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$arouter implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER, AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, -1, -2147483648));
    atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER, InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter", null, -1, -2147483648));
  }
}

_ARouter触发初始化:

    static void afterInit() {
        // Trigger interceptor init, use byName.
        interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
    }

定位到InterceptorServiceImpl类,通过反射构造实例,并调用init方法。此时所有带@Interceptor注解的类将初始化。

方法调用

对于实现了IProvider的类,打上@Route注解,会生成PROVIDER类型的RouteMeta:

public interface HelloService extends IProvider {
    void sayHello(String name);
}
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$yourservicegroupname implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/yourservicegroupname/hello", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", null, -1, -2147483648));
    atlas.put("/yourservicegroupname/json", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/yourservicegroupname/json", "yourservicegroupname", null, -1, -2147483648));
    atlas.put("/yourservicegroupname/single", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/yourservicegroupname/single", "yourservicegroupname", null, -1, -2147483648));
  }
}

通过路径定位到类,实例化之后调用其方法:

((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");