Gradle脚本小总结

1.禁用task

    gradle.taskGraph.whenReady {
        tasks.each { task ->
            if (task.name.equalsIgnoreCase("transformClassesWithDelegateProguardTransformForRelease")
            || task.name.equalsIgnoreCase("transformClassesWithApplicationInjectForRelease"))
            {
                task.enabled = false
                println '####disable task.. '+task.name
            }
        }
    }

2.插入task或者脚本

  • task的doFirstdoLast
project.afterEvaluate {

    File buildGradleFile = project.getBuildFile()
    println "kblog:buildDir = " + project.getBuildDir().getAbsolutePath()
    println "kblog:rootDir 2 " + buildGradleFile.getText()

    Task buildRelease = project.tasks.findByName("buildRelease")
    if (buildRelease) {
        buildRelease.doLast {
            File mappingFile = new File(project.getBuildDir().getAbsolutePath() + "/intermediates/bundle/mapping.txt")
            if (mappingFile.exists()) {
                mappingFile.renameTo(project.getBuildDir().getAbsolutePath() + "/intermediates/bundle/mapping.mochuan.4mtl.xml")
            }
        }
    }

    Task assembleRelease = project.tasks.findByName("assembleRelease")
    if (assembleRelease) {
        assembleRelease.doLast {
            File mappingFile = new File(project.getBuildDir().getAbsolutePath() + "/intermediates/bundle/mapping.txt")
            if (mappingFile.exists()) {
                mappingFile.renameTo(project.getBuildDir().getAbsolutePath() + "/intermediates/bundle/mapping.mochuan.4mtl.xml")
            }
        }
    }

}
  • dependOn
mOrganizeImportsTask.dependsOn project.tasks.findByName(REPLACE_TASK_NAME)

3.使用transform复制so

  • 将部分aar中的armeabi-v7a中的文件,复制到armeabi
import com.android.annotations.NonNull
import com.android.build.api.transform.Format
import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformException
import com.android.build.api.transform.TransformInvocation

import com.android.build.gradle.internal.pipeline.ExtendedContentType

//@version mochuan.zhb on 2019/6/15.
//@Author Zheng Haibo
//@Blog github.com/nuptboyzhb
//@Company Alibaba Group
//@Description 将部分aar中的armeabi-v7a中的文件,复制到armeabi;
public class NativeTransform extends Transform {

    public def projectContext;

    public static final String ABI_ARMEABI = "armeabi";
    public static final String ABI_ARMEABI_V7A = "armeabi-v7a";


    @Override
    public String getName() {
        return "copyNativeLibraries"
    }

    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        Set<QualifiedContent.ContentType> set = EnumSet.of(ExtendedContentType.NATIVE_LIBS);
        return set;
    }

    @Override
    public Set<QualifiedContent.Scope> getScopes() {
        Set<QualifiedContent.Scope> set = EnumSet.of(
                QualifiedContent.Scope.EXTERNAL_LIBRARIES,
                QualifiedContent.Scope.PROJECT,
                QualifiedContent.Scope.SUB_PROJECTS
        )
        return set;
    }

    @Override
    public boolean isIncremental() {
        return false;
    }

    @Override
    public void transform(@NonNull TransformInvocation transformInvocation)
            throws TransformException, InterruptedException, IOException {

        def outputProvider = transformInvocation.outputProvider
        if (!transformInvocation.isIncremental()) {
            outputProvider.deleteAll()
        }

        transformInvocation.inputs.forEach { transformInput ->

            transformInput.directoryInputs.forEach { directoryInput ->
                def dir = directoryInput.file.toPath()
                def output = outputProvider.getContentLocation(
                        directoryInput.name, inputTypes, directoryInput.scopes, Format.DIRECTORY)

                projectContext.fileTree(dir).forEach { input ->
                    def path = dir.relativize(input.toPath())
                    def destDir = output.toPath().resolve(path).toFile().parentFile

                    def abiName = input.parentFile.name

                    println 'kblog:path = ' + path + ",abiName = " + abiName

                    if (ABI_ARMEABI_V7A == abiName) {
                        def v5Dir = new File(destDir.parentFile, ABI_ARMEABI)

                        projectContext.copy { spec ->
                            spec.from(input)
                            spec.into(v5Dir)
                        }
                        println 'kblog:copy ' + path + " into " + v5Dir.getAbsolutePath()
                        projectContext.copy { spec ->
                            spec.from(input)
                            spec.into(destDir)
                        }
                    } else if (ABI_ARMEABI == abiName) {
                        def v7Dir = new File(destDir.parentFile, ABI_ARMEABI_V7A)
                        if (!(new File(v7Dir, input.name)).isFile()) {
                            // copy if not present
                            projectContext.copy { spec ->
                                spec.from(input)
                                spec.into(v7Dir)
                            }
                        }
                        projectContext.copy { spec ->
                            spec.from(input)
                            spec.into(destDir)
                        }
                    } else {
                        // just copy
                        projectContext.copy { spec ->
                            spec.from(input)
                            spec.into(destDir)
                        }
                    }
                }
            }
        }

    }


}

