【Android 组件化】路由组件 ( 运行时获取 注解处理器 生成的路由表 )

2023-03-29 13:00:54 浏览数 (1)

文章目录

  • 一、获取应用的 APK
  • 二、获取所有 APK 中 kim.hsl.router 包的类
  • 三、获取其它 Module 中的路由表
  • 四、Router 路由加载类代码
  • 五、博客资源

组件化系列博客 :

  • 【Android 组件化】从模块化到组件化
  • 【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )
  • 【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )
  • 【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
  • 【Android 组件化】路由组件 ( 路由组件结构 )
  • 【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
  • 【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
  • 【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
  • 【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
  • 【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
  • 【Android 组件化】路由组件 ( 组件间共享的服务 )
  • 【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )

一、获取应用的 APK


获取应用的 APK 文件 :

首先 , 获取 ApplicationInfo 应用信息 ;

代码语言:javascript复制
ApplicationInfo applicationInfo = null;
try {
    applicationInfo = mContext.getPackageManager().getApplicationInfo(mContext
            .getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

然后 , 从应用中获取 APK 的安装路径 ;

代码语言:javascript复制
// 使用集合存放应用安装的 APK 文件
List<String> sourcePaths = new ArrayList<>();

// 一般情况下 , 一个应用只有一个安装 APK
sourcePaths.add(applicationInfo.sourceDir);

最后 , 考虑 instant run 的情况 , 可能存在多个 APK 文件 , 如果有多个 , 也一并放入路径字符串集合中 ;

代码语言:javascript复制
// 如果是 instant run 形式安装的 , 则有多个 APK 文件
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    if (null != applicationInfo.splitSourceDirs) {
        sourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));
    }
}

代码示例 :

代码语言:javascript复制
ApplicationInfo applicationInfo = null;
try {
    applicationInfo = mContext.getPackageManager().getApplicationInfo(mContext
            .getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

// 使用集合存放应用安装的 APK 文件
List<String> sourcePaths = new ArrayList<>();

// 一般情况下 , 一个应用只有一个安装 APK
sourcePaths.add(applicationInfo.sourceDir);

// 如果是 instant run 形式安装的 , 则有多个 APK 文件
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    if (null != applicationInfo.splitSourceDirs) {
        sourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));
    }
}

二、获取所有 APK 中 kim.hsl.router 包的类


获取所有 APK 中 kim.hsl.router 包的类 :

首先 , 根据 APK 的地址 , 创建 DexFile 对象 ;

代码语言:javascript复制
// 获取 APK 下的 dex 文件
DexFile dexfile = null;
try {
    dexfile = new DexFile(path);
} catch (IOException e) {
    e.printStackTrace();
}

然后 , 遍历 DexFile 对象中的所有的类 , 调用 dexfile.entries() 获取 Enumeration<String> 对象进行遍历 , 将 “kim.hsl.router” 包名下的类记录下来 ;

代码语言:javascript复制
Enumeration<String> dexEntries = dexfile.entries();
// 遍历 DEX 文件中的所有的类
while (dexEntries.hasMoreElements()) {
    String className = dexEntries.nextElement();
    if (className.startsWith("kim.hsl.router")) {
        classNames.add(className);
    }
}

代码示例 :

代码语言:javascript复制
/*
    根据获取所有 APK 下的类
    根据 kim.hsl.router 包名, 获取该包名下的所有路由类
 */
// 获取查找的 kim.hsl.router 包下的类 的 类名
Set<String> classNames = new HashSet<>();

