All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.faker.android.gradle.SmaliBuilderTask Maven / Gradle / Ivy

The newest version!
package com.faker.android.gradle;
import com.android.build.api.artifact.BuildableArtifact;
import com.android.build.gradle.api.AndroidSourceSet;
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.tasks.VariantAwareTask;
import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction;
import com.android.tools.build.bundletool.io.ZipBuilder;
import com.faker.android.SmaliCompiler;
import com.google.common.io.Files;
import com.googlecode.d2j.dex.Dex2jar;
import com.googlecode.dex2jar.tools.BaksmaliBaseDexExceptionHandler;
//import com.googlecode.d2j.dex.Dex2jar;
//import com.googlecode.dex2jar.tools.BaksmaliBaseDexExceptionHandler;
import org.apache.commons.io.FileUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.Incubating;
import org.gradle.api.Project;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileType;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.Zip;
import org.gradle.work.ChangeType;
import org.gradle.work.FileChange;
import org.gradle.work.Incremental;
import org.gradle.work.InputChanges;
import org.jetbrains.annotations.NotNull;
import java.io.File;

import brut.directory.ZipUtils;

import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.ALL;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.CLASSES;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH;
import static com.android.build.gradle.internal.scope.InternalArtifactType.JAVAC;

public class SmaliBuilderTask extends DefaultTask implements VariantAwareTask {//TODO this task should produce javascaffoding for dev
    private String variantName;
    private final DirectoryProperty destinationDirectory;

    private final DirectoryProperty destinationjarDirectory;

    private  FileCollection source;

    @Input
    public int getApiLevel() {
        return apiLevel;
    }

    public void setApiLevel(int apiLevel) {
        this.apiLevel = apiLevel;
    }

    private int apiLevel;

    public DirectoryProperty getDestinationjarDirectory() {
        return destinationjarDirectory;
    }

