@@ -5,11 +5,13 @@ import com.android.build.api.transform.DirectoryInput
55import com.android.build.api.transform.Format
66import com.android.build.api.transform.JarInput
77import com.android.build.api.transform.QualifiedContent
8+ import com.android.build.api.transform.Status
89import com.android.build.api.transform.Transform
910import com.android.build.api.transform.TransformException
1011import com.android.build.api.transform.TransformInput
1112import com.android.build.api.transform.TransformOutputProvider
1213import com.android.build.gradle.internal.pipeline.TransformManager
14+ import com.android.ide.common.internal.WaitableExecutor
1315import groovy.io.FileType
1416import org.apache.commons.codec.digest.DigestUtils
1517import org.apache.commons.io.FileUtils
@@ -18,18 +20,21 @@ import org.objectweb.asm.ClassReader
1820import org.objectweb.asm.ClassVisitor
1921import org.objectweb.asm.ClassWriter
2022
23+ import java.util.concurrent.Callable
2124import java.util.jar.JarEntry
2225import java.util.jar.JarFile
2326import java.util.jar.JarOutputStream
2427import java.util.zip.ZipEntry
2528
2629class SensorsAnalyticsTransform extends Transform {
2730 private SensorsAnalyticsTransformHelper transformHelper
28- public static final String VERSION = " 3.0.0 "
31+ public static final String VERSION = " 3.0.1 "
2932 public static final String MIN_SDK_VERSION = " 3.0.0"
33+ private WaitableExecutor waitableExecutor
3034
3135 SensorsAnalyticsTransform (SensorsAnalyticsTransformHelper transformHelper ) {
3236 this . transformHelper = transformHelper
37+ this . waitableExecutor = WaitableExecutor . useGlobalSharedThreadPool()
3338 }
3439
3540 @Override
@@ -49,13 +54,17 @@ class SensorsAnalyticsTransform extends Transform {
4954
5055 @Override
5156 boolean isIncremental () {
52- return false
57+ return true
5358 }
5459
55- /**
60+ @Override
61+ boolean isCacheable () {
62+ return true
63+ }
64+ /**
5665 * 打印提示信息
5766 */
58- private void printCopyRight () {
67+ private static void printCopyRight () {
5968 println ()
6069 println (" \0 33[40;32m" + " ####################################################################" + " \0 33[0m" )
6170 println (" \0 33[40;32m" + " ######## ########" + " \0 33[0m" )
@@ -75,12 +84,13 @@ class SensorsAnalyticsTransform extends Transform {
7584 */
7685 printCopyRight()
7786
78- if (! incremental) {
79- outputProvider. deleteAll()
80- }
81-
8287 transformHelper. onTransform()
8388
89+ println (" [SensorsAnalytics]: 是否增量编译:$isIncremental " )
90+ long startTime = System . currentTimeMillis()
91+ if (! isIncremental) {
92+ outputProvider. deleteAll()
93+ }
8494 /**
8595 * 遍历输入文件
8696 */
@@ -89,59 +99,139 @@ class SensorsAnalyticsTransform extends Transform {
8999 * 遍历 jar
90100 */
91101 input. jarInputs. each { JarInput jarInput ->
92- String destName = jarInput. file. name
93- /**
94- * 截取文件路径的md5值重命名输出文件,因为可能同名,会覆盖
95- */
96- def hexName = DigestUtils . md5Hex(jarInput. file. absolutePath). substring(0 , 8 )
97- if (destName. endsWith(" .jar" )) {
98- destName = destName. substring(0 , destName. length() - 4 )
99- }
100- /* * 获得输出文件*/
101- File dest = outputProvider. getContentLocation(destName + " _" + hexName, jarInput. contentTypes, jarInput. scopes, Format . JAR )
102-
103- def modifiedJar = null
104- if (! transformHelper. disableJar || jarInput. file. absolutePath. contains(' SensorsAnalyticsSDK' )) {
105- Logger . info(" 开始遍历 jar:" + jarInput. file. absolutePath)
106- modifiedJar = modifyJarFile(jarInput. file, context. getTemporaryDir())
107- Logger . info(" 结束遍历 jar:" + jarInput. file. absolutePath)
108- }
109- if (modifiedJar == null ) {
110- modifiedJar = jarInput. file
111- }
112- FileUtils . copyFile(modifiedJar, dest)
102+ waitableExecutor. execute(new Callable<Object > () {
103+ @Override
104+ Object call () throws Exception {
105+ forEachJar(isIncremental, jarInput, outputProvider, context)
106+ return null
107+ }
108+ })
113109 }
114110
115111 /**
116112 * 遍历目录
117113 */
118114 input. directoryInputs. each { DirectoryInput directoryInput ->
119- File dest = outputProvider. getContentLocation(directoryInput. name, directoryInput. contentTypes, directoryInput. scopes, Format . DIRECTORY )
120115 // Logger.info("||-->开始遍历特定目录 ${dest.absolutePath}")
121116 File dir = directoryInput. file
122- if (dir) {
123- HashMap<String , File > modifyMap = new HashMap<> ()
124- dir. traverse(type : FileType . FILES , nameFilter : ~/ .*\. class/ ) {
125- File classFile ->
126- File modified = modifyClassFile(dir, classFile, context. getTemporaryDir())
127- if (modified != null ) {
128- // key为相对路径
129- modifyMap. put(classFile. absolutePath. replace(dir. absolutePath, " " ), modified)
130- }
117+ File dest = outputProvider. getContentLocation(directoryInput. getName(),
118+ directoryInput. getContentTypes(), directoryInput. getScopes(),
119+ Format . DIRECTORY )
120+ FileUtils . forceMkdir(dest)
121+ String srcDirPath = dir. absolutePath
122+ String destDirPath = dest. absolutePath
123+ if (isIncremental) {
124+ Map<File , Status > fileStatusMap = directoryInput. getChangedFiles()
125+ for (Map.Entry < File , Status > changedFile : fileStatusMap. entrySet()) {
126+ Status status = changedFile. getValue()
127+ File inputFile = changedFile. getKey()
128+ String destFilePath = inputFile. absolutePath. replace(srcDirPath, destDirPath)
129+ File destFile = new File (destFilePath)
130+ switch (status) {
131+ case Status . NOTCHANGED :
132+ break
133+ case Status . REMOVED :
134+ Logger . info(" 目录 status = $status :$inputFile . absolutePath " )
135+ if (destFile. exists()) {
136+ // noinspection ResultOfMethodCallIgnored
137+ destFile. delete()
138+ }
139+ break
140+ case Status . ADDED :
141+ case Status . CHANGED :
142+ Logger . info(" 目录 status = $status :$inputFile . absolutePath " )
143+ File modified = modifyClassFile(dir, inputFile, context. getTemporaryDir())
144+ if (destFile. exists()) {
145+ destFile. delete()
146+ }
147+ if (modified != null ) {
148+ FileUtils . copyFile(modified, destFile)
149+ modified. delete()
150+ } else {
151+ FileUtils . copyFile(inputFile, destFile)
152+ }
153+ break
154+ default :
155+ break
156+ }
157+
131158 }
132- FileUtils . copyDirectory(directoryInput. file, dest)
133- modifyMap. entrySet(). each {
134- Map.Entry < String , File > en ->
135- File target = new File (dest. absolutePath + en. getKey())
136- if (target. exists()) {
137- target. delete()
138- }
139- FileUtils . copyFile(en. getValue(), target)
140- en. getValue(). delete()
159+ } else {
160+ FileUtils . copyDirectory(dir, dest)
161+ dir. traverse(type : FileType . FILES , nameFilter : ~/ .*\. class/ ) {
162+ File inputFile ->
163+ waitableExecutor. execute(new Callable<Object > () {
164+ @Override
165+ Object call () throws Exception {
166+ File modified = modifyClassFile(dir, inputFile, context. getTemporaryDir())
167+ if (modified != null ) {
168+ File target = new File (inputFile. absolutePath. replace(srcDirPath, destDirPath))
169+ if (target. exists()) {
170+ target. delete()
171+ }
172+ FileUtils . copyFile(modified, target)
173+ modified. delete()
174+ }
175+ return null
176+ }
177+ })
141178 }
142179 }
180+
143181 }
144182 }
183+
184+ waitableExecutor. waitForTasksWithQuickFail(true )
185+
186+ println (" [SensorsAnalytics]: 此次编译共耗时:${ System.currentTimeMillis() - startTime} 毫秒" )
187+ }
188+
189+ void forEachJar (boolean isIncremental ,JarInput jarInput ,TransformOutputProvider outputProvider ,Context context ){
190+ String destName = jarInput. file. name
191+ /**
192+ * 截取文件路径的md5值重命名输出文件,因为可能同名,会覆盖
193+ */
194+ def hexName = DigestUtils . md5Hex(jarInput. file. absolutePath). substring(0 , 8 )
195+ if (destName. endsWith(" .jar" )) {
196+ destName = destName. substring(0 , destName. length() - 4 )
197+ }
198+ /* * 获得输出文件*/
199+ File destFile = outputProvider. getContentLocation(destName + " _" + hexName, jarInput. contentTypes, jarInput. scopes, Format . JAR )
200+ if (isIncremental) {
201+ Status status = jarInput. getStatus()
202+ switch (status) {
203+ case Status . NOTCHANGED :
204+ break
205+ case Status . ADDED :
206+ case Status . CHANGED :
207+ Logger . info(" jar status = $status :$destFile . absolutePath " )
208+ transformJar(destFile,jarInput,context)
209+ break
210+ case Status . REMOVED :
211+ Logger . info(" jar status = $status :$destFile . absolutePath " )
212+ if (destFile. exists()) {
213+ FileUtils . forceDelete(destFile)
214+ }
215+ break
216+ default :
217+ break
218+ }
219+ } else {
220+ transformJar(destFile,jarInput,context)
221+ }
222+ }
223+
224+ void transformJar (File dest ,JarInput jarInput ,Context context ) {
225+ def modifiedJar = null
226+ if (! transformHelper. disableJar || jarInput. file. absolutePath. contains(' SensorsAnalyticsSDK' )) {
227+ Logger . info(" 开始遍历 jar:" + jarInput. file. absolutePath)
228+ modifiedJar = modifyJarFile(jarInput. file, context. getTemporaryDir())
229+ Logger . info(" 结束遍历 jar:" + jarInput. file. absolutePath)
230+ }
231+ if (modifiedJar == null ) {
232+ modifiedJar = jarInput. file
233+ }
234+ FileUtils . copyFile(modifiedJar, dest)
145235 }
146236
147237 /**
@@ -219,6 +309,10 @@ class SensorsAnalyticsTransform extends Transform {
219309 } catch (UnsupportedOperationException e) {
220310 throw e
221311 } catch (Exception ex) {
312+ ex. printStackTrace()
313+ if (transformHelper. debug) {
314+ throw new Error ()
315+ }
222316 return srcByteCode
223317 }
224318 }
@@ -235,6 +329,10 @@ class SensorsAnalyticsTransform extends Transform {
235329 } catch (UnsupportedOperationException e) {
236330 throw e
237331 } catch (Exception ex) {
332+ ex. printStackTrace()
333+ if (transformHelper. debug) {
334+ throw new Error ()
335+ }
238336 return srcClass
239337 }
240338 }
@@ -277,7 +375,7 @@ class SensorsAnalyticsTransform extends Transform {
277375 return modified
278376 }
279377
280- private String path2ClassName (String pathName ) {
378+ private static String path2ClassName (String pathName ) {
281379 pathName. replace(File . separator, " ." ). replace(" .class" , " " )
282380 }
283381}
0 commit comments