文章目录
Task9 generateDebugResValues
1. input/ouput
taskName:generateDebugResValues
=========================================================
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/generated/res/resValues/debug
简单的说该任务就是生成一个generated.xml文件,里面包含了在build.gradle文件中自定义的资源属性
- 配置自定义资源属性
- 输出xml文件结构
2. 核心类(GenerateResValues)
public class GenerateResValues extends AndroidBuilderTask {
@TaskAction
void generate() throws IOException, ParserConfigurationException {
File folder = getResOutputDir();
//1. 读取build.gradle中自定义的资源配置数据项
List<Object> resolvedItems = getItems();
//2. 如果未自定义,清空旧数据
if (resolvedItems.isEmpty()) {
FileUtils.cleanOutputDir(folder);
} else {
//如果自定义了,将自定义资源数据项交给资源值生成器对象
ResValueGenerator generator = new ResValueGenerator(folder);
generator.addItems(getItems());
//3. 生成generated.xml
generator.generate();
}
}
}
代码看流程清晰明了,关键代码就是将自定义属性(支持12种类型属性哦)写入到xml文件中,其实现细节集中在类ResValueGenerator.generater中;内部主要使用DOM API来实现,具体不再详细说明,贴下实现代码
public class ResValueGenerator {
public static final String RES_VALUE_FILENAME_XML = "generated.xml";
private static final List<ResourceType> RESOURCES_WITH_TAGS = ImmutableList.of(
ResourceType.ARRAY,
ResourceType.ATTR,
ResourceType.BOOL,
ResourceType.COLOR,
ResourceType.DECLARE_STYLEABLE,
ResourceType.DIMEN,
ResourceType.FRACTION,
ResourceType.INTEGER,
ResourceType.PLURALS,
ResourceType.STRING,
ResourceType.STYLE);
/**
* Generates the resource files
*/
public void generate() throws IOException, ParserConfigurationException {
File pkgFolder = getFolderPath();
if (!pkgFolder.isDirectory()) {
if (!pkgFolder.mkdirs()) {
throw new RuntimeException("Failed to create " + pkgFolder.getAbsolutePath());
}
}
File resFile = new File(pkgFolder, RES_VALUE_FILENAME_XML);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
factory.setIgnoringComments(true);
DocumentBuilder builder;
builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
//创建根节点resources
Node rootNode = document.createElement(TAG_RESOURCES);
document.appendChild(rootNode);
//添加子节点,此处就是添加些注释说明
rootNode.appendChild(document.createTextNode("\n"));
rootNode.appendChild(document.createComment("Automatically generated file. DO NOT MODIFY"));
rootNode.appendChild(document.createTextNode("\n\n"));
//遍历自定义资源属性
for (Object item : mItems) {
if (item instanceof ClassField) {
ClassField field = (ClassField)item;
ResourceType type = ResourceType.getEnum(field.getType());
//判断是否是通用的11种类型中一种
boolean hasResourceTag = (type != null && RESOURCES_WITH_TAGS.contains(type));
//如果不是通用的资源类型,则生成<item>标签节点
Node itemNode = document.createElement(hasResourceTag ? field.getType() : TAG_ITEM);
Attr nameAttr = document.createAttribute(ATTR_NAME);
nameAttr.setValue(field.getName());
itemNode.getAttributes().setNamedItem(nameAttr);
if (!hasResourceTag) {
//如果是item标签,需要设置其type、name属性值
//eg:<item type="id" name="button_ok" />
Attr typeAttr = document.createAttribute(ATTR_TYPE);
typeAttr.setValue(field.getType());
itemNode.getAttributes().setNamedItem(typeAttr);
}
if (type == ResourceType.STRING) {
//如果是string资源,添加traslatable属性,使其设备统一使用该字段,和系统语言等无关
Attr translatable = document.createAttribute(ATTR_TRANSLATABLE);
translatable.setValue(VALUE_FALSE);
itemNode.getAttributes().setNamedItem(translatable);
}
if (!field.getValue().isEmpty()) {
itemNode.appendChild(document.createTextNode(field.getValue()));
}
rootNode.appendChild(itemNode);
} else if (item instanceof String) {
rootNode.appendChild(document.createTextNode("\n"));
rootNode.appendChild(document.createComment((String) item));
rootNode.appendChild(document.createTextNode("\n"));
}
}
String content;
try {
content = XmlPrettyPrinter.prettyPrint(document, true);
} catch (Throwable t) {
content = XmlUtils.toXml(document);
}
//写文件
Files.write(content, resFile, Charsets.UTF_8);
}
}
支持的自定义资源属性类型
序号 | 类型 |
---|---|
1 | array |
2 | attr |
3 | bool |
4 | color |
5 | declare-styleable |
6 | dimen |
7 | fraction |
8 | integer |
9 | plurals |
10 | string |
11 | style |
12 | item |
Task10 generateDebugResources
属于空task直接忽略
Task11 mergeDebugResources
合并资源任务
1. input/ouput
taskName:mergeDebugResources
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/aapt2-3.2.0-4818971-osx.jar/c5355294e416159d9559f45d46460f7d/aapt2-3.2.0-4818971-osx
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/res/resValues/debug
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/res
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/res
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/res
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/res
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/res/rs/debug
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/main/res
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/debug/res
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/blame/res/debug
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/res/pngs/debug
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/incremental/mergeDebugResources
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/res/merged/debug
先来一张总流程图吧,先把握主线;文字描述的不一定有图清楚
xml -> drawable 、string 、color、anim、layout、value
layout、generated
png
先看输入好了,可以很清楚看到输入都是项目依赖的库的res文件以及本身结构的res文件
输出路径 | 产物 | 备注 | 所在类 |
---|---|---|---|
app/build/intermediates/blame/res/debug | 1. 日志文件 2. 资源文件和编译后产物的映射表文件 | — | |
app/build/generated/res/pngs/debug | 资源文件vector、png | xxx | |
app/build/intermediates/incremental/mergeDebugResources | 1、merged.dir 存放合并资源文件的地方2、stripped.dir 3、compile-file-map.properties 资源和编译产物映射表 4、merger.xml 合并文件 | MergedResourceWriter | |
app/build/intermediates/res/merged/debug | flat文件 | AAPT2编译的产物,也就是本上图的重点产物 | MergedResourceWriter |
app/build/intermediates/incremental/mergeDebugResources
- merged.dir
- stripped.dir
- compile-file-map.properties
- merger.xml
2. 核心类(MergeResources)
@CacheableTask
public class MergeResources extends IncrementalTask {
@Override
protected void doFullTaskAction() throws IOException, JAXBException {
ResourcePreprocessor preprocessor = getPreprocessor();
// this is full run, clean the previous outputs
File destinationDir = getOutputDir();
FileUtils.cleanOutputDir(destinationDir);
if (dataBindingLayoutInfoOutFolder != null) {
FileUtils.deleteDirectoryContents(dataBindingLayoutInfoOutFolder);
}
List<ResourceSet> resourceSets = getConfiguredResourceSets(preprocessor);
// create a new merger and populate it with the sets.
ResourceMerger merger = new ResourceMerger(minSdk.get());
MergingLog mergingLog = null;
if (blameLogFolder != null) {
FileUtils.cleanOutputDir(blameLogFolder);
mergingLog = new MergingLog(blameLogFolder);
}
try (ResourceCompilationService resourceCompiler =
getResourceProcessor(
aaptGeneration,
getBuilder(),
aapt2FromMaven,
workerExecutorFacade,
crunchPng,
variantScope,
mergingLog,
flags,
processResources)) {
for (ResourceSet resourceSet : resourceSets) {
resourceSet.loadFromFiles(getILogger());
//1. 添加资源
merger.addDataSet(resourceSet);
}
MergedResourceWriter writer =
new MergedResourceWriter(
workerExecutorFacade,
destinationDir,
getPublicFile(),
mergingLog,
preprocessor,
resourceCompiler,
getIncrementalFolder(),
dataBindingLayoutProcessor,
mergedNotCompiledResourcesOutputDirectory,
pseudoLocalesEnabled,
getCrunchPng());
//2. 执行资源合并操作
merger.mergeData