怎么将 Android 程序做成插件化的形式?
背景:
最近做了移动开放平台(mpaas) ,由于不知道各模块组件的初始化类以及appid等信息, 最后采用了注解,插桩的方式初始化各个模块组件。
目标:
KAPT
+ JavaPoet
+ Gradle Transform API
+ ASM
+ ASM ByteCode onLine
+ startup
startup: 同步初始化、异步初始化、延迟初始化、懒加载初始化,支持依赖顺序,主界面等待某个组件初始化完毕等功能
注解:
APT(Annotation Processor Tool)即 注解处理器,是一种处理注解的工具,确切的说它是javac
的一个工具,它用在 编译时 扫描和处理注解。
常用的开源注解框架 ButterKnife、Dagger、EventBus 等注解框架
JavaPoet 生成注解代码框架
gthub地址:https://github.com/square/javapoet
自定义注解可以参考我的另一篇Java之注解的定义及使用
//面向接口编程,这个类是每个组件的base协议类
import android.content.Context;
public interface IBaseProtocol {
void onCreate(Context context,boolean isDebug);
/**
* obtain protocol name
*
* @return protocol name
*/
String name();
/**
* obtain protocol version
*
* @return protocol version
*/
String version();
void onDestroy();
}
同步初始化、异步初始化、延迟初始化、懒加载初始化
如果初始化是异步的,支持等待机制
/**
* ******************************
* 说明:模块初始化和依赖项的协议
* 注解类的工厂类 功能是统一管理各个组件的创建和销毁
* ******************************
*/
import android.content.Context;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public abstract class AbProtocolFactory<T extends IBaseProtocol> {
private volatile boolean mIsSend;// Task是否已经被分发
private CountDownLatch mDepends = new CountDownLatch(dependencies() == null ? 0 : dependencies().size());// 当前Task依赖的Task数量(需要等待被依赖的Task执行完毕才能执行自己),默认没有依赖
/**
* 当前Task等待,让依赖的Task先执行
*/
public void waitToSatisfy() {
try {
mDepends.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 依赖的Task执行完一个
*/
public void satisfy() {
mDepends.countDown();
}
/**
* 模块初始化
*
* @param context
* @return
*/
public abstract T createProtocol( Context context,boolean isDebug);
/**
* 模块依赖项
*
* @return
*/
public abstract List<Class<? extends AbProtocolFactory<? extends IBaseProtocol>>> dependencies();
/**
* 协议类class
*
* @return
*/
public abstract Class<T> getProtocol();
/**
* 是否在主线程初始化
* 默认是
*/
public abstract boolean runOnUiThread();
public boolean isSend() {
return mIsSend;
}
public void setSend(boolean send) {
mIsSend = send;
}
/**
* 异步线程执行的Task是否需要在被调用await的时候等待,默认不需要 false
* 主线程是否需要等待这个组件初始化完成在进行下步操作 比如 slpash页面的 网络组件 存储组件等等
* @return
*/
public abstract boolean isWaitThisEnd();
/**
* 是否是延迟初始化 默认false
* 需要业务方选择合适的时机,在系统空闲的时候初始化一些非必须初始化完成的Task
* @return
*/
public abstract boolean isDelayCreate();
/**
* 是否是懒加载初始化 默认false
* @return
*/
public abstract boolean isLazyCreate();
}
注解类:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface StartUp {
// String appId() default "";
// boolean isDebug() default false;
/**
* 启动顺序依赖的class
* @return
*/
Class<?>[] dependenciesClass() default {};
/**
* 初始化协议类
* @return
*/
Class<?> protocol();
/**
* 是否在主线程执行
* 默认是主线程中初始化
*
*/
boolean runOnUIThread() default true;
/**
* 异步线程执行的Task是否需要在被调用await的时候等待,默认不需要 false
* 主线程是否需要等待这个组件初始化(在子线程初始化)完成在进行下步操作 比如 slpash页面的 网络组件 存储组件等等
* @return
*/
boolean isWaitThisEnd() default false;
/**
* 是否是延迟初始化 默认false
* 需要业务方选择合适的时机,在系统空闲的时候初始化一些非必须初始化完成的Task
* @return
*/
boolean isDelayCreate() default false;
/**
* 是否是懒加载初始化 默认false
* @return
*/
boolean isLazyCreate() default false;
}
注解解析类:
@AutoService(Processor.class)
public class Processor extends AbstractProcessor {
/**
* java源文件操作相关类,主要用于生成java源文件
*/
private Filer mFiler;
/**
* 注解类型工具类,主要用于后续生成java源文件使用
* 类为TypeElement,变量为VariableElement,方法为ExecuteableElement
*/
private Elements mElementsUtils;
/**
* 日志打印,类似于log,可用于输出错误信息
*/
private Logger logger;
/**
* 类信息工具类
*/
private Types mTypeUtils;
/**
* 节点信息缓存
*/
private Map<String, List<NodeInfo>> mCache = new HashMap<>();
/**
* 初始化,主要用于初始化各个变量
* 注解处理器的初始化阶段,可以通过ProcessingEnvironment来获取一些帮助我们来处理注解的工具类
*
* @param processingEnv
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mTypeUtils = processingEnv.getTypeUtils();
mFiler = processingEnv.getFiler();
mElementsUtils = processingEnv.getElementUtils();
logger = new Logger(processingEnv.getMessager());
}
/**
* 支持的注解类型
* 指明有哪些注解需要被扫描到,返回注解的全路径(包名+类名)
*
* @return
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(StartUp.class.getCanonicalName());
}
@Override
public Set<String> getSupportedOptions() {
return new HashSet<String>() {{
this.add(KEY_MODULE_NAME);
}};
}
/**
* 支持的版本
* 用来指定当前正在使用的Java版本,一般返回SourceVersion.latestSupported()表示最新的java版本即可
*
* @return
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
/**
* 1.搜集信息
* 2.生成java源文件
* 核心方法,注解的处理和生成代码都是在这个方法中完成
*
* @param annotations
* @param roundEnv
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (annotations == null || annotations.isEmpty()) return false;
//获取Bind注解类型的元素,这里是类类型TypeElement
Set<? extends Element> bindElement = roundEnv.getElementsAnnotatedWith(StartUp.class);
if (bindElement == null || bindElement.isEmpty()) return false;
try {
generateCode(bindElement);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* @param elements
*/
private void generateCode(Set<? extends Element> elements) throws IOException {
for (Element element : elements) {
// 判断元素的类型为Class
if (element.getKind() == ElementKind.CLASS) {
//由于是在类上注解,那么获取TypeElement
TypeElement typeElement = (TypeElement) element;
// 获取包路径 kt.dongdong.myannotation
String packageName = mElementsUtils.getPackageOf(typeElement).getQualifiedName().toString();
logger.warning(packageName);
//获取类路径 kt.dongdong.myannotation.AppliationA
String classPathName = typeElement.getQualifiedName().toString();
logger.warning(classPathName);
//获取用于生成的类名 AppliationA
String className = getClassName(typeElement, packageName);
logger.warning(className);
//获取注解值
StartUp StartUp = typeElement.getAnnotation(StartUp.class);
boolean isRunUiThread = StartUp.runOnUIThread();
boolean waitThisEnd = StartUp.isWaitThisEnd();
boolean delayCreate = StartUp.isDelayCreate();
boolean lazyCreate = StartUp.isLazyCreate();
// String appId = StartUp.appId();
// System.out.println("appId:" + appId);
// boolean isDebug = StartUp.isDebug();
// System.out.println("isDebug:" + isDebug);
List<? extends TypeMirror> dependenciesClass = APUtils.getTypeMirrorFromAnnotationValue(() -> StartUp.dependenciesClass());
System.out.println(dependenciesClass);
String protocolQualifiedClassName;
String protocolSimpleClassName;
try { // 该类已经被编译
Class<?> clazz = StartUp.protocol();
protocolQualifiedClassName = clazz.getCanonicalName();
protocolSimpleClassName = clazz.getSimpleName();
} catch (MirroredTypeException mte) {// 该类未被编译
DeclaredType classTypeMirror = (DeclaredType) mte.getTypeMirror();
TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
protocolQualifiedClassName = classTypeElement.getQualifiedName().toString();
protocolSimpleClassName = classTypeElement.getSimpleName().toString();
}
int index = protocolQualifiedClassName.lastIndexOf(".");
String protocolPackageName = protocolQualifiedClassName.substring(0, index);
System.out.println("protocolQualifiedClassName:" + protocolQualifiedClassName+" protocolPackageName : "+protocolPackageName+" protocolSimpleClassName :"+protocolSimpleClassName);
// for (int i = 0; i < startUpClass.size(); i++) {
// TypeMirror typeMirror = startUpClass.get(i);
// String aClass = typeMirror.getClass().getSimpleName();
// System.out.println(aClass);
// }
// 缓存KEY
String key = classPathName;
// logger.warning(key);
// 缓存节点信息
List<NodeInfo> nodeInfos = mCache.get(key);
if (nodeInfos == null) {
nodeInfos = new ArrayList<>();
nodeInfos.add(new NodeInfo(packageName, className, classPathName, "appId", false, dependenciesClass,protocolPackageName,protocolSimpleClassName,isRunUiThread,waitThisEnd,delayCreate,lazyCreate));
// 缓存
mCache.put(key, nodeInfos);
} else {
nodeInfos.add(new NodeInfo(packageName, className, classPathName, "appId", false, dependenciesClass,protocolPackageName,protocolSimpleClassName,isRunUiThread,waitThisEnd,delayCreate,lazyCreate));
}
}
}
// 判断临时缓存是否不为空
if (!mCache.isEmpty()) {
// 遍历临时缓存文件
for (Map.Entry<String, List<NodeInfo>> stringListEntry : mCache.entrySet()) {
try {
// 创建文件
createFile(stringListEntry.getValue());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 创建文件,自动生成代码
*/
private void createFile(List<NodeInfo> infos) throws IOException {
NodeInfo info = infos.get(0);
logger.warning("createFile");
// 方法参数
ParameterSpec appIdParamSpec = ParameterSpec.builder(OBJECT, "appId").build();
ParameterSpec isDebugParamSpec = ParameterSpec.builder(TypeName.BOOLEAN, "isDebug").build();
ClassName context = ClassName.get("android.content", "Context");
ParameterSpec savedInstanceState = ParameterSpec.builder(context, "context").build();
ClassName arrayList = ClassName.get("java.util", "ArrayList");
ClassName type_AbProtocolFactory = ClassName.get(IROUTE_GROUP, IROUTE_GROUP_CLASSNAME);
/**
* List<Class<? extends IRouteGroup<?>>>
*/
ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(List.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ParameterizedTypeName.get(
type_AbProtocolFactory,
WildcardTypeName.subtypeOf(OBJECT)
))
)
);
//return
ClassName returnToCreat = ClassName.get(info.getPackageName(), info.getClassName());
ClassName clazzProtocol = ClassName.get(info.getProtocolPackageName(), info.getProtocolSimpleClassName());
//生成方法 createProtocol
MethodSpec.Builder methodCreate = MethodSpec
.methodBuilder(Annotation_MethodCreateProtocol)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addParameter(savedInstanceState)
// .addParameter(appIdParamSpec)
.addParameter(isDebugParamSpec)
.returns(clazzProtocol);
// 给create方法添加代码块
methodCreate.addStatement("$L $L = new $L();\n$L.$L($L,$L)",
info.getProtocolSimpleClassName(),
info.getProtocolSimpleClassName().toLowerCase(),
returnToCreat,
info.getProtocolSimpleClassName().toLowerCase(),
Protocol_MethodName,
savedInstanceState.name,
isDebugParamSpec.name)
.addStatement("return $L", info.getProtocolSimpleClassName().toLowerCase());
//生成方法 dependencies
MethodSpec.Builder methodDependencies = MethodSpec
.methodBuilder(Annotation_MethodDependencies)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(inputMapTypeOfRoot);
// 给dependencies方法添加代码块
methodDependencies.addStatement("$L dependenciesClassList = new $L<>()", inputMapTypeOfRoot, arrayList);
if (info.getDependenciesClass() != null && !info.getDependenciesClass().isEmpty()) {
for (TypeMirror typeMirror : info.getDependenciesClass()) {
String s = typeMirror.toString().substring((typeMirror.toString().lastIndexOf(".") + 1), typeMirror.toString().length());
methodDependencies.addStatement("dependenciesClassList.add($L$L$L)", "StartUp$$", s, ".class");
}
}
methodDependencies.addStatement("return $L", "dependenciesClassList");
/**
* List<Class<? extends IRouteGroup<?>>>
*/
ParameterizedTypeName inputMdddapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(Class.class),clazzProtocol);
//生成方法 getProtocol
MethodSpec.Builder methodGetProtocol = MethodSpec
.methodBuilder(Annotation_MethodGetProtocol)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(inputMdddapTypeOfRoot);
// 给getProtocol方法添加代码块
methodGetProtocol.addStatement("return $L$L", info.getProtocolSimpleClassName(),".class");
//生成方法 runOnMainThread
MethodSpec.Builder methodRunOnMainThread = MethodSpec
.methodBuilder(Annotation_MethodRunOnMainThread)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(boolean.class);
// 给runOnMainThread方法添加代码块
methodRunOnMainThread.addStatement("return $L", info.isRunUiThread());
//生成方法 isWaitThisEnd
MethodSpec.Builder methodIsWaitThisEnd = MethodSpec
.methodBuilder(ANNOTATION_METHODISWAITTHISEND)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(boolean.class);
// 给isWaitThisEnd方法添加代码块
methodIsWaitThisEnd.addStatement("return $L", info.isWaitThisEnd());
//生成方法 isDelayCreate
MethodSpec.Builder methodIsDelayCreat = MethodSpec
.methodBuilder(ANNOTATION_METHODISDELAYCREAT)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(boolean.class);
// 给isDelayCreate方法添加代码块
methodIsDelayCreat.addStatement("return $L", info.isDelayCreate());
//生成方法 isLazyCreate
MethodSpec.Builder methodIsLazyCreate = MethodSpec
.methodBuilder(ANNOTATION_METHODISLAZYCREATE)
.addAnnotation(NonNull.class)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(boolean.class);
// 给isLazyCreate方法添加代码块
methodIsLazyCreate.addStatement("return $L", info.isLazyCreate());
//生成的类xx
TypeSpec type = TypeSpec
.classBuilder(ClassName.get(info.getPackageName(), "StartUp$$" + info.getClassName()))
.addJavadoc(WARNING_TIPS)
.addModifiers(Modifier.PUBLIC)
.superclass(ParameterizedTypeName.get(type_AbProtocolFactory, clazzProtocol))
.addMethod(methodCreate.build())
.addMethod(methodDependencies.build())
.addMethod(methodGetProtocol.build())
.addMethod(methodRunOnMainThread.build())
.addMethod(methodIsWaitThisEnd.build())
.addMethod(methodIsDelayCreat.build())
.addMethod(methodIsLazyCreate.build())
.build();
//生成文件
JavaFile.builder(PACKAGE_OF_GENERATE_FILE, type).build().writeTo(mFiler);
}
/**
* 根据type和package获取类名
*
* @param type
* @param packageName
* @return
*/
private static String getClassName(TypeElement type, String packageName) {
int packageLen = packageName.length() + 1;
return type.getQualifiedName().toString().substring(packageLen)
.replace('.', '$');
}
}
插桩:
Gradle Transform API Android Gradle Plugin 从 1.5.0-beta1 开始支持 Transform API,以允许第三方插件在经过编译的 .class 文件转换为 .dex 文件之前对其进行操纵。
Transform 的工作原理图如下:
Transform方法介绍:
Transform 参考文档:
ASM
要想修改 .class 文件,我们首先得搞清楚 .class 的文件结构,这可不是个简单的事情,好在有大神创建了神器 ASM。
ASM是一个通用的Java字节码操作和分析框架。它可以用来修改现有的类,也可以直接以二进制形式动态生成类。
ASM 开发文档: https://asm.ow2.io/asm4-guide.pdf
简单来讲,ASM 将 .class 文件抽象为 ClassVisitor、MethodVisitor 等对象,类访问器 ClassVisitor 读取和分析 .class 文件,然后发现方法后,交给方法访问器 MethodVisitor 分析修改方法逻辑,当然也可以在类访问器中新增方法。
ASM Bytecode Outline
虽然 ASM 降低了解析和修改 .class 文件的门槛,但其本身的 API 也有一定的学习成本,本文并不打算详细讲解这部分内容,大家可以自行阅读 ASM 的开发文档。
这里借助另一个神器 ASM Bytecode Outline,这是一个 IDEA 插件,兼容 IntelliJ IDEA, Android Studio,通过这个插件我们可以查看 java 文件对应的 ASM 代码,还可以对比两个 java 文件的 ASM 代码的差异,具体到我们的例子,通过对比无日志打印逻辑和有日志打印逻辑的差异 ASM代码就能得到我们需要的 ASM 代码。 https://plugins.jetbrains.com/plugin/5918-asm-bytecode-outline
ASM Bytecode Outline 安装:
ASM Bytecode Outline 的最新版本,无法在 Android Studio 4.1 上使用,只支持 IntelliJ IDEA,我们使用 IntelliJ IDEA 安装。
Preferences -> Plugins -> Markplace 搜索 ASM,下载量第一的就是 ASM Bytecode Outline 插件,安装然后重启 IntelliJ IDEA。
查看 ASM 代码
(类文件或者代码)右键 -> Show Bytecode Outline -> ASMified
显示 ASM 代码差异
(类文件或者代码)右键 -> Show Bytecode Outline -> ASMified -> Show differences
gradle-plugin
在这里不介绍如何自定义gradle-plugin,有兴趣的同学查看
Android Gradle 插件开发入门指南一共规划了三篇文档:
- Android Gradle 插件开发入门指南(一),讲解Gradle Plugin开发的完整流程
- Android Gradle 插件开发入门指南(二),针对Android的Gradle Plugin开发实践
- Android Gradle 插件开发入门指南(三),如何将插件发布到jcenter
public class InitTransform extends Transform {
Project project
static ArrayList<ScanSetting> registerList
static File fileContainsInitClass;
InitTransform(Project project) {
this.project = project
}
/**
* 转换器的名字
* @return
*/
@Override
public String getName() {
return ScanSetting.PLUGIN_NAME
}
/**
* 返回转换器需要消费的数据类型。我们需要处理所有的 class 内容
* @return
*/
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
/**
* 返回转换器的作用域,即处理范围 全项目 jar
* @return
*/
@Override
public Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
/**
* 不支持增量
* @return
*/
@Override
public boolean isIncremental() {
return false
}
/**
* 实现转换逻辑
* @param context
* @param inputs
* @param referencedInputs
* @param outputProvider
* @param isIncremental
* @throws IOException
* @throws TransformException
* @throws InterruptedException
*/
@Override
public void transform(Context context, Collection<TransformInput> inputs
, Collection<TransformInput> referencedInputs
, TransformOutputProvider outputProvider
, boolean isIncremental) throws IOException, TransformException, InterruptedException {
Logger.i("Start scan register info in jar file.");
long startTime = System.currentTimeMillis();
boolean leftSlash = File.separator == '/'
// 由于不支持增量编译,清空 OutputProvider 的内容
if (!isIncremental){
outputProvider.deleteAll()
}
inputs.each { TransformInput input ->
// 处理 jar 输入
input.jarInputs.each { JarInput jarInput ->
String destName = jarInput.name
// rename jar files
def hexName = DigestUtils.md5Hex(jarInput.file.absolutePath)
if (destName.endsWith(".jar")) {
destName = destName.substring(0, destName.length() - 4)
}
// TODO 编辑 class 文件,添加日志打印逻辑
// 有输入进来就必须将其输出,否则会出现类缺失的问题,
// 无论是否经过转换,我们都需要将输入目录复制到目标目录
File src = jarInput.file
File dest = outputProvider.getContentLocation(destName + "_" + hexName, jarInput.contentTypes, jarInput.scopes, Format.JAR)
//scan jar file to find classes
if (ScanUtil.shouldProcessPreDexJar(src.absolutePath)) {
ScanUtil.scanJar(src, dest)
}
FileUtils.copyFile(src, dest)
}
// 处理目录输入
input.directoryInputs.each { DirectoryInput directoryInput ->
// TODO 编辑 class 文件,添加日志打印逻辑
// 有输入进来就必须将其输出,否则会出现类缺失的问题,
// 无论是否经过转换,我们都需要将输入目录复制到目标目录
File dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
String root = directoryInput.file.absolutePath
if (!root.endsWith(File.separator))
root += File.separator
directoryInput.file.eachFileRecurse { File file ->
def path = file.absolutePath.replace(root, '')
if (!leftSlash) {
path = path.replaceAll("\\\\", "/")
}
if(file.isFile() && ScanUtil.shouldProcessClass(path)){
ScanUtil.scanClass(file)
}
}
// copy to dest
FileUtils.copyDirectory(directoryInput.file, dest)
}
}
Logger.i('Scan finish, current cost time ' + (System.currentTimeMillis() - startTime) + "ms")
if (fileContainsInitClass) {
registerList.each { ext ->
Logger.i('Insert register code to file ' + fileContainsInitClass.absolutePath)
if (ext.classList.isEmpty()) {
Logger.e("No class implements found for superclass:" + ext.mySuperName)
} else {
ext.classList.each {
Logger.i(it)
}
InitCodeGenerator.insertInitCodeTo(ext)
}
}
}
Logger.i("Generate code finish, current cost time: " + (System.currentTimeMillis() - startTime) + "ms")
}
}
ASM插入代码修改 .class 文件
在 ASM 中,提供了一个 ClassReader 类,这个类可以直接由字节数组或由 class 文件间接的获得字节码数据,它能正确的分析字节码,构建出抽象的树在内存中表示字节码。它会调用 accept 方法,这个方法接受一个继承于 ClassVisitor 抽象类的对象实例作为参数,然后依次调用 ClassVisitor 抽象类的各个方法。
ClassWriter 类编写器,继承于 ClassVisitor,实现了具体的字节码编辑功能。各个 ClassVisitor 通过职责链 (Chain-of-responsibility) 模式,可以非常简单的封装对字节码的各种修改,而无须关注字节码的字节偏移,因为这些实现细节对于用户都被隐藏了,用户要做的只是覆写相应的 visit 函数。
我们首先需要实现我们自己的 ClassVisitor,实现里面相关的 visit 函数,来添加日志打印代码:
ClassVisitor主要是读取class
class MyClassVisitor extends ClassVisitor {
MyClassVisitor(int api, ClassVisitor cv) {
super(api, cv)
}
void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces)
// 访问到了具体的类信息,name 当前类的完整类名,superName 表示父类完整类名,access 可访问性
}
@Override
MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions)
//generate code into this method
if (name == ScanSetting.GENERATE_TO_METHOD_NAME) {
mv = new RouteMethodVisitor(Opcodes.ASM5, mv)
}
return mv
}
}
MethodVisitor主要是修改class
class RouteMethodVisitor extends MethodVisitor {
RouteMethodVisitor(int api, MethodVisitor mv) {
super(api, mv)
}
@Override
void visitInsn(int opcode) {
//generate code before return
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) {
extension.classList.each { name ->
// name = name.replaceAll("/", ".")
/**
* 生成字节码对象
*/
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(Opcodes.LCONST_0, l0);
mv.visitLdcInsn(Type.getType("L"+name+";"));
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ScanSetting.GENERATE_TO_CLASS_NAME, ScanSetting.REGISTER_METHOD_NAME, "(Ljava/lang/Class;)V", false);
}
}
super.visitInsn(opcode)
}
@Override
void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack, maxLocals)
}
}
StartUp:
public class ProtocolManager {
private static final String TAG = ProtocolManager.class.getSimpleName();
private Context mContext;
private Application mApplication;
private boolean isDebug;
private volatile static boolean registerByPlugin;
private boolean sIsMainProcess;
//wait
private static final int WAITTIME = 10000;
private CountDownLatch isWaitThisEndCountDownLatch;
private static AtomicInteger isWaitThisEndCount = new AtomicInteger();//保存需要wait的Task的数量
private static volatile List<AbProtocolFactory<? extends IBaseProtocol>> mIsWaitThisEndCountTasks = new ArrayList<>();
//delay
private Queue<AbProtocolFactory<? extends IBaseProtocol>> mDelayTasks = new LinkedList<AbProtocolFactory<? extends IBaseProtocol>>();
private MessageQueue.IdleHandler mIdleHandler = new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
if (mDelayTasks.size() > 0) {
AbProtocolFactory<? extends IBaseProtocol> poll = mDelayTasks.poll();
if (poll != null) {
new StartUpDispatchRunnable(poll, ProtocolManager.this, mContext).run();
poll.setSend(true);
}
}
return !mDelayTasks.isEmpty();
}
};
//lazy
@NonNull
private ConcurrentHashMap<Class<? extends IBaseProtocol>, AbProtocolFactory<? extends IBaseProtocol>> mLzyMap = new ConcurrentHashMap<>();
/**
* 缓存初始化后的class
*/
@NonNull
private ConcurrentHashMap<Class<? extends IBaseProtocol>, IBaseProtocol> mProtocolMap = new ConcurrentHashMap<>();
private static List<AbProtocolFactory<? extends IBaseProtocol>> mAllTasks = new ArrayList<>();
private static List<Class<? extends AbProtocolFactory<? extends IBaseProtocol>>> mClsAllTasks = new ArrayList<>();
private volatile List<AbProtocolFactory<? extends IBaseProtocol>> mMainThreadTasks = new ArrayList<>();
/**
* 例如 A -> B C -> B
* <p>
* key:B
* value:A+C
*/
private static ConcurrentHashMap<Class<? extends AbProtocolFactory<? extends IBaseProtocol>>, ArrayList<AbProtocolFactory<? extends IBaseProtocol>>> mDependedHashMap = new ConcurrentHashMap<>();
private volatile static ProtocolManager instance = null;
public static ProtocolManager getInstance() {
if (instance == null) {
synchronized (ProtocolManager.class) {
if (instance == null) {
instance = new ProtocolManager();
}
}
}
return instance;
}
public synchronized void init(Application application, boolean isDebug) {
sIsMainProcess = Utils.isMainProcess(application);
this.mContext = application.getApplicationContext();
this.mApplication = application;
this.isDebug = isDebug;
long startInit = System.currentTimeMillis();
//加载插件插入字节码
insertCodeByMSA();
if (registerByPlugin) {
Log.e("regist moudle by _annotation_register plugin.");
startInit();
}
startAwait();
Log.e(TAG, "regist moudle finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");
}
/**
* ASM忘此方法插入初始化的代码
*/
private void insertCodeByMSA() {
registerByPlugin = false;
// auto generate register code by gradle plugin: _annotation_register
// looks like below:
// registerModule(Annotation$$ApmModule.class,new Annotation$$ApmModule());
// registerModule(Annotation$$ApmModule.class,new Annotation$$ApmModule());
}
/**
* method for _annotation_register plugin to register moudle
*/
private static <T extends IBaseProtocol> void registerModule(Class<? extends AbProtocolFactory<T>> abProtocolFactoryClass, AbProtocolFactory<T> abProtocolFactory) {
Log.e(abProtocolFactoryClass.getSimpleName() + "-------registerModule");
markRegisteredByPlugin();
/**
* 记录每个组件的前置依赖项
*/
if (abProtocolFactory.dependencies() != null && abProtocolFactory.dependencies().size() > 0) {
for (Class<? extends AbProtocolFactory<? extends IBaseProtocol>> cls : abProtocolFactory.dependencies()) {
if (mDependedHashMap.get(cls) == null) {
mDependedHashMap.put(cls, new ArrayList<AbProtocolFactory<? extends IBaseProtocol>>());
}
mDependedHashMap.get(cls).add(abProtocolFactory);
}
}
// 非主线程且需要wait的,主线程不需要CountDownLatch也是同步的
if (ifNeedWait(abProtocolFactory)) {
mIsWaitThisEndCountTasks.add(abProtocolFactory);
isWaitThisEndCount.getAndIncrement();
}
mAllTasks.add(abProtocolFactory);
mClsAllTasks.add(abProtocolFactoryClass);
}
/**
* mark already registered by _annotation_register plugin
*/
private static void markRegisteredByPlugin() {
if (!registerByPlugin) {
registerByPlugin = true;
}
}
public <T extends IBaseProtocol> T getProtocol(@NonNull Class<T> clz) {
if (mProtocolMap == null) {
throw new IllegalStateException("regist moudle fail by _startup_register plugin.");
}
if (!mProtocolMap.containsKey(clz)) {
throw new RuntimeException("Not found " + clz.getSimpleName() + " in this map!");
}
IBaseProtocol obj = (IBaseProtocol) mProtocolMap.get(clz);
if (obj == null) {
throw new RuntimeException("found " + clz.getSimpleName() + " in this map is null !");
}
return clz.cast(obj);
}
/**
* 懒加载初始化 目前只支持主线程, 后续会添加子线程
*
* @param clz
* @param listenering
* @param <T>
* @return
*/
public <T extends IBaseProtocol> void getLazyProtocol(@NonNull Class<T> clz, LazyStartUpListenering<T> listenering) {
if (mProtocolMap == null) {
if (listenering != null) {
listenering.lazyStartUpError();
}
} else {
if (mProtocolMap.containsKey(clz)) {
if (listenering != null) {
listenering.lazyStartUpSuccess(getProtocol(clz));
}
} else {
AbProtocolFactory<? extends IBaseProtocol> abProtocolFactory = mLzyMap.get(clz);
if (abProtocolFactory.runOnUiThread()) {
long time = System.currentTimeMillis();
new StartUpDispatchRunnable(abProtocolFactory, this, mContext).run();
Log.i("lazy real main " + abProtocolFactory.getProtocol().getSimpleName() + " run " +
(System.currentTimeMillis() - time) + " millisecond !!!!!!!!!");
lazyCreateMain(clz, listenering);
} else {
Future<?> submit = StartUpDispatcherExecutor.getCPUExecutor().submit(new StartUpDispatchRunnable(abProtocolFactory, this, mContext));
if (submit == null) {
if (listenering != null) {
listenering.lazyStartUpError();
}
} else {
while (true) {
boolean done = submit.isDone();
if (done) {
if (listenering != null) {
listenering.lazyStartUpSuccess(getProtocol(clz));
}
break;
}
}
}
}
abProtocolFactory.setSend(true);
}
}
}
/**
* 懒加载初始化主线程
*
* @param clz
* @param listenering
* @param <T>
*/
private <T extends IBaseProtocol> void lazyCreateMain(@NonNull Class<T> clz, LazyStartUpListenering<T> listenering) {
if (!mProtocolMap.containsKey(clz)) {
if (listenering != null) {
listenering.lazyStartUpError();
}
} else {
IBaseProtocol obj = (IBaseProtocol) mProtocolMap.get(clz);
if (obj == null) {
if (listenering != null) {
listenering.lazyStartUpError();
}
} else {
if (listenering != null) {
listenering.lazyStartUpSuccess(clz.cast(obj));
}
}
}
}
/**
* 打印每个组件的依赖信息
*/
private void printDependedMsg() {
Log.i("needWait size : " + (isWaitThisEndCount.get()));
for (Class<? extends AbProtocolFactory<? extends IBaseProtocol>> cls : mDependedHashMap.keySet()) {
Log.i(mDependedHashMap.get(cls).size() + " num is depend of " + cls.getSimpleName());
for (AbProtocolFactory<? extends IBaseProtocol> task : mDependedHashMap.get(cls)) {
Log.i("printDependedMsg " + task.getClass().getSimpleName() + "--->" + cls.getSimpleName());
}
}
}
@UiThread
public void startInit() {
if (Looper.getMainLooper() != Looper.myLooper()) {
throw new RuntimeException("must be called from UiThread");
}
if (mAllTasks.size() > 0) {
printDependedMsg();
//拓扑排序
mAllTasks = TaskSortUtil.getSortResult(mAllTasks, mClsAllTasks);
isWaitThisEndCountDownLatch = new CountDownLatch(isWaitThisEndCount.get());
/**
* 分发任务
*/
for (AbProtocolFactory<? extends IBaseProtocol> task : mAllTasks) {
if (task.isLazyCreate()) {
mLzyMap.put(task.getProtocol(), task);
} else if (task.isDelayCreate()) {
mDelayTasks.add(task);
} else {
if (task.runOnUiThread()) {
//主线程的任务缓存起来
mMainThreadTasks.add(task);
markTaskDone(task);
} else {
// 子线程直接分发,是否执行取决于线程池
Future<?> submit = StartUpDispatcherExecutor.getCPUExecutor().submit(new StartUpDispatchRunnable(task, this, mContext));
}
task.setSend(true);
}
}
/**
* 初始化主线程
*/
for (AbProtocolFactory<? extends IBaseProtocol> task : mMainThreadTasks) {
long time = System.currentTimeMillis();
new StartUpDispatchRunnable(task, this, mContext).run();
Log.i("real main " + task.getProtocol().getSimpleName() + " run " +
(System.currentTimeMillis() - time) + " millisecond !!!!!!!!!");
}
}
}
/**
* 异步初始化
* 通知Children一个前置任务已完成
*
* @param mTask 例如:A --> B
* B == mTask
* 此处的意思是通知A,B初始化完成了
*/
public void satisfyChildren(AbProtocolFactory<? extends IBaseProtocol> mTask) {
ArrayList<AbProtocolFactory<? extends IBaseProtocol>> abProtocolFactories = mDependedHashMap.get(mTask.getClass());
if (abProtocolFactories != null && abProtocolFactories.size() > 0) {
for (AbProtocolFactory<? extends IBaseProtocol> task : abProtocolFactories) {
task.satisfy();
}
}
}
public void putProtocolMap(Class<? extends IBaseProtocol> mTaskProtocol, IBaseProtocol protocol) {
Log.i("putProtocolMap " + mTaskProtocol.getSimpleName() + " -------- " + protocol.getClass().getSimpleName());
mProtocolMap.put(mTaskProtocol, protocol);
}
public boolean isDebug() {
return isDebug;
}
/**
* 异步task是否需要阻塞UiThread
*
* @param task
* @return
*/
private static boolean ifNeedWait(AbProtocolFactory<? extends IBaseProtocol> task) {
return !task.runOnUiThread() && task.isWaitThisEnd();
}
/**
* 异步初始化 task完成
*
* @param task
*/
public void markTaskDone(AbProtocolFactory<? extends IBaseProtocol> task) {
if (ifNeedWait(task)) {
mIsWaitThisEndCountTasks.remove(task);
isWaitThisEndCountDownLatch.countDown();
isWaitThisEndCount.getAndDecrement();
}
}
@UiThread
public void startAwait() {
try {
if (isDebug) {
Log.i("is wait count still has " + isWaitThisEndCount.get());
for (AbProtocolFactory<? extends IBaseProtocol> task : mIsWaitThisEndCountTasks) {
Log.i("needWait: " + task.getClass().getSimpleName());
}
}
if (isWaitThisEndCount.get() > 0) {
isWaitThisEndCountDownLatch.await(WAITTIME, TimeUnit.MILLISECONDS);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void startDelayInit() {
Looper.myQueue().addIdleHandler(mIdleHandler);
}
public Application getmApplication() {
return mApplication;
}
}
ASM插入代码执行
/**
* ASM忘此方法插入初始化的代码
*/
private void insertCodeByMSA() {
registerByPlugin = false;
// auto generate register code by gradle plugin: _annotation_register
// looks like below:
// registerModule(Annotation$$ApmModule.class,new Annotation$$ApmModule());
// registerModule(Annotation$$ApmModule.class,new Annotation$$ApmModule());
}
反编译查看ProtocolManager里的insertCodeByMSA方法
private void insertCodeByMSA() {
registerByPlugin = false;
registerModule(StartUp$$CrashProtocolImpl.class, new AbProtocolFactory<ICrashProtocol>() { // from class: StartUp$$CrashProtocolImpl
@Override // AbProtocolFactory
@NonNull
public ICrashProtocol createProtocol(Context context, boolean isDebug) {
ICrashProtocol icrashprotocol = new CrashProtocolImpl();
icrashprotocol.onCreate(context, isDebug);
return icrashprotocol;
}
@Override // AbProtocolFactory
@NonNull
public List<Class<? extends AbProtocolFactory<?>>> dependencies() {
List<Class<? extends AbProtocolFactory<?>>> dependenciesClassList = new ArrayList<>();
dependenciesClassList.add(StartUp$$NetworkProtocolImpl.class);
return dependenciesClassList;
}
@Override // AbProtocolFactory
@NonNull
public Class<ICrashProtocol> getProtocol() {
return ICrashProtocol.class;
}
@Override // AbProtocolFactory
@NonNull
public boolean runOnUiThread() {
return false;
}
@Override // AbProtocolFactory
@NonNull
public boolean isWaitThisEnd() {
return false;
}
@Override // AbProtocolFactory
@NonNull
public boolean isDelayCreate() {
return false;
}
@Override // AbProtocolFactory
@NonNull
public boolean isLazyCreate() {
return true;
}
});
}
生成的注解类:
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY StartUp. */
public class StartUp$$CrashProtocolImpl extends AbProtocolFactory<ICrashProtocol> {
@NonNull
@Override
public ICrashProtocol createProtocol(Context context, boolean isDebug) {
ICrashProtocol icrashprotocol = new CrashProtocolImpl();
icrashprotocol.onCreate(context,isDebug);
return icrashprotocol;
}
@NonNull
@Override
public List<Class<? extends AbProtocolFactory<?>>> dependencies() {
java.util.List<java.lang.Class<? extends AbProtocolFactory<?>>> dependenciesClassList = new java.util.ArrayList<>();
dependenciesClassList.add(StartUp$$NetworkProtocolImpl.class);
return dependenciesClassList;
}
@NonNull
@Override
public Class<ICrashProtocol> getProtocol() {
return ICrashProtocol.class;
}
@NonNull
@Override
public boolean runOnUiThread() {
return false;
}
@NonNull
@Override
public boolean isWaitThisEnd() {
return false;
}
@NonNull
@Override
public boolean isDelayCreate() {
return false;
}
@NonNull
@Override
public boolean isLazyCreate() {
return true;
}
}
Application调用:
StartUpLunch.getInstance().init(this,BuildConfig.DEBUG);
实战:
crash组件依赖network组件,并且异步的懒加载初始化
@StartUp(protocol = ICrashProtocol.class,isLazyCreate = true,runOnUIThread = false,dependenciesClass = NetworkProtocolImpl.class)
public class CrashProtocolImpl implements ICrashProtocol {
@Override
public void onCreate(Context context, boolean b) {
Log.e(MainActivity.TAG, "rnProtocolImpl: " + "onCreate, isDebug: "+b);
}
@Override
public String name() {
return "rn protocol";
}
@Override
public String version() {
return "1.0.0";
}
@Override
public void onDestroy() {
}
@Override
public void postRNException(Throwable thr, Map<String, String> extraInfo) {
}
@Override
public void postFlutterException(Throwable thr, Map<String, String> extraInfo) {
}
}
使用:懒加载初始化Crash组件
ProtocolManager.getInstance().getLazyProtocol(ICrashProtocol.class, new LazyStartUpListenering<ICrashProtocol>() {
@Override
public void lazyStartUpSuccess(ICrashProtocol iCrashProtocol) {
String name = iCrashProtocol.name();
String version = iCrashProtocol.version();
Log.e(TAG, "ICrashProtocol: name:" + name + " version:" + version);
}
@Override
public void lazyStartUpError() {
}
});
异步初始化获取目标组件:
INetworkProtocol networkProtocol = ProtocolManager.getInstance().getProtocol(INetworkProtocol.class);
后面会附上Demo