def transform = new NativeTransform()
transform.projectContext = project
project.android.registerTransform(transform)

4.使用Transform检查类

  • 用于检查依赖的类是否有重复,如果重复,则随机删除一个
import org.apache.commons.io.FileUtils;
import com.android.annotations.NonNull
import com.android.build.api.transform.Format
import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformInput
import com.android.build.api.transform.DirectoryInput
import com.android.build.api.transform.JarInput
import com.android.build.api.transform.TransformOutputProvider
import com.android.build.api.transform.TransformException
import com.android.build.api.transform.TransformInvocation
import com.android.build.gradle.internal.pipeline.TransformManager

import java.util.jar.JarFile
import java.util.zip.ZipEntry;


//@version mochuan.zhb on 2021/6/23.
//@Author Zheng Haibo
//@Blog github.com/nuptboyzhb
//@Company Alibaba Group
//@Description
public class FilterJarTransform extends Transform {

    public def projectContext;


    @Override
    public String getName() {
        return "filterJar"
    }

    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_JARS;
    }

    @Override
    public Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT;
    }

    @Override
    public boolean isIncremental() {
        return false;
    }

    private Map<String, String> clazzJarMap = new HashMap<>();

    public static class FileModel{
        public FileModel(File file1,JarInput jarInput1){
            this.jarInput = jarInput1;
            this.file = file1;
        }
        public File file;
        public JarInput jarInput;
    }

    @Override
    public void transform(@NonNull TransformInvocation transformInvocation)
            throws TransformException, InterruptedException, IOException {

        List<FileModel> inputFiles = new ArrayList<>();
        for (TransformInput input : transformInvocation.getInputs()) {
            for (DirectoryInput directoryInput : input.getDirectoryInputs()) {
                if (directoryInput.getFile().isDirectory()) {
                    inputFiles.add(new FileModel(directoryInput.getFile(),null));
                }
            }
            for (JarInput jarInput : input.getJarInputs()) {
                if (jarInput.getFile().isFile()) {
                    inputFiles.add(new FileModel(jarInput.getFile(),jarInput));
                }
            }
        }
        Map<String, String> multiJarPath = new HashMap<>();
        inputFiles.each { fileModel ->
            println('process file = ' + fileModel.file.getAbsolutePath())
            TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();
            if (fileModel.file.isFile() && fileModel.file.getName().endsWith(".jar")) {
                JarFile jarFile = new JarFile(fileModel.file);
                Enumeration<? extends ZipEntry> entries = jarFile.entries();
                boolean isMultiJar = false;
                while (entries.hasMoreElements()) {
                    ZipEntry element = entries.nextElement();
                    //element.setExtra();
                    String currentClass = element.getName();
                    String path = clazzJarMap.get(currentClass);
                    if (path != null && path.length() > 0) {
                        println('find multi-class: ' + currentClass)
                        isMultiJar = true;
                        multiJarPath.put(path, fileModel.file.getAbsolutePath());
                    } else {
                        clazzJarMap.put(currentClass, fileModel.file.getAbsolutePath());
                    }
                }
                if (!isMultiJar) {
                    if(fileModel.jarInput != null){
                        File dest = outputProvider.getContentLocation(
                                fileModel.jarInput.getFile().getAbsolutePath(),
                                fileModel.jarInput.getContentTypes(),
                                fileModel.jarInput.getScopes(),
                                Format.JAR);
                        FileUtils.copyFile(fileModel.file, dest);
                    }else{
                        //
                        println("TODO:///"+fileModel.file.getAbsolutePath())
                    }
                }
            }
        }

        for (Map.Entry<String, String> entry : multiJarPath) {
            println('### multi-jar: ' + entry.getKey() + "," + entry.getValue())
        }

    }

}