// 遍历所有的 APK 路径 , 查找其中的 DEX 中的类
for (final String path : sourcePaths) {
    // 获取 APK 下的 dex 文件
    DexFile dexfile = null;
    try {
        dexfile = new DexFile(path);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    Enumeration<String> dexEntries = dexfile.entries();
    // 遍历 DEX 文件中的所有的类
    while (dexEntries.hasMoreElements()) {
        String className = dexEntries.nextElement();
        if (className.startsWith("kim.hsl.router")) {
            classNames.add(className);
        }
    }
}

三、获取其它 Module 中的路由表


之前已经获取了 “kim.hsl.router” 包中的所有类 , 将 " kim.hsl.router.Router_Root_ " 开头的类记录下来 , 使用反射获取相关类 , 可以直接创建 Root 表对应的对象 ;

代码示例 :

代码语言:javascript复制
// 最终所有的 kim.hsl.router 包下的类都存放到了 Set<String> classNames 变量中
for (String className : classNames){
    /*
        这是打印出来的类
        kim.hsl.router_annotation.model.RouteBean$Type
        kim.hsl.router.Router_Group_app
        kim.hsl.router_annotation.Route
        kim.hsl.router.Router_Root_library2
        kim.hsl.router.Router_Root_app
        kim.hsl.router.Router_Group_library2
        kim.hsl.router_annotation.model.RouteBean
     */
    Log.i(TAG, "loadInfo : "   className);
    // 如果该类以 " Router_Root_ " 开头 , 说明这是 Root 表类
    if (className.startsWith("kim.hsl.router.Router_Root_")) {
        // root中注册的是分组信息 将分组信息加入仓库中
        try {
            // 获取 IRouteRoot 类
            Class<IRouteRoot> clazz = (Class<IRouteRoot>) Class.forName(className);
            // 获取构造函数
            Constructor<IRouteRoot> constructor = clazz.getConstructor();
            // 创建 IRouteRoot 类
            IRouteRoot routeRoot = constructor.newInstance();
            // 将 Root 表的信息装载到 Warehouse.groupsIndex 集合中
            routeRoot.loadInto(Warehouse.groupsIndex);
            // 打印 Root 表
            for ( Map.Entry<String, Class<? extends IRouteGroup>> entry : Warehouse.groupsIndex.entrySet()){
                Log.i(TAG, "loadInfo : "   entry.getKey()   " : "   entry.getValue().getName());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

最终打印出的数据 :

代码语言:javascript复制
loadInfo : kim.hsl.router_annotation.model.RouteBean$Type
loadInfo : kim.hsl.router.Router_Group_app
loadInfo : kim.hsl.router_annotation.Route
loadInfo : kim.hsl.router.Router_Root_library2
loadInfo : library2 : kim.hsl.router.Router_Group_library2
loadInfo : kim.hsl.router.Router_Root_app
loadInfo : app : kim.hsl.router.Router_Group_app
loadInfo : library2 : kim.hsl.router.Router_Group_library2
loadInfo : kim.hsl.router.Router_Group_library2
loadInfo : kim.hsl.router_annotation.model.RouteBean

获取了 “app” 分组的路由表 kim.hsl.router.Router_Group_app 类 ,

获取了 “library2” 分组的路由表 kim.hsl.router.Router_Group_library2 类 ,

已知路由表的类名 , 可以使用反射创建两个路由表 , 并拿到路由表中的数据 ;

四、Router 路由加载类代码


Router 现阶段完整代码 :

代码语言:javascript复制
package kim.hsl.route_core;

import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import dalvik.system.DexFile;
import kim.hsl.route_core.template.IRouteGroup;
import kim.hsl.route_core.template.IRouteRoot;

public class Router {
    private static final String TAG = "Router";

    /**
     * 上下文
     */
    private static Application mContext;

    /**
     * 单例类
     */
    private static Router instance;

    private Router() {
    }

    /**
     * 初始化路由表
     * @param application
     */
    public static void init(Application application) {
        mContext = application;
        loadInfo();
    }

    /**
     * 加载 分组 路由表 数据
     * 每个分组对应一个路由表
     */
    private static void loadInfo(){
        /*
            获取程序的所有 APK 安装文件
         */
        ApplicationInfo applicationInfo = null;
        try {
            applicationInfo = mContext.getPackageManager().getApplicationInfo(mContext
                    .getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        // 使用集合存放应用安装的 APK 文件
        List<String> sourcePaths = new ArrayList<>();

        // 一般情况下 , 一个应用只有一个安装 APK
        sourcePaths.add(applicationInfo.sourceDir);

        // 如果是 instant run 形式安装的 , 则有多个 APK 文件
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (null != applicationInfo.splitSourceDirs) {
                sourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));
            }
        }


        /*
            根据获取所有 APK 下的类
            根据 kim.hsl.router 包名, 获取该包名下的所有路由类
         */

        // 获取查找的 kim.hsl.router 包下的类 的 类名
        Set<String> classNames = new HashSet<>();

        // 遍历所有的 APK 路径 , 查找其中的 DEX 中的类
        for (final String path : sourcePaths) {
            // 获取 APK 下的 dex 文件
            DexFile dexfile = null;
            try {
                dexfile = new DexFile(path);
            } catch (IOException e) {
                e.printStackTrace();
            }

            Enumeration<String> dexEntries = dexfile.entries();
            // 遍历 DEX 文件中的所有的类
            while (dexEntries.hasMoreElements()) {
                String className = dexEntries.nextElement();
                if (className.startsWith("kim.hsl.router")) {
                    classNames.add(className);
                }
            }
        }

        // 最终所有的 kim.hsl.router 包下的类都存放到了 Set<String> classNames 变量中
        for (String className : classNames){
            /*
                这是打印出来的类
                kim.hsl.router_annotation.model.RouteBean$Type
                kim.hsl.router.Router_Group_app
                kim.hsl.router_annotation.Route
                kim.hsl.router.Router_Root_library2
                kim.hsl.router.Router_Root_app
                kim.hsl.router.Router_Group_library2
                kim.hsl.router_annotation.model.RouteBean
             */
            Log.i(TAG, "loadInfo : "   className);

            // 如果该类以 " Router_Root_ " 开头 , 说明这是 Root 表类
            if (className.startsWith("kim.hsl.router.Router_Root_")) {
                // root中注册的是分组信息 将分组信息加入仓库中
                try {
                    // 获取 IRouteRoot 类
                    Class<IRouteRoot> clazz = (Class<IRouteRoot>) Class.forName(className);

                    // 获取构造函数
                    Constructor<IRouteRoot> constructor = clazz.getConstructor();

                    // 创建 IRouteRoot 类
                    IRouteRoot routeRoot = constructor.newInstance();

                    // 将 Root 表的信息装载到 Warehouse.groupsIndex 集合中
                    routeRoot.loadInto(Warehouse.groupsIndex);

                    // 打印 Root 表
                    for ( Map.Entry<String, Class<? extends IRouteGroup>> entry : Warehouse.groupsIndex.entrySet()){
                        Log.i(TAG, "loadInfo : "   entry.getKey()   " : "   entry.getValue().getName());
                    }

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

五、博客资源


博客源码 :

  • GitHub : https://github.com/han1202012/Component

0 人点赞