|
@@ -0,0 +1,154 @@
|
|
|
+package com.gradle
|
|
|
+
|
|
|
+import com.android.build.api.transform.*
|
|
|
+import com.google.common.collect.ImmutableSet
|
|
|
+import org.apache.commons.codec.digest.DigestUtils
|
|
|
+import org.apache.commons.io.FileUtils
|
|
|
+import org.gradle.api.Project
|
|
|
+import org.gradle.api.logging.Logger
|
|
|
+import org.gradle.api.logging.Logging
|
|
|
+
|
|
|
+/**
|
|
|
+ * Created by Glen on 2017/2/7.
|
|
|
+ */
|
|
|
+
|
|
|
+public class ModifyClassTransform extends Transform {
|
|
|
+ Project project;
|
|
|
+ Logger logger;
|
|
|
+
|
|
|
+ public ModifyClassTransform(Project project) {
|
|
|
+ this.project = project;
|
|
|
+ this.logger = Logging.getLogger(ModifyClassTransform.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getName() {
|
|
|
+ return "Modify"
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<QualifiedContent.ContentType> getInputTypes() {
|
|
|
+ return ImmutableSet.of(QualifiedContent.DefaultContentType.CLASSES)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<QualifiedContent.Scope> getScopes() {
|
|
|
+ return ImmutableSet.of(
|
|
|
+ QualifiedContent.Scope.PROJECT,// app class
|
|
|
+ QualifiedContent.Scope.PROJECT_LOCAL_DEPS,// app libs local jar
|
|
|
+ QualifiedContent.Scope.SUB_PROJECTS,//sub lib class
|
|
|
+ QualifiedContent.Scope.SUB_PROJECTS_LOCAL_DEPS,//sub lib libs local jar
|
|
|
+ QualifiedContent.Scope.EXTERNAL_LIBRARIES//compile dependencies
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean isIncremental() {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
|
|
|
+ //delete all
|
|
|
+ transformInvocation.outputProvider.deleteAll()
|
|
|
+
|
|
|
+ // Collecting inputs.
|
|
|
+ transformInvocation.inputs.each { input ->
|
|
|
+ input.directoryInputs.each { dirInput ->
|
|
|
+ if (transformInvocation.incremental) {
|
|
|
+ dirInput.changedFiles.each { changedFile ->
|
|
|
+ handleChangedFile(changedFile.key)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dirInput.file.eachFileRecurse { File file ->
|
|
|
+ handleChangedFile(file)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //output modify class file
|
|
|
+ File file = transformInvocation.outputProvider.getContentLocation(dirInput.file.name, dirInput.contentTypes, dirInput.scopes, Format.DIRECTORY)
|
|
|
+ FileUtils.copyDirectory(dirInput.file, file)
|
|
|
+ }
|
|
|
+ input.jarInputs.each { jarInput ->
|
|
|
+ switch (jarInput.status) {
|
|
|
+ case Status.NOTCHANGED:
|
|
|
+ if (transformInvocation.incremental) break
|
|
|
+ case Status.ADDED:
|
|
|
+ case Status.CHANGED:
|
|
|
+ handleChangedFile(jarInput.file)
|
|
|
+ }
|
|
|
+
|
|
|
+ //output modify jar file
|
|
|
+ File file = transformInvocation.outputProvider.getContentLocation(getUniqueHashName(jarInput.file), jarInput.contentTypes, jarInput.scopes, Format.JAR)
|
|
|
+ FileUtils.copyFile(jarInput.file, file)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 增量文件
|
|
|
+ * @param input
|
|
|
+ */
|
|
|
+ private void handleChangedFile(File input) {
|
|
|
+ String path = input.absolutePath.replace("/", "\\")
|
|
|
+ if (input.isFile()) {
|
|
|
+ debug("changed:" + input.absolutePath)
|
|
|
+ if (path.endsWith(".class")) {
|
|
|
+ modifyClass(input)
|
|
|
+ } else if (path.endsWith(".jar")) {
|
|
|
+ if (path.contains("exploded-aar")) {
|
|
|
+ if (!path.contains("com.android.support")) {
|
|
|
+ //需要处理的jar包
|
|
|
+ File tmp = new File(input.getParent() + File.separator + "tmp")
|
|
|
+ tmp.deleteOnExit()
|
|
|
+
|
|
|
+ boolean modify = false
|
|
|
+ if (!modify) JarZipUtil.unzipJar(input, tmp.absolutePath)
|
|
|
+ tmp.eachFileRecurse { File file ->
|
|
|
+ if (file.isFile()) {
|
|
|
+ if (modifyClass(file)) {
|
|
|
+ modify = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (modify) JarZipUtil.zipJar(tmp.absolutePath, input)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改类文件
|
|
|
+ * @param clazz
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean modifyClass(File clazz) {
|
|
|
+ debug("modify:" + clazz.absolutePath)
|
|
|
+
|
|
|
+
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成唯一文件名
|
|
|
+ * @param fileInput
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getUniqueHashName(File fileInput) {
|
|
|
+ final String fileInputName = fileInput.getName()
|
|
|
+ if (fileInput.isDirectory()) {
|
|
|
+ return fileInputName
|
|
|
+ }
|
|
|
+ final String parentDirPath = fileInput.getParentFile().getAbsolutePath()
|
|
|
+ final String pathMD5 = DigestUtils.md5Hex(parentDirPath.getBytes()).substring(0, 6)
|
|
|
+ final int extSepPos = fileInputName.lastIndexOf('.')
|
|
|
+ final String fileInputNamePrefix =
|
|
|
+ (extSepPos >= 0 ? fileInputName.substring(0, extSepPos) : fileInputName)
|
|
|
+ return fileInputNamePrefix + '_' + pathMD5
|
|
|
+ }
|
|
|
+
|
|
|
+ private void debug(def msg) {
|
|
|
+ this.logger.lifecycle(":" + this.project.name + ":" + msg)
|
|
|
+ }
|
|
|
+}
|