def transform = new FilterJarTransform()
transform.projectContext = project
project.android.registerTransform(transform)

5.Hook所有task的输入输出

/**
 * @version mochuan.zhb on 2019/7/3.
 * @Author Zheng Haibo
 * @Blog github.com/nuptboyzhb
 * @Company Alibaba Group
 * @Description task执行的顺序以及所有的input/output
 */
public class TaskIOPlugin implements Plugin<Project> {

    private Map<String, TaskNode> taskExecuteMap = new LinkedHashMap<>();

    private File buildDir;

    private static long gradleStartTime = 0L;

    @Override
    public void apply(Project project) {

        buildDir = project.getBuildDir();
        project.getGradle().addBuildListener(new BuildListener() {
            @Override
            public void buildStarted(Gradle gradle) {
                myLog("buildStarted")
            }

            @Override
            public void settingsEvaluated(Settings settings) {
                myLog("settingsEvaluated")
            }

            @Override
            public void projectsLoaded(Gradle gradle) {
                myLog("projectsLoaded")
            }

            @Override
            public void projectsEvaluated(Gradle gradle) {
                gradleStartTime = System.currentTimeMillis();
                myLog("projectsEvaluated")
            }

            @Override
            public void buildFinished(BuildResult buildResult) {
                myLog("buildFinished")
                printTaskMap();
            }
        });
        taskExecuteMap.clear()
        project.getGradle().getTaskGraph().addTaskExecutionListener(new TaskExecutionListener() {
            @Override
            public void beforeExecute(Task task) {
                TaskNode taskNode = taskExecuteMap.get(getTaskName(task))
                if (taskNode != null) {
                    println("== taskNode added ...")
                    return;
                }
                List<String> inputFileList = new ArrayList<>();
                task.getInputs().files.each { item ->
                    inputFileList.add(item.getAbsolutePath())
                }
                taskNode = new TaskNode();
                taskNode.startTime = System.currentTimeMillis()
                taskNode.name = getTaskName(task);
                taskNode.clazz = task.getClass().getName()
                taskNode.input = inputFileList
                taskExecuteMap.put(getTaskName(task), taskNode)
            }

            @Override
            public void afterExecute(Task task, TaskState taskState) {
                List<String> outputList = new ArrayList<>();
                task.getOutputs().files.each { item ->
                    outputList.add(item.getAbsolutePath())
                }
                TaskNode taskNode = taskExecuteMap.get(getTaskName(task))
                if (taskNode == null) {
                    taskNode = new TaskNode();
                    taskNode.name = getTaskName(task);
                    taskNode.clazz = task.getClass().getName()
                }
                taskNode.endTime = System.currentTimeMillis()
                taskNode.output = outputList
                taskExecuteMap.put(getTaskName(task), taskNode)
            }
        });

        project.getGradle().getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
            @Override
            public void graphPopulated(TaskExecutionGraph taskExecutionGraph) {
                myLog("---graphPopulated---")
            }
        });

    }

    private static String getTaskName(Task task) {
        String taskName = String.format("%s:%s", task.getProject().getName(), task.getName());
        println("== afterExecute > " + taskName)
        return taskName;
    }

    private static void myLog(String content) {
        myLog(content, false)
    }

    private static void myLog(String content, boolean node) {
        if (node) {
            println("       [node]:" + content)
        } else {
            println("[====task-io===]:" + content)
        }
    }

    private void printTaskMap() {
        println("start task io file.")
        StringBuilder stringBuilder = new StringBuilder()
        StringBuilder taskList = new StringBuilder();
        boolean lastItem = false
        int taskCount = 0;
        List<TimeData> timeDataList = new ArrayList<>();
        taskExecuteMap.each { item ->
            taskCount++
            TaskNode taskNode = item.value
            long time = taskNode.endTime - taskNode.startTime
            if (time > 0) {
                TimeData timeData = new TimeData();
                timeData.taskName = taskNode.name;
                timeData.time = time;
                timeData.startTime4Charts = taskNode.startTime - gradleStartTime
                timeDataList.add(timeData);
            }
            taskList.append(taskCount).append(" ").append(taskNode.name).append("(" + time + " ms)").append("   ::<" + taskNode.clazz + ">").append("\n")
            taskList.append("           ↓").append("\n")
            stringBuilder.append(":").append(taskNode.name).append("\n")
            stringBuilder.append('   input→').append("\n")
            int count = 0
            taskNode.input.each { i ->
                count++
                if (count == taskNode.input.size()) {
                    stringBuilder.append("       └──" + i).append("\n")
                    lastItem = true
                } else {
                    stringBuilder.append("       ├──" + i).append("\n")
                    lastItem = false
                }
                if (new File(i).isDirectory()) {
                    printChildFiles(new File(i), stringBuilder, lastItem);
                }
            }
            stringBuilder.append('   output→').append("\n")
            count = 0
            taskNode.output.each { o ->
                count++
                if (count == taskNode.output.size()) {
                    stringBuilder.append("       └──" + o).append("\n")
                    lastItem = true
                } else {
                    stringBuilder.append("       ├──" + o).append("\n")
                    lastItem = false
                }
                if (new File(o).isDirectory()) {
                    printChildFiles(new File(o), stringBuilder, lastItem);
                }
            }
        }

        stringBuilder.append("\n\n\n")
        stringBuilder.append(taskList.toString())

        printData4Charts(timeDataList, stringBuilder);

        printData4Markdown(timeDataList, stringBuilder)

        printTimeline4Text(new ArrayList<TimeData>(timeDataList), stringBuilder)

        File outPutDir = new File(buildDir, "/outputs/");
        if (!outPutDir.exists()) {
            outPutDir.mkdirs()
        }
        long currentTime = System.currentTimeMillis();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date(currentTime);
        String fileName = formatter.format(date) + "_taskio.txt";
        File resultFile = new File(outPutDir, fileName);
        boolean success = FileUtils.toFile(resultFile, stringBuilder)
        if (success) {
            println("task io file finished. file path = " + resultFile.getAbsolutePath())
        } else {
            println("task io file failed.")
        }
    }

    /**
     * 递归打印
     * @param dir
     * @param stringBuilder
     * @param lastItem
     */
    private void printChildFiles(File dir, StringBuilder stringBuilder, boolean lastItem) {
        int childCount = 0;
        boolean nextLastItem = false;
        dir.listFiles().each { child ->
            childCount++
            if (lastItem) {
                if (childCount == dir.listFiles().size()) {
                    stringBuilder.append("            └──" + child.getAbsolutePath()).append("\n")
                    nextLastItem = true
                } else {
                    stringBuilder.append("            ├──" + child.getAbsolutePath()).append("\n")
                    nextLastItem = false
                }
            } else {
                if (childCount == dir.listFiles().size()) {
                    stringBuilder.append("       |    └──" + child.getAbsolutePath()).append("\n")
                } else {
                    stringBuilder.append("       |    ├──" + child.getAbsolutePath()).append("\n")
                }
            }
            if (child.isDirectory()) {
                printChildFiles(child, stringBuilder, nextLastItem);
            }
        }
    }

    /**
     *  data: [
     *{value: 1048, name: '搜索引擎'},
     *{value: 735, name: '直接访问'},
     *{value: 580, name: '邮件营销'},
     *{value: 484, name: '联盟广告'},
     *{value: 300, name: '视频广告'}*             ],
     * @param timeDataList
     * @param stringBuilder
     */
    private void printData4Charts(List<TimeData> timeDataList, StringBuilder stringBuilder) {
        stringBuilder.append("\n\n\n")
        stringBuilder.append("option = {\n" +
                "    title: {\n" +
                "        text: 'Task耗时分布',\n" +
                "        subtext: '耗时详情',\n" +
                "        left: 'center'\n" +
                "    },\n" +
                "    tooltip: {\n" +
                "        trigger: 'item'\n" +
                "    },\n" +
                "    series: [\n" +
                "        {\n" +
                "            name: '耗时详情',\n" +
                "            type: 'pie',\n" +
                "            radius: '50%',\n" +
                "            data: [").append("\n");
        for (TimeData timeData : timeDataList) {
            stringBuilder.append("{value:")
                    .append(timeData.time)
                    .append(",name:'")
                    .append(timeData.taskName)
                    .append("'},").append("\n")
        }
        stringBuilder.append("],\n" +
                "            emphasis: {\n" +
                "                itemStyle: {\n" +
                "                    shadowBlur: 10,\n" +
                "                    shadowOffsetX: 0,\n" +
                "                    shadowColor: 'rgba(0, 0, 0, 0.5)'\n" +
                "                }\n" +
                "            }\n" +
                "        }\n" +
                "    ]\n" +
                "};");
    }


    /**
     * 打印markdown
     * @param timeDataList
     * @param stringBuilder
     */
    private void printData4Markdown(List<TimeData> timeDataList, StringBuilder stringBuilder) {
        timeDataList.sort(new Comparator<TimeData>() {
            @Override
            int compare(TimeData timeData, TimeData t1) {
                return (int) (t1.time - timeData.time);
            }
        });
        stringBuilder.append("\n\n\n")
        stringBuilder.append("|task名称|耗时(ms)|备注|").append("\n")
        stringBuilder.append("|:---|:---|:---|").append("\n")
        for (TimeData timeData : timeDataList) {
            stringBuilder.append(String.format("|%s|%s||", timeData.taskName, timeData.time)).append("\n")
        }
        stringBuilder.append("\n\n\n")
    }


    /**
     * 打印任务执行的时间线
     * @param timeDataList
     * @param stringBuilder
     */
    private void printTimeline4Text(List<TimeData> timeDataList, StringBuilder stringBuilder) {
        timeDataList.sort(new Comparator<TimeData>() {
            @Override
            int compare(TimeData timeData, TimeData t1) {
                return (int) (timeData.startTime4Charts - t1.startTime4Charts);
            }
        });
        stringBuilder.append("\n\n\n")
        stringBuilder.append("task执行的timeline").append("\n")
        TimeData lastItem = timeDataList.get(timeDataList.size() - 1);
        int step = (int) (lastItem.startTime4Charts + lastItem.time) / 120 + 1;
        println('[taskio]:step = '+step)
        char eChar = ' ';
        char sChar = '▇';
        for (TimeData timeData : timeDataList) {
            int eCount = (int) (timeData.startTime4Charts / step) + 1;
            int sCount = (int) (timeData.time / step) + 1;
            for (int i = 0; i < eCount; i++) {
                stringBuilder.append(eChar);
            }
            for (int i = 0; i < sCount; i++) {
                stringBuilder.append(sChar);
            }
            stringBuilder.append("(").append(timeData.time).append("ms)").append(timeData.taskName).append("\n");
        }
        stringBuilder.append("\n\n\n")
    }

}

