• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import com.android.build.api.variant.AndroidComponentsExtension
2import org.apache.tools.ant.taskdefs.condition.Os
3import org.gradle.api.Plugin
4import org.gradle.api.Project
5import org.w3c.dom.Document
6import org.w3c.dom.Element
7
8import javax.xml.parsers.DocumentBuilder
9import javax.xml.parsers.DocumentBuilderFactory
10import javax.xml.transform.TransformerFactory
11import javax.xml.transform.dom.DOMSource
12import javax.xml.transform.stream.StreamResult
13
14/**
15 * Utility plugin to fix some common resource issues with gradle:
16 *  - add support for androidprv attributes
17 */
18class ResourceFixerPlugin implements Plugin<Project> {
19
20    @Override
21    void apply(Project project) {
22
23        def extension = project.getExtensions().getByType(AndroidComponentsExtension.class);
24        def allVariants = []
25
26        def androidTop = project.extensions.extraProperties.get("ANDROID_TOP");
27        String buildTools = project.extensions.extraProperties.get("BUILD_TOOLS_VERSION")
28        buildTools = buildTools.replace(' ', '-')
29        def aapt = "$androidTop/out/gradle/MockSdk/build-tools/$buildTools/aapt2"
30
31        // Store all variant names
32        extension.onVariants(extension.selector().all(), variant -> {
33            allVariants.add(variant.name)
34            allVariants.add("${variant.name}AndroidTest")
35            allVariants.add("${variant.name}UnitTest")
36        })
37
38        // After the project is evaluated, update the mergeResource task
39        project.afterEvaluate {
40            allVariants.forEach(variant -> {
41                def taskName = "merge${variant.capitalize()}Resources";
42                def mergeTask = project.tasks.findByName(taskName);
43                if (mergeTask == null) {
44                    System.out.println("Task not found " + taskName);
45                    return
46                }
47                mergeTask.doLast {
48                    processResources(
49                            new File(project.buildDir, "intermediates/incremental/${variant}/${taskName}/merged.dir"),
50                            new File(project.buildDir, "intermediates/merged_res/${variant}"),
51                            new File(aapt))
52                }
53            })
54        }
55    }
56
57    void processResources(File xmlDir, File outputDir, File aapt) {
58        for (File values: xmlDir.listFiles()) {
59            if (values.getName().startsWith("values") && values.isDirectory()) {
60                for (File xml : values.listFiles()) {
61                    if (xml.isFile() && xml.getName().endsWith(".xml")
62                            && xml.getText().contains("androidprv:")) {
63                        processAndroidPrv(xml, outputDir, aapt);
64                    }
65                }
66            }
67        }
68    }
69
70    private void processAndroidPrv(File xmlFile, File outputDir, File aapt) {
71        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
72        DocumentBuilder db = dbf.newDocumentBuilder();
73        Document doc = db.parse(xmlFile);
74
75        Element root = doc.getDocumentElement();
76        if (root.hasAttribute("xmlns:androidprv")) {
77            // This file is already processed
78            System.out.println("Skipping " + xmlFile.absolutePath);
79            return
80        }
81        root.setAttribute("xmlns:androidprv", "http://schemas.android.com/apk/prv/res/android");
82
83        // Update the file
84        TransformerFactory.newInstance().newTransformer()
85                .transform(new DOMSource(doc), new StreamResult(xmlFile))
86
87        // recompile
88        String command = aapt.getAbsolutePath() +
89                " compile " +
90                xmlFile.getAbsolutePath() +
91                " -o " +
92                outputDir.getAbsolutePath()
93        def proc = command.execute()
94        def sout = new StringBuilder(), serr = new StringBuilder()
95        proc.consumeProcessOutput(sout, serr)
96        proc.waitForOrKill(5000)
97        System.out.println("Processed " + xmlFile.absolutePath + "  " + sout + "  " + serr);
98    }
99}
100