怎么将 Android 程序做成插件化的形式?

只是一个纯技术上的疑惑:Android程序每次更新都要下载一个完整的apk,而很多时候软件只是更新了一个小功能而已,这样的话,就显得很麻烦。能不能把a…
关注者
1,285
被浏览
166,800
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

背景:

最近做了移动开放平台(mpaas) ,由于不知道各模块组件的初始化类以及appid等信息, 最后采用了注解,插桩的方式初始化各个模块组件。

目标:

KAPT + JavaPoet + Gradle Transform API + ASM + ASM ByteCode onLine + startup

startup: 同步初始化、异步初始化、延迟初始化、懒加载初始化,支持依赖顺序,主界面等待某个组件初始化完毕等功能

注解:

APT(Annotation Processor Tool)即 注解处理器,是一种处理注解的工具,确切的说它是javac的一个工具,它用在 编译时 扫描和处理注解。

常用的开源注解框架 ButterKnifeDaggerEventBus 等注解框架

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 的工作原理图如下:

添加图片注释,不超过 140 字(可选)

Transform方法介绍:

添加图片注释,不超过 140 字(可选)

Transform 参考文档:

https://developer.android.com/reference/tools/gradle-api/4.1/com/android/build/api/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 插件开发入门指南一共规划了三篇文档:

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