背景
通常我们会遇到项目中存在很多模块的情况,每次构建都会花费好久,但是又不知道每个模块耗费多久,因此使用该工具可以很方便的检测,用来决定如何优化项目结构
实现效果
构建总耗时:6637ms
app, 总耗时:4943ms
xxx-util, 总耗时:90ms
lib, 总耗时:148ms
xxx_browser, 总耗时:22ms
videoxxx, 总耗时:33ms
xxxmodule, 总耗时:90ms
xxx_message, 总耗时:69ms
xxx_notchtoolslib, 总耗时:46ms
xxx_zxing, 总耗时:27ms
xxx_emojilib, 总耗时:36ms
xxx_magicindicator, 总耗时:20ms
xxx_uselogin, 总耗时:46ms
xxxPlugin, 总耗时:92ms
xxxcommonlib, 总耗时:53ms
xxxmvvm, 总耗时:55ms
这样很容易就能看到每个模块耗时多久。
使用源码方式
- 在 app/build.gradle 添加
...
apply from: "../buildTrace.gradle"
...
- 项目根目录下
buildTrace.gradle
import java.text.SimpleDateFormat
/**
* 监控构建耗时
*
* 记录构建过程中的每个任务的耗时,并写入文件中 .build_history/buildTimeLog_yy_MM_dd_HH_mm_ss.log中
*/
class BuildTimeListener implements TaskExecutionListener, BuildListener {
private final String BUILD_LOG_FILE_DIR = ".build_history"
private final String BUILD_LOG_FILE_PATH = "buildTimeLog"
private long taskStartTime;
private long buildStartTime;
private int taskCounts = 0;
private StringBuilder sb = new StringBuilder()
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
private SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss")
private SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
private Map<String, Long> moduleTimeMap = new HashMap<>()
BuildTimeListener() {
buildStartTime = System.currentTimeMillis()
sb.append("构建时间:" + sdf3.format(new Date()) + "\n")
sb.append("开始构建----------------------\n")
}
@Override
void buildStarted(Gradle gradle) {
}
@Override
void settingsEvaluated(Settings settings) {
}
@Override
void projectsLoaded(Gradle gradle) {
}
@Override
void projectsEvaluated(Gradle gradle) {
}
/**
* 构建完成回调
* @param result The result of the build. Never null.
*/
@Override
void buildFinished(BuildResult result) {
if(taskCounts<5) return
long buildCost = System.currentTimeMillis() - buildStartTime
sb.append("构建结束------------------" + sdf3.format(new Date()) + "----\n")
sb.append("构建总耗时:" + buildCost + "ms \n")
for (Map.Entry<String, Long> entry : moduleTimeMap.entrySet()) {
sb.append(entry.key + ", 总耗时:" + entry.value + "ms \n")
}
//输出到文件
String text = sb.toString()
writeToFile(BUILD_LOG_FILE_PATH, text)
}
/**
* 任务执行开始
* @param task The task about to be executed. Never null.
*/
@Override
void beforeExecute(Task task) {
taskStartTime = System.currentTimeMillis();
task.name
String moduleName = task.path.split(":")[1]
String taskName=task.name
// moduleTimeMap.put(moduleName, 0)
}
/**
* 任务执行结束
* @param task The task which was executed. Never null.
* @param state The task state. If the task failed with an exception, the exception is available in this
*/
@Override
void afterExecute(Task task, TaskState state) {
long cost = System.currentTimeMillis() - taskStartTime;
System.out.println("任务:" + task.name + "," + task.path + ",耗时:" + cost + " \n")
String timeStamp = sdf3.format(new Date())
String moduleName = task.path.split(":")[1]
String taskName=task.name
Long preTotalTime = moduleTimeMap.get(moduleName)
if (preTotalTime != null) {
preTotalTime+=cost
moduleTimeMap.put(moduleName, preTotalTime)
} else {
moduleTimeMap.put(moduleName, cost)
}
sb.append(timeStamp + ": 【" + moduleName + "】" + taskName + "=" + cost + "ms \n")
taskCounts++
}
private void writeToFile(String fname, String text) {
File dir = new File(BUILD_LOG_FILE_DIR)
if (!dir.exists()) {
dir.mkdir()
}
File file = new File(BUILD_LOG_FILE_DIR + File.separator + fname + "_" + sdf2.format(new Date()) + ".log")
file.write(text)
}
}
gradle.addListener new BuildTimeListener()
如果查看?
当运行 app 项目,会自动在项目的根目录下创建 .build_history 文件夹,并且根据时间戳把耗时日志保存到本地,开始是每个模块的单独任务,最后进行汇总,模块的使用时间。查看对应文件即可。
.
├── app
├── build.gradle
├── buildTrace.gradle
├── .build_history
│ ├── buildTimeLog_2022_02_15_18_34_26.log
│ └── buildTimeLog_2022_02_15_18_35_50.log
├── gradle
└── testlib
给一个完整文件示例:
buildTimeLog_2022_02_15_18_35_50.log
构建时间:2022-02-15 18:35:42:193
开始构建----------------------
2022-02-15 18:35:42:280: 【app】preBuild=0ms
2022-02-15 18:35:42:281: 【app】preDebugBuild=0ms
2022-02-15 18:35:42:281: 【testlib】preBuild=0ms
2022-02-15 18:35:42:282: 【testlib】preDebugBuild=0ms
2022-02-15 18:35:42:285: 【testlib】compileDebugAidl=2ms
2022-02-15 18:35:42:287: 【app】compileDebugAidl=1ms
2022-02-15 18:35:42:288: 【testlib】packageDebugRenderscript=0ms
2022-02-15 18:35:42:290: 【app】compileDebugRenderscript=1ms
2022-02-15 18:35:42:409: 【app】dataBindingMergeDependencyArtifactsDebug=118ms
2022-02-15 18:35:42:418: 【app】dataBindingMergeGenClassesDebug=9ms
2022-02-15 18:35:42:419: 【app】generateDebugResValues=0ms
2022-02-15 18:35:42:420: 【app】generateDebugResources=0ms
2022-02-15 18:35:42:422: 【testlib】compileDebugRenderscript=0ms
2022-02-15 18:35:42:423: 【testlib】generateDebugResValues=1ms
2022-02-15 18:35:42:423: 【testlib】generateDebugResources=0ms
2022-02-15 18:35:42:426: 【testlib】packageDebugResources=2ms
2022-02-15 18:35:43:409: 【app】generateDebugBuildConfig=3ms
2022-02-15 18:35:43:422: 【app】javaPreCompileDebug=1ms
2022-02-15 18:35:43:423: 【testlib】writeDebugAarMetadata=0ms
2022-02-15 18:35:43:443: 【app】createDebugCompatibleScreenManifests=1ms
2022-02-15 18:35:43:444: 【app】extractDeepLinksDebug=1ms
2022-02-15 18:35:43:445: 【testlib】extractDeepLinksDebug=1ms
2022-02-15 18:35:43:449: 【testlib】processDebugManifest=2ms
2022-02-15 18:35:43:622: 【app】processDebugMainManifest=172ms
2022-02-15 18:35:43:627: 【app】processDebugManifest=4ms
2022-02-15 18:35:43:631: 【app】checkDebugAarMetadata=3ms
2022-02-15 18:35:43:634: 【testlib】compileDebugLibraryResources=1ms
2022-02-15 18:35:43:639: 【testlib】parseDebugLocalResources=5ms
2022-02-15 18:35:43:648: 【testlib】generateDebugBuildConfig=1ms
2022-02-15 18:35:43:650: 【testlib】javaPreCompileDebug=0ms
2022-02-15 18:35:43:651: 【app】mergeDebugNativeDebugMetadata=1ms
2022-02-15 18:35:43:653: 【app】mergeDebugShaders=1ms
2022-02-15 18:35:43:655: 【app】compileDebugShaders=1ms
2022-02-15 18:35:43:656: 【app】generateDebugAssets=0ms
2022-02-15 18:35:43:658: 【testlib】mergeDebugShaders=2ms
2022-02-15 18:35:43:660: 【testlib】compileDebugShaders=1ms
2022-02-15 18:35:43:660: 【testlib】generateDebugAssets=0ms
2022-02-15 18:35:43:662: 【testlib】packageDebugAssets=1ms
2022-02-15 18:35:43:683: 【app】mergeDebugAssets=20ms
2022-02-15 18:35:43:685: 【app】compressDebugAssets=1ms
2022-02-15 18:35:43:687: 【app】processDebugJavaRes=1ms
2022-02-15 18:35:43:688: 【testlib】processDebugJavaRes=0ms
2022-02-15 18:35:43:690: 【testlib】bundleLibResDebug=1ms
2022-02-15 18:35:43:727: 【testlib】generateDebugRFile=36ms
2022-02-15 18:35:44:855: 【testlib】compileDebugJavaWithJavac=1126ms
2022-02-15 18:35:44:876: 【app】mergeDebugJavaResource=20ms
2022-02-15 18:35:44:899: 【app】desugarDebugFileDependencies=1ms
2022-02-15 18:35:44:939: 【app】mergeDebugResources=39ms
2022-02-15 18:35:44:941: 【app】dataBindingGenBaseClassesDebug=1ms
2022-02-15 18:35:44:943: 【app】mergeDebugJniLibFolders=1ms
2022-02-15 18:35:44:944: 【testlib】mergeDebugJniLibFolders=0ms
2022-02-15 18:35:44:946: 【testlib】mergeDebugNativeLibs=1ms
2022-02-15 18:35:44:947: 【testlib】stripDebugDebugSymbols=1ms
2022-02-15 18:35:44:948: 【testlib】copyDebugJniLibsProjectOnly=1ms
2022-02-15 18:35:44:964: 【app】validateSigningDebug=0ms
2022-02-15 18:35:44:965: 【app】writeDebugAppMetadata=1ms
2022-02-15 18:35:44:966: 【app】writeDebugSigningConfigVersions=1ms
2022-02-15 18:35:44:967: 【testlib】bundleLibRuntimeToDirDebug=2ms
2022-02-15 18:35:44:968: 【testlib】bundleLibCompileToJarDebug=3ms
2022-02-15 18:35:44:970: 【app】checkDebugDuplicateClasses=5ms
2022-02-15 18:35:45:002: 【app】processDebugManifestForPackage=28ms
2022-02-15 18:35:45:316: 【app】mergeLibDexDebug=18ms
2022-02-15 18:35:46:448: 【app】mergeDebugNativeLibs=1149ms
2022-02-15 18:35:46:456: 【app】stripDebugDebugSymbols=7ms
2022-02-15 18:35:48:751: 【app】processDebugResources=2303ms
2022-02-15 18:35:49:288: 【app】compileDebugJavaWithJavac=533ms
2022-02-15 18:35:49:288: 【app】compileDebugSources=0ms
2022-02-15 18:35:49:772: 【app】dexBuilderDebug=481ms
2022-02-15 18:35:49:835: 【app】mergeExtDexDebug=62ms
2022-02-15 18:35:50:035: 【app】mergeProjectDexDebug=262ms
2022-02-15 18:35:50:420: 【app】packageDebug=384ms
2022-02-15 18:35:50:421: 【app】assembleDebug=0ms
构建结束------------------2022-02-15 18:35:50:441----
构建总耗时:8248ms
app, 总耗时:5635ms
testlib, 总耗时:1190ms
这样就能看出来是 testlib 占用 1.1s, 把占比最高的,抽离成 aar 即刻实现项目编译的更快。