6.对Jar文件进行处理

    /**
     * 从inputJarPath删除特定的class,将剩余的class,写入到outPutJarPath
     * @param inputJarPath
     * @param outPutJarPath
     * @param clazzNameSet
     */
    private void removeClassInJar(String inputJarPath, String outPutJarPath, HashSet<String> clazzNameSet) {
        try {
            JarFile inputJarFile = new JarFile(inputJarPath);
            Enumeration<JarEntry> inputJarEntries = inputJarFile.entries();
            //将oldJarEntries中的oldJar替换掉,并将对应的新Jar生成
            File outFile = new File(outPutJarPath);
            if (outFile.exists()) {
                outFile.delete();
            }
            outFile.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(outFile);
            CheckedOutputStream checksum = new CheckedOutputStream(fileOutputStream, new Adler32());
            ZipOutputStream out = new ZipOutputStream(checksum);
            while (inputJarEntries.hasMoreElements()) {
                ZipEntry element = inputJarEntries.nextElement();
                String currentClassName = element.getName();
                if (!clazzNameSet.contains(currentClassName)) {
                    try {
                        out.putNextEntry(element);
                        InputStream entryIn = inputJarFile.getInputStream(element);
                        int read;
                        byte[] buf = new byte[4096];
                        while ((read = entryIn.read(buf, 0, buf.length)) != -1) {
                            out.write(buf, 0, read);
                        }
                        out.flush();
                        out.closeEntry();
                        entryIn.close();
                    } catch (Exception e) {
                        throw e;
                    }
                }
            }
            out.finish();
            out.close();
            fileOutputStream.close();
            inputJarFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

7.修改AndroidManifest

//@version mochuan.zhb on 2019/4/15.
//@Author Zheng Haibo
//@Blog github.com/nuptboyzhb
//@Company Alibaba Group
//@Description 适配mateX + targetSdkVersion升级适配:透明背景的Activity,删除其screenOrientation属性


import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.TransformerFactory

project.afterEvaluate {
    def LOG_TAG = 'ManifestFlodHandler: '
    Task taskProcessReleaseManifest = project.tasks.findByName('splitsDiscoveryTaskRelease')
    if (taskProcessReleaseManifest) {
        taskProcessReleaseManifest.doFirst {
            println(LOG_TAG + 'splitsDiscoveryTaskRelease doFirst files: ' + it.outputs.files.files)
            def manifestFileName = './launcher/build/intermediates/manifests/full/release/AndroidManifest.xml'
            def document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(manifestFileName)
            def activities = document.getElementsByTagName('activity')
            println(LOG_TAG + 'Activites size: ' + activities.getLength())

            def buffReader = new BufferedReader(new FileReader('./launcher/recreate_activites'))
            def recreateActivities = []
            def line = null
            while (null != (line = buffReader.readLine())) {
                if (line.startsWith('com.')) {
                    recreateActivities.add(line)
                }
            }
            buffReader.close()
            def attNameName = 'android:name'
            def attConfigChangesName = 'android:configChanges'
            def attResizeableActivityName = 'android:resizeableActivity'
            //android:screenOrientation="portrait"
            def attScreenOrientationName = 'android:screenOrientation'
            def attThemeName = 'android:theme'
            for (int i = 0; i < activities.getLength(); i++) {
                def attributes = activities.item(i).getAttributes()

                def attName = attributes.getNamedItem(attNameName)
                def attConfigChanges = attributes.getNamedItem(attConfigChangesName)
                def attResizeableActivity = attributes.getNamedItem(attResizeableActivityName)
                def attScreenOrientation = attributes.getNamedItem(attScreenOrientationName)
                def attTheme = attributes.getNamedItem(attThemeName)

                // add multi-window support
                if (attResizeableActivity == null) {
                    def attResizeNew = document.createAttribute(attResizeableActivityName)
                    attResizeNew.setNodeValue('true')
                    attributes.setNamedItem(attResizeNew)
                } else if (attResizeableActivity.getNodeValue() == 'false') {
                    println(LOG_TAG + "不支持多窗口 ==> " + attName.getNodeValue())
                }

                if (attName.getNodeValue() in recreateActivities) {
                    println(LOG_TAG + ' ' + attName.getNodeValue() + ' In WhiteList, Use Recreate Plan.')
                    continue
                }

                // add config change support
                if (attConfigChanges != null) {
                    //screenSize|smallestScreenSize|screenLayout
                    def value = attConfigChanges.getNodeValue()
                    if (!value.contains('screenSize')) {
                        value += '|screenSize'
                    }
                    if (!value.contains('smallestScreenSize')) {
                        value += '|smallestScreenSize'
                    }
                    if (!value.contains('screenLayout')) {
                        value += '|screenLayout'
                    }
                    attConfigChanges.setNodeValue(value)
                } else {
                    def attConfigNew = document.createAttribute(attConfigChangesName)
                    attConfigNew.setNodeValue('screenSize|smallestScreenSize|screenLayout')
                    attributes.setNamedItem(attConfigNew)
                }

                if (attTheme != null && attScreenOrientation != null) {
                    if (attTheme.getNodeValue() != null && (attTheme.getNodeValue().toLowerCase().contains("translucent")
                            || attTheme.getNodeValue().toLowerCase().contains("transparent")
                            || attTheme.getNodeValue().toLowerCase().contains("vrtheme")
                            || attTheme.getNodeValue().toLowerCase().contains("alipaylogintheme")
                            || attTheme.getNodeValue().toLowerCase().contains("mspapppaytheme")
                            || attTheme.getNodeValue().toLowerCase().contains("mspapptheme"))) {
                        attributes.removeNamedItem(attScreenOrientationName)
                        println 'remove screenOrientation:' + attName
                    }
                }

            }

            //save change to AndroidManifest.xml
            def transformer = TransformerFactory.newInstance().newTransformer()
            transformer.transform(new DOMSource(document), new StreamResult(manifestFileName))

        }
    }
    Task taskProcessDebugManifest = project.tasks.findByName('splitsDiscoveryTaskDebug')
    if (taskProcessDebugManifest) {
        taskProcessDebugManifest.doFirst {
            println(LOG_TAG + 'splitsDiscoveryTaskDebug doFirst files: ' + it.outputs.files.files)
            def manifestFileName = './launcher/build/intermediates/manifests/full/debug/AndroidManifest.xml'
            def document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(manifestFileName)
            def activities = document.getElementsByTagName('activity')
            println(LOG_TAG + 'Activites size: ' + activities.getLength())

            def buffReader = new BufferedReader(new FileReader('./launcher/recreate_activites'))
            def recreateActivities = []
            def line = null
            while (null != (line = buffReader.readLine())) {
                if (line.startsWith('com.')) {
                    recreateActivities.add(line)
                }
            }
            buffReader.close()
            def attNameName = 'android:name'
            def attConfigChangesName = 'android:configChanges'
            def attResizeableActivityName = 'android:resizeableActivity'
            //android:screenOrientation="portrait"
            def attScreenOrientationName = 'android:screenOrientation'
            def attThemeName = 'android:theme'
            for (int i = 0; i < activities.getLength(); i++) {
                def attributes = activities.item(i).getAttributes()

                def attName = attributes.getNamedItem(attNameName)
                def attConfigChanges = attributes.getNamedItem(attConfigChangesName)
                def attResizeableActivity = attributes.getNamedItem(attResizeableActivityName)
                def attScreenOrientation = attributes.getNamedItem(attScreenOrientationName)
                def attTheme = attributes.getNamedItem(attThemeName)

                // add multi-window support
                if (attResizeableActivity == null) {
                    def attResizeNew = document.createAttribute(attResizeableActivityName)
                    attResizeNew.setNodeValue('true')
                    attributes.setNamedItem(attResizeNew)
                } else if (attResizeableActivity.getNodeValue() == 'false') {
                    println(LOG_TAG + "不支持多窗口 ==> " + attName.getNodeValue())
                }

                if (attName.getNodeValue() in recreateActivities) {
                    println(LOG_TAG + ' ' + attName.getNodeValue() + ' In WhiteList, Use Recreate Plan.')
                    continue
                }

                // add config change support
                if (attConfigChanges != null) {
                    //screenSize|smallestScreenSize|screenLayout
                    def value = attConfigChanges.getNodeValue()
                    if (!value.contains('screenSize')) {
                        value += '|screenSize'
                    }
                    if (!value.contains('smallestScreenSize')) {
                        value += '|smallestScreenSize'
                    }
                    if (!value.contains('screenLayout')) {
                        value += '|screenLayout'
                    }
                    attConfigChanges.setNodeValue(value)
                } else {
                    def attConfigNew = document.createAttribute(attConfigChangesName)
                    attConfigNew.setNodeValue('screenSize|smallestScreenSize|screenLayout')
                    attributes.setNamedItem(attConfigNew)
                }

                if (attTheme != null && attScreenOrientation != null) {
                    if (attTheme.getNodeValue() != null && (attTheme.getNodeValue().toLowerCase().contains("translucent")
                            || attTheme.getNodeValue().toLowerCase().contains("transparent")
                            || attTheme.getNodeValue().toLowerCase().contains("vrtheme")
                            || attTheme.getNodeValue().toLowerCase().contains("alipaylogintheme")
                            || attTheme.getNodeValue().toLowerCase().contains("mspapppaytheme")
                            || attTheme.getNodeValue().toLowerCase().contains("mspapptheme"))) {
                        attributes.removeNamedItem(attScreenOrientationName)
                        println 'remove screenOrientation:' + attName
                    }
                }

            }

            //save change to AndroidManifest.xml
            def transformer = TransformerFactory.newInstance().newTransformer()
            transformer.transform(new DOMSource(document), new StreamResult(manifestFileName))

        }
    }

}

排查编译问题的思路

  • 分析每个Task的构建产物
  • 反编译jar
  • 反编译apk
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值