    public SmaliBuilderTask() {
        this.destinationDirectory = getProject().getObjects().directoryProperty();
        this.destinationjarDirectory = getProject().getObjects().directoryProperty();
    }
    @TaskAction
    protected void compile(InputChanges inputs) {//TODO MY FOCUS ON

        System.out.println("compiling the smali to dex ...");

        if(!inputs.isIncremental()) {
            try {
                FileUtils.deleteDirectory(getDestinationDirectory().getAsFile().getOrNull());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Iterable sourceChanges = inputs.getFileChanges(getSource());
        for (FileChange fileChange: sourceChanges) {
            if (fileChange.getFileType() != FileType.FILE) {
                continue;
            }
            String absPath = fileChange.getFile().getAbsolutePath();
            String path = fileChange.getNormalizedPath();
            String nonePrefixNamePath = getFileNameNoEx(path);
            String toDexPath = nonePrefixNamePath +".dex";
            String toDexAbsPath = new File(getDestinationDirectory().getAsFile().getOrNull(),toDexPath).getAbsolutePath();
            File smaliFile = new File(absPath);
            File dexFile = new File(toDexAbsPath);
            if(fileChange.getChangeType()== ChangeType.ADDED||fileChange.getChangeType()== ChangeType.MODIFIED) {
                if(!dexFile.getParentFile().exists()){
                    dexFile.getParentFile().mkdirs();
                }
                try {
                    String classesAspath = getClassesFileCollection().getAsPath();

                    File isClassFile = new File(classesAspath,nonePrefixNamePath+".class");
                    if(isClassFile.exists()){
                        System.out.println("current dex "+toDexPath+" ref smali is covered by "+ nonePrefixNamePath+".class ref java");
                        continue;
                    }
                    SmaliCompiler.build(smaliFile,dexFile,apiLevel);
                    //System.out.println("add dex or mod flie:"+ toDexPath);
                    File scaffdingJarFile = new File(getDestinationjarDirectory().getAsFile().getOrNull(),"classes.all.dex.jar");
                    if(scaffdingJarFile.exists()) {
                        if(fileChange.getChangeType()== ChangeType.MODIFIED){
                            BaksmaliBaseDexExceptionHandler handler = false ? null : new BaksmaliBaseDexExceptionHandler();
                            Dex2jar.from(dexFile).withExceptionHandler(handler).reUseReg(false).topoLogicalSort()
                                    .skipDebug(false).optimizeSynchronized(false).printIR(false)
                                    .noCode(false).skipExceptions(false).to(scaffdingJarFile.toPath());
                            System.out.println("a smali "+path+" file mod has been found the java scaffding jar file sync with it...");
                        }
                    }else{
                        System.err.println(" no javaScaffoding base jar with name "+scaffdingJarFile.getName()+" has been found --");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                if(dexFile.exists()){
                    System.out.println("del dex flie :"+ toDexPath);
                    dexFile.delete();
                }
            }
        }
        Iterable classChanges =  inputs.getFileChanges(getClassesFileCollection());
        for (FileChange fileChange: classChanges) {//TODO catch the classes in project
            if (fileChange.getFileType() != FileType.FILE) {
                continue;
            }
            String normalizedPathClassPath = fileChange.getNormalizedPath();
            String noExtNormalizedPathClassPath = getFileNameNoEx(normalizedPathClassPath);
            if(fileChange.getChangeType()== ChangeType.ADDED){
                File destinationDirectoryFile = getDestinationDirectory().getAsFile().getOrNull();
                File isDex = new File(destinationDirectoryFile,noExtNormalizedPathClassPath+".dex");
                 if(isDex.exists()){
                     isDex.delete();
                     System.out.println("isDex del:"+noExtNormalizedPathClassPath+".dex");
                 }
            }
            if(fileChange.getChangeType()== ChangeType.REMOVED){
                String sourcePath = getSource().getAsPath();
                File isSmali = new File(sourcePath,noExtNormalizedPathClassPath+".smali");
                System.out.println("isSmali:"+isSmali.getAbsolutePath());
                if(isSmali.exists()){
                    File isToDex = new File(getDestinationDirectory().getAsFile().getOrNull(),noExtNormalizedPathClassPath+".dex");
                    try {
                        if(!isToDex.exists()){
                            SmaliCompiler.build(isSmali,isToDex,apiLevel);
                        }
                        System.out.println("class remove now recover the smali file to dex path smali:"+noExtNormalizedPathClassPath+".smali");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        Iterable jarChanges =  inputs.getFileChanges(getJarFileCollection());
        for (FileChange fileChange: jarChanges) {//TODO catch the classes in project
//            System.out.println("jar change path:" +fileChange.getFile().getAbsolutePath());
//            System.out.println("jar change name:"+fileChange.getNormalizedPath());
        }
    }
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot >-1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }
    @OutputDirectory
    public DirectoryProperty  getDestinationDirectory() {
        return destinationDirectory;
    }


    @NotNull
    @Override
    public String getVariantName() {
        return variantName;
    }

    @Override
    public void setVariantName(@NotNull String variantName) {
        this.variantName = variantName;
    }

    @Incremental
    @Incubating
    @SkipWhenEmpty
    @PathSensitive(PathSensitivity.RELATIVE)
    @InputFiles
    public FileCollection getClassesFileCollection() {
        return classesFileCollection;
    }

    private void setClassesFileCollection(FileCollection classesFileCollection) {
        this.classesFileCollection = classesFileCollection;
    }

    private FileCollection classesFileCollection;

    private FileCollection jarFileCollection;//TODO

    @Incremental
    @InputFiles
    @Incubating
    @PathSensitive(PathSensitivity.RELATIVE)
    @SkipWhenEmpty
    public FileCollection getSource() {
        return source;
    }

    public void setSource(FileCollection source) {
        this.source = source;
    }
    @Incremental
    @InputFiles
    @Incubating
    @PathSensitive(PathSensitivity.RELATIVE)
    @SkipWhenEmpty
    public FileCollection getJarFileCollection() {
        return jarFileCollection;
    }

    public void setJarFileCollection(FileCollection jarFileCollection) {
        this.jarFileCollection = jarFileCollection;
    }

    public void setDestinationDir(File destinationDir) {
        this.destinationDirectory.set(destinationDir);
    }
    public void setDestinationJarDir(File destinationJarDir) {
        this.destinationjarDirectory.set(destinationJarDir);
    }

    public static class CreationAction extends VariantTaskCreationAction {
        TaskProvider taskProvider;
        File destinationDir;
        File destinationJarDir;
        public CreationAction(@NotNull VariantScope variantScope, TaskProvider taskProvider) {
            super(variantScope);
            this.taskProvider = taskProvider;
        }
        @NotNull
        @Override
        public String getName() {
            return getVariantScope().getTaskName("smali");
        }
        @NotNull
        @Override
        public Class getType() {
            return SmaliBuilderTask.class;
        }

        @Override
        public void preConfigure(@NotNull String taskName) {
            super.preConfigure(taskName);
            destinationDir = getVariantScope().getArtifacts().appendArtifact(FakerBuildArtifactType.SMALIDEXES, taskName, "dexes");
            Project project = getVariantScope().getVariantData().getScope().getGlobalScope().getProject();
            File file = project.getBuildscript().getSourceFile().getParentFile();
            destinationJarDir = new File(file,"javaScaffoding");
            if(!destinationJarDir.exists()){
                destinationJarDir.mkdirs();
            }
        }

        @Override
        public void configure(@NotNull SmaliBuilderTask task) {
            super.configure(task);
            task.setDestinationDir(destinationDir);
            task.setDestinationJarDir(destinationJarDir);


            Project project = getVariantScope().getVariantData().getScope().getGlobalScope().getProject();
            BaseAppModuleExtension appExtension = project.getExtensions().getByType(BaseAppModuleExtension.class);
            AndroidSourceSet androidSourceSet = appExtension.getSourceSets().getByName("main");


            File smalis = new File(androidSourceSet.getManifest().getSrcFile().getParent(),"smali");
            int apiLevel = appExtension.getDefaultConfig().getMinSdkVersion().getApiLevel();
            task.setApiLevel(apiLevel);
            //TODO this is filecollection of smali files
            ConfigurableFileCollection source = getVariantScope().getGlobalScope().getProject().files(smalis);



            task.setSource(source);
            //TODO this is a .class filecollection in current moudle
            final BuildableArtifact javacOutput = getVariantScope().getArtifacts().getArtifactFiles(JAVAC);
            final FileCollection preJavacGeneratedBytecode = getVariantScope().getVariantData().getAllPreJavacGeneratedBytecode();
            final FileCollection postJavacGeneratedBytecode = getVariantScope().getVariantData().getAllPostJavacGeneratedBytecode();
            ConfigurableFileCollection classFiles = getVariantScope().getGlobalScope().getProject().files(javacOutput, preJavacGeneratedBytecode, postJavacGeneratedBytecode);
            task.setClassesFileCollection(classFiles);

            //TODO  this is a .jar filecollection in current moudle
            FileCollection jarFiles  =getVariantScope().getArtifactCollection(RUNTIME_CLASSPATH, ALL, CLASSES).getArtifactFiles();//




            task.setJarFileCollection(jarFiles);

            //设置必须运行在javac之后
            task.mustRunAfter(taskProvider);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy