Git Product home page Git Product logo

appmethodtime's Introduction

AppMethodTime

一个测量函数耗时的库(更新readme)

背景:这次没什么背景就是知识总结,Gradle自定义插件+Transform+javassist 做了个 JakeWharton大神hugo库类似的东西

特别说明:本文已经稍后送上的代码参考以及抄袭了(http://blog.csdn.net/eclipsexys/article/details/50973205) (https://github.com/HalfStackDeveloper/Savior), 还有巴掌大神的库(https://github.com/JeasonWong/CostTime) ,十分鸣谢巴掌大神手把手教我改代码 (有用到代码的同学,联系我,有侵必删)

源码下载地址:(https://github.com/zjw-swun/AppMethodTime) 觉得有帮助可以给个star

简单介绍一下:Transform 参与class打包的Android gradle plugin的api,javassist 是生成或者修改class字节码的库。借由这2个特性,我们就可以完成类似于JakeWharton大神hugo库类似的东西。

#1. 2种生成自定义插件的方式 1.新建一个BuildSrc module (lib module ,BuildSrc 名字固定),从src(包括src)开始以下文件或者文件夹都是自己建的(具体步骤就不讲了,CSDN 简书上都有讲) QQ图片20170502230318.png

2.比第1种方式名字可以不固定,但是需要带上META那个文件夹,

QQ图片20170502231259.png 该build.gradle 需要加一个task

//设置maven deployer
uploadArchives {
    repositories {
        mavenDeployer {
            //设置插件的GAV参数
            pom.groupId = 'com.branch.plugin'
            pom.artifactId = 'dellog'
            pom.version = '1.0.0'
            //文件发布到下面目录
            repository(url: uri('../repo'))
        }
    }
}

然后执行uploadArchives 上传 具体不细说看代码吧

核心就是MyTransform类,以及MyInject类 MyInject类里面的代码如下

package com.zjw.plugin

import javassist.*

public class MyInject {

    private static ClassPool pool = ClassPool.getDefault()
    //注意这里需要替换你的anroid.jar路径
    static String androidJar = "D:\\Application\\Android\\sdkUpDate\\platforms\\android-24\\android.jar"
    static String myPackageName = "com.zjw.appmethodtime";
    static String myCostTimeAnnotation = "@com.zjw.appmethodtime.CostTime";
    static String CostTime = "CostTime";

    public static void injectDir(String path, String packageName, boolean enabeCostTime) {
        pool.appendClassPath(path)
        // 以下为windows环境下你的相应android.jar路径
        pool.insertClassPath(androidJar)

        println("enabeCostTime is " + enabeCostTime)

        File dir = new File(path)
        if (dir.isDirectory()) {
            dir.eachFileRecurse { File file ->
                String filePath = file.absolutePath
                //确保当前文件是class文件,并且不是系统自动生成的class文件以及注解文件
                if (filePath.endsWith(".class")
                        && !filePath.contains('R$')
                        && !filePath.contains('R.class')
                        && !filePath.contains("BuildConfig.class")
                        && !filePath.contains("CostTime")
                ) {
                    // 判断当前目录是否是在我们的应用包里面
                    int index = filePath.indexOf(packageName);
                    boolean isMyPackage = index != -1;
                    if (isMyPackage) {
                        int end = filePath.length() - 6 // .class = 6
                        String className = filePath.substring(index, end).replace('\\', '.').replace('/', '.')
                        //开始修改class文件
                        CtClass c = pool.getCtClass(className)

                        if (c.isFrozen()) {
                            c.defrost()
                        }
                        pool.importPackage(myPackageName)

                        //给类添加计时变量
                        CtField startTime = new CtField(CtClass.longType, "sStart", c);
                        startTime.setModifiers(Modifier.STATIC);
                        c.addField(startTime);

                        //给类添加计时变量
                        CtField endTime = new CtField(CtClass.longType, "sEnd", c);
                        endTime.setModifiers(Modifier.STATIC);
                        c.addField(endTime);

                        //遍历类的所有方法
                        CtMethod[] methods = c.getDeclaredMethods();
                        for (CtMethod method : methods) {
                            println("method ====" + method.longName)
                            if (enabeCostTime
                                    && method.getAvailableAnnotations() != null
                                    && method.getAvailableAnnotations().length >= 1
                                    && "${method.getAvailableAnnotations()[0]}".contains(CostTime)
                            ) {
                                insertCostTimeCode(method)
                            } else if (!enabeCostTime) {
                                insertCostTimeCode(method)
                            }
                        }//END   for (CtMethod method : methods)
                        c.writeFile(path)
                        c.detach()
                    }//END if(isMyPackage)
                }
            }
        }
    }

    private static void insertCostTimeCode(CtMethod method) {
        //插入到函数第一句
        StringBuilder startInjectStr = new StringBuilder();
        startInjectStr.append("sStart = System.nanoTime();");
        print("方法第一句插入了:" + startInjectStr.toString() + "语句\n")
        method.insertBefore(startInjectStr.toString())

        //插入到函数最后一句
        StringBuilder endInjectStr = new StringBuilder();
        endInjectStr.append("sEnd = System.nanoTime();\n");
        endInjectStr.append("android.util.Log.e(\"AppMethodTime\",");
        endInjectStr.append("\"" + method.longName + "\"");
        endInjectStr.append("+(sEnd - sStart)/1000000+\" (毫秒)\");");
        print("方法最后一句插入了:" + endInjectStr.toString() + "语句\n")
        method.insertAfter(endInjectStr.toString(), true)
    }
}

#2. 插件自定义的配置字段

pluginsrc{
    message = 'hello gradle plugin'
    cost = true
}

在MyTransform类中

 MyInject.injectDir(directoryInput.file.absolutePath,
                        "com" + File.separator + "zjw" + File.separator + "appmethodtime",
                        project.pluginsrc.cost)

使用了。如果你想在自定义插件中自己创建的task中在你的app编译生成apk前读取

pluginsrc{
    message = 'hello gradle plugin'
    cost = true
}

cost 等字段值的话,你得加上 preBuild.dependsOn appPlugin

不说了自定义插件的初级知识应该都在这里了 效果图

QQ图片20170512022507.png 说明:如果函数返回类型是void log中对应return is null

2019/7/6 新增支持修改aar和jar 中class插入字节码

添加aarOrJarPath 配置字段,填入目标jar或者aar路径 执行gradle面板对应项目中other目录appMethodJarOrAar 任务即可在aarOrJarPath 配置的同目录下生成带 Target_前缀的目标jar或者aar文件

2019/7/13 增加自定义lint

感谢 https://github.com/Omooo/CustomLint 的作者

调试Gradle 插件的方法

  1. 运行按钮 -> edit config -> 命名 + 指定要调试的源码位置 ->apply
  2. studio 命令行中 : gradle assembleDebug -Dorg.gradle.debug=true --no-daemon
  3. studio 面板debug启动 按钮

appmethodtime's People

Contributors

harlber avatar zjw-swun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

appmethodtime's Issues

fail to compile

build log:

Error:Execution failed for task ':app:transformClassesWithMyTransForDebug'.

1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.