Android 组件化路由组件 ( 运行时获取 注解处理器 生成的路由表 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 组件化路由组件 ( 运行时获取 注解处理器 生成的路由表 )相关的知识,希望对你有一定的参考价值。
组件化系列博客 :
- 【Android 组件化】从模块化到组件化
- 【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )
- 【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )
- 【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
- 【Android 组件化】路由组件 ( 路由组件结构 )
- 【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
- 【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
- 【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
- 【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
- 【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
- 【Android 组件化】路由组件 ( 组件间共享的服务 )
- 【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
一、获取应用的 APK
获取应用的 APK 文件 :
首先 , 获取 ApplicationInfo 应用信息 ;
ApplicationInfo applicationInfo = null;
try {
applicationInfo = mContext.getPackageManager().getApplicationInfo(mContext
.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
然后 , 从应用中获取 APK 的安装路径 ;
// 使用集合存放应用安装的 APK 文件
List<String> sourcePaths = new ArrayList<>();
// 一般情况下 , 一个应用只有一个安装 APK
sourcePaths.add(applicationInfo.sourceDir);
最后 , 考虑 instant run 的情况 , 可能存在多个 APK 文件 , 如果有多个 , 也一并放入路径字符串集合中 ;
// 如果是 instant run 形式安装的 , 则有多个 APK 文件
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (null != applicationInfo.splitSourceDirs) {
sourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));
}
}
代码示例 :
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 对象 ;
// 获取 APK 下的 dex 文件
DexFile dexfile = null;
try {
dexfile = new DexFile(path);
} catch (IOException e) {
e.printStackTrace();
}
然后 , 遍历 DexFile 对象中的所有的类 , 调用 dexfile.entries() 获取 Enumeration<String> 对象进行遍历 , 将 “kim.hsl.router” 包名下的类记录下来 ;
Enumeration<String> dexEntries = dexfile.entries();
// 遍历 DEX 文件中的所有的类
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith("kim.hsl.router")) {
classNames.add(className);
}
}
代码示例 :
/*
根据获取所有 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 表对应的对象 ;
代码示例 :
// 最终所有的 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();
}
}
}
最终打印出的数据 :
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 现阶段完整代码 :
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
- CSDN 下载 :
以上是关于Android 组件化路由组件 ( 运行时获取 注解处理器 生成的路由表 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 组件化路由组件 ( 使用 JavaPoet 生成路由表类 )
Android 组件化路由组件 ( 注解处理器获取被注解的节点 )
Android 组件化路由组件 ( 构造路由表中的路由信息 )