为说明Android构建过程中gradle执行的各task,写了简单demo
git clone https://github.com/xiaobaoyihao/AndroidGradleTaskDemo.git
先罗列下Android构建流程中任务有哪些,本系列讲解都是基于gradle plugin 3.2.0源码
clone下demo,终端执行
./gradlew assembleDebug --console=plain
输出如下任务链
:app:checkDebugClasspath UP-TO-DATE
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:checkDebugManifest UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceDebug UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:createDebugCompatibleScreenManifests UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:splitsDiscoveryTaskDebug UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:javaPreCompileDebug UP-TO-DATE
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk NO-SOURCE
:app:compileDebugSources UP-TO-DATE
:app:mergeDebugShaders UP-TO-DATE
:app:compileDebugShaders UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:transformClassesWithDexBuilderForDebug UP-TO-DATE
:app:transformDexArchiveWithExternalLibsDexMergerForDebug UP-TO-DATE
:app:transformDexArchiveWithDexMergerForDebug UP-TO-DATE
:app:mergeDebugJniLibFolders UP-TO-DATE
:app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE
:app:checkDebugLibraries UP-TO-DATE
:app:processDebugJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE
:app:validateSigningDebug UP-TO-DATE
:app:packageDebug UP-TO-DATE
:app:assembleDebug UP-TO-DATE
为了更清楚观察各任务,我们可以对每个任务的输入和输出添加日志打印,在demo中放开build.gradle中任务打印区域代码
可以通过taskname来查找,一般任务路径大部分都是在
com.android.build.gradle.internal.tasks
com.android.build.gradle.tasks
目录下,任务名称基本和类名一致
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/5b2333922ba05b1f174de51739b24d14/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.0/e414a4cb28434e25c4f6aa71426eb20cf4874ae9/common-1.0.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/checkDebugClasspath/debug
从task字面可以猜测出该任务是对app classpath做校验,具体是在那个类呢?
我们找到到AppClasspathCheckTask.java,如何确定是正确的呢?
我们发现该类中有个ConfigAction.getName方法
其实这个方法的返回字符串就是执行的任务名(checkDebugClasspath),具体怎么流程大家直接看代码就知道了
ConfigAction被调用的地方
核心入口代码
//ApplicationTaskManager.java
@Override
protected Task createVariantPreBuildTask(@NonNull VariantScope scope) {
final VariantType variantType = scope.getVariantConfiguration().getType();
if (variantType.isApk()) {
AppClasspathCheckTask classpathCheck =
taskFactory.create(new AppClasspathCheckTask.ConfigAction(scope));
return (variantType.isTestComponent()
? taskFactory.create(new TestPreBuildTask.ConfigAction(scope))
: taskFactory.create(new AppPreBuildTask.ConfigAction(scope)))
.dependsOn(classpathCheck);
}
return super.createVariantPreBuildTask(scope);
}
有人会问中间的debug怎么多出来?追踪getName方法内部实现发现最终调用BaseVariantData.getTaskName方法
public String getTaskName(@NonNull String prefix, @NonNull String suffix) {
return StringHelper.appendCapitalized(prefix, variantConfiguration.getFullName(), suffix);
}
// VariantConfiguration.java
public String getFullName() {
if (mFullName == null) {
mFullName =
computeFullName(
getFlavorName(),
mBuildType,
mType,
mTestedConfig == null ? null : mTestedConfig.getType());
}
return mFullName;
}
/**
* Returns the full, unique name of the variant in camel case (starting with a lower case),
* including BuildType, Flavors and Test (if applicable).
*
* @param flavorName the flavor name, as computed by {@link #computeFlavorName(List)}
* @param buildType the build type
* @param type the variant type
* @return the name of the variant
*/
public static <B extends BuildType> String computeFullName(
@NonNull String flavorName,
@NonNull B buildType,
@NonNull VariantType type,
@Nullable VariantType testedType) {
StringBuilder sb = new StringBuilder();
if (!flavorName.isEmpty()) {
sb.append(flavorName);
StringHelper.appendCapitalized(sb, buildType.getName());
} else {
sb.append(buildType.getName());
}
if (type.isHybrid()) {
sb.append("Feature");
}
if (type.isTestComponent()) {
if (testedType != null && testedType.isHybrid()) {
sb.append("Feature");
}
sb.append(type.getSuffix());
}
return sb.toString();
}
可以看到computeFullName是返回variant相关的名字,和我们输入的assembleDebug相匹配,所以我们后期直接通过任务名就能准确找到对应ConfigAction类了这样真正的Task类名也就找到了
确定任务名 -> 在所有TaskConfigAction的子类中寻找getName返回值是否与其task名匹配 -> 对应Task实现类
//AppClasspathCheckTask.java
@TaskAction
void run() {
compareClasspaths();
}
//ClasspathComparisionTask.java
void compareClasspaths() {
//com.android.support:appcompat-v7:23.3.0
//group:module/artifact:version
Set<ResolvedArtifactResult> runtimeArtifacts = runtimeClasspath.getArtifacts();
Set<ResolvedArtifactResult> compileArtifacts = compileClasspath.getArtifacts();
// Store a map of groupId -> (artifactId -> versions)
Map<String, Map<String, String>> runtimeIds =
Maps.newHashMapWithExpectedSize(runtimeArtifacts.size());
//1. 存储runtime依赖版本信息到map中groupId -> (artifactId -> versions)
for (ResolvedArtifactResult artifact : runtimeArtifacts) {
// only care about external dependencies to compare versions.
final ComponentIdentifier componentIdentifier =
artifact.getId().getComponentIdentifier();
if (componentIdentifier instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier moduleId =
(ModuleComponentIdentifier) componentIdentifier;
// get the sub-map, creating it if needed.
Map<String, String> subMap =
runtimeIds.computeIfAbsent(moduleId.getGroup(), s -> new HashMap<>());
subMap.put(moduleId.getModule(), moduleId.getVersion());
}
}
//对compileArtifacts集合进行遍历,并和compileArtifacts中相同的group.module比较,如何发现版本不一致,调用onDifferentVersionsFound方法
for (ResolvedArtifactResult artifact : compileArtifacts) {
// only care about external dependencies to compare versions.
final ComponentIdentifier componentIdentifier =
artifact.getId().getComponentIdentifier();
if (componentIdentifier instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier moduleId =
(ModuleComponentIdentifier) componentIdentifier;
Map<String, String> subMap = runtimeIds.get(moduleId.getGroup());
if (subMap == null) {
continue;
}
String runtimeVersion = subMap.get(moduleId.getModule());
if (runtimeVersion == null) {
continue;
}
if (runtimeVersion.equals(moduleId.getVersion())) {
continue;
}
onDifferentVersionsFound(
moduleId.getGroup(),
moduleId.getModule(),
runtimeVersion,
moduleId.getVersion());
}
}
}
//AppClasspathCheckTask.java
@Override
void onDifferentVersionsFound(
@NonNull String group,
@NonNull String module,
@NonNull String runtimeVersion,
@NonNull String compileVersion) {
//这个方法很简单,就是比较版本不一样的话,会提示依赖有冲突,运行时可能导致crash
String suggestedVersion;
try {
GradleVersion runtime = GradleVersion.parse(runtimeVersion);
GradleVersion compile = GradleVersion.parse(compileVersion);
if (runtime.compareTo(compile) > 0) {
suggestedVersion = runtimeVersion;
} else {
suggestedVersion = compileVersion;
}
} catch (Throwable e) {
// in case we are unable to parse versions for some reason, choose runtime
suggestedVersion = runtimeVersion;
}
String message =
String.format(
"Conflict with dependency '%1$s:%2$s' in project '%3$s'. Resolved versions for "
+ "runtime classpath (%4$s) and compile classpath (%5$s) differ. This "
+ "can lead to runtime crashes. To resolve this issue follow "
+ "advice at https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties. "
+ "Alternatively, you can try to fix the problem "
+ "by adding this snippet to %6$s:\n"
+ "dependencies {\n"
+ " implementation(\"%1$s:%2$s:%7$s\")\n"
+ "}\n",
group,
module,
getProject().getPath(),
runtimeVersion,
compileVersion,
getProject().getBuildFile(),
suggestedVersion);
reporter.reportWarning(EvalIssueReporter.Type.GENERIC, message);
}
简单总结:
该任务就是对编译类路径和运行时类路径进行校验,如果相同的group.module中存在不同version,则提示用户依赖有冲突,会导致运行是crash
冲突解决方案参见官网
taskName:preDebugBuild
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/AndroidManifest.xml
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/5b2333922ba05b1f174de51739b24d14/AndroidManifest.xml
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/prebuild/debug
输入都为依赖库的清单文件,输出为空;这个任务简单说也是对应用变体做校验
@TaskAction
void run() {
Set<ResolvedArtifactResult> compileArtifacts = new HashSet<>();
compileArtifacts.addAll(compileManifests.getArtifacts());
compileArtifacts.addAll(compileNonNamespacedManifests.getArtifacts());
Set<ResolvedArtifactResult> runtimeArtifacts = new HashSet<>();
runtimeArtifacts.addAll(runtimeManifests.getArtifacts());
runtimeArtifacts.addAll(runtimeNonNamespacedManifests.getArtifacts());
// create a map where the key is either the sub-project path, or groupId:artifactId for
// external dependencies.
// For external libraries, the value is the version.
Map<String, String> runtimeIds = Maps.newHashMapWithExpectedSize(runtimeArtifacts.size());
// build a list of the runtime artifacts
for (ResolvedArtifactResult artifact : runtimeArtifacts) {
handleArtifact(artifact.getId().getComponentIdentifier(), runtimeIds::put);
}
// run through the compile ones to check for provided only.
for (ResolvedArtifactResult artifact : compileArtifacts) {
final ComponentIdentifier compileId = artifact.getId().getComponentIdentifier();
handleArtifact(
compileId,
(key, value) -> {
//校验代码逻辑
String runtimeVersion = runtimeIds.get(key);
if (runtimeVersion == null) {
if (isBaseModule) {
String display = compileId.getDisplayName();
throw new RuntimeException(
"Android dependency '"
+ display
+ "' is set to compileOnly/provided which is not supported");
}
} else if (!runtimeVersion.isEmpty()) {
// compare versions.
if (!runtimeVersion.equals(value)) {
throw new RuntimeException(
String.format(
"Android dependency '%s' has different version for the compile (%s) and runtime (%s) classpath. You should manually set the same version via DependencyResolution",
key, value, runtimeVersion));
}
}
});
}
}
private void handleArtifact(
@NonNull ComponentIdentifier id, @NonNull BiConsumer<String, String> consumer) {
if (id instanceof ProjectComponentIdentifier) {
consumer.accept(((ProjectComponentIdentifier) id).getProjectPath().intern(), "");
} else if (id instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier moduleComponentId = (ModuleComponentIdentifier) id;
consumer.accept(
moduleComponentId.getGroup() + ":" + moduleComponentId.getModule(),
moduleComponentId.getVersion());
} else if (id instanceof OpaqueComponentArtifactIdentifier) {
// skip those for now.
// These are file-based dependencies and it's unlikely to be an AAR.
} else {
getLogger()
.warn(
"Unknown ComponentIdentifier type: "
+ id.getClass().getCanonicalName());
}
}
如果用compileOnly、provider修饰aar则会失败
验证下我们的想法,add 如下代码到app.build.gradle中
compileOnly 'com.facebook.stetho:stetho:1.5.0'
执行
./gradlew preDebugBuild
执行结果
可以反推compileOnly不支持修饰aar只支持jar
补充下AppClasspathCheckTask是AppPreBuildTask任务前置条件,在的图可以体现出来
taskName:compileDebugAidl
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/aidl
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/aidl
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/main/aidl/com/gradle/task/demo/IHelloAidlInterface.aidl
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/incremental/compileDebugAidl
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/source/aidl/debug
input | output | 备注 |
---|---|---|
*.aidl | build/*.java | java源文件 |
- | dependency.store | .aidl -> .java映射文件表 |
先来看下该类继承关系
AidlCompile -> IncrementalTask(abstract)
//IncrementalTask.java
/**
* Gradle's entry-point into this task. Determines whether or not it's possible to do this task
* incrementally and calls either doIncrementalTaskAction() if an incremental build is possible,
* and doFullTaskAction() if not.
*/
@TaskAction
void taskAction(IncrementalTaskInputs inputs) throws Exception {
//如果是非增量操作,直接走全量操作方法
if (!isIncremental() || !inputs.isIncremental()) {
getProject().getLogger().info("Unable do incremental execution: full task run");
//交给子类实现
doFullTaskAction();
return;
}
//走增量操作方法,并携带变更的输入文件,交给子类实现
doIncrementalTaskAction(getChangedInputs(inputs));
}
private Map<File, FileStatus> getChangedInputs(IncrementalTaskInputs inputs) {
final Map<File, FileStatus> changedInputs = Maps.newHashMap();
inputs.outOfDate(
change -> {
FileStatus status = change.isAdded() ? FileStatus.NEW : FileStatus.CHANGED;
changedInputs.put(change.getFile(), status);
});
inputs.removed(change -> changedInputs.put(change.getFile(), FileStatus.REMOVED));
return changedInputs;
}
可以看到该任务主流程逻辑还是比较简单,如果是全量动作,走doFullTaskAction方法,否则走doIncrementalTaskAction增量操作,我们先来看下全量操作
doFullTaskAction
/** Task to compile aidl files. Supports incremental update. */
@CacheableTask
public class AidlCompile extends IncrementalTask {
private static final String DEPENDENCY_STORE = "dependency.store";
private static final PatternSet PATTERN_SET = new PatternSet().include("**/*.aidl");
@Override
protected void doFullTaskAction() throws IOException {
//1. 全量操作前,先对输出目录做下清理操作
// this is full run, clean the previous output
File destinationDir = getSourceOutputDir();
File parcelableDir = getPackagedDir();
FileUtils.cleanOutputDir(destinationDir);
if (parcelableDir != null) {
FileUtils.cleanOutputDir(parcelableDir);
}
//2. 编译所有aidl文件
DepFileProcessor processor = new DepFileProcessor();
try {
compileAllFiles(processor);
} catch (Exception e) {
throw new RuntimeException(e);
}
//3. 生成aid->java映射文件
List<DependencyData> dataList = processor.getDependencyDataList();
DependencyDataStore store = new DependencyDataStore();
store.addData(dataList);
try {
store.saveTo(new File(getIncrementalFolder(), DEPENDENCY_STORE));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@InputFiles
@SkipWhenEmpty
@PathSensitive(PathSensitivity.RELATIVE)
public FileTree getSourceFiles() {
// this is because aidl may be in the same folder as Java and we want to restrict to
// .aidl files and not java files.
return getProject().files(sourceDirs.get()).getAsFileTree().matching(PATTERN_SET);
}
}
@InputFiles
@SkipWhenEmpty
@PathSensitive(PathSensitivity.RELATIVE)
public FileTree getSourceFiles() {
// this is because aidl may be in the same folder as Java and we want to restrict to
// .aidl files and not java files.
return getProject().files(sourceDirs.get()).getAsFileTree().matching(PATTERN_SET);
}
可以看到关键方法是compileAllFiles它是调用aidl工具生成了java源文件,进去看下
public void compileAllAidlFiles(
@NonNull Collection<File> sourceFolders,
@NonNull File sourceOutputDir,
@Nullable File packagedOutputDir,
@Nullable Collection<String> packageWhiteList,
@NonNull Collection<File> importFolders,
@Nullable DependencyFileProcessor dependencyFileProcessor,
@NonNull ProcessOutputHandler processOutputHandler)
throws IOException, InterruptedException, ProcessException {
//1. 校验输入参数
checkNotNull(sourceFolders, "sourceFolders cannot be null.");
checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");
checkNotNull(importFolders, "importFolders cannot be null.");
checkState(mTargetInfo != null,
"Cannot call compileAllAidlFiles() before setTargetInfo() is called.");
IAndroidTarget target = mTargetInfo.getTarget();
BuildToolInfo buildToolInfo = mTargetInfo.getBuildTools();
//2. 关键点,获取aidl工具路径(先确定buildTool版本,在从buildTool工具包中找aidl工具包,见下图);便于以后调用
String aidl = buildToolInfo.getPath(BuildToolInfo.PathId.AIDL);
if (aidl == null || !new File(aidl).isFile()) {
throw new IllegalStateException("aidl is missing from '" + aidl + "'");
}
List<File> fullImportList = Lists.newArrayListWithCapacity(
sourceFolders.size() + importFolders.size());
fullImportList.addAll(sourceFolders);
fullImportList.addAll(importFolders);
//3. 构建一个aidl处理器,用来生成java文件
AidlProcessor processor = new AidlProcessor(
aidl,
target.getPath(IAndroidTarget.ANDROID_AIDL),
fullImportList,
sourceOutputDir,
packagedOutputDir,
packageWhiteList,
dependencyFileProcessor != null ?
dependencyFileProcessor : DependencyFileProcessor.NO_OP,
mProcessExecutor,
processOutputHandler);
//4. 对输入的aidl文件集合进行遍历,一次执行编译操作
for (File dir : sourceFolders) {
DirectoryWalker.builder()
.root(dir.toPath())
.extensions("aidl")
.action(processor)
.build()
.walk();
}
}
操作流程
DirectoryWalker.walk -> AidlProcessor.call -> GradleProcessExecutor.execute
贴下AidlProcessor.call部分代码
public void call(@NonNull Path startDir, @NonNull Path path) throws IOException {
ProcessInfoBuilder builder = new ProcessInfoBuilder();
builder.setExecutable(mAidlExecutable);
builder.addArgs("-p" + mFrameworkLocation);
builder.addArgs("-o" + mSourceOutputDir.getAbsolutePath());
// add all the library aidl folders to access parcelables that are in libraries
for (File f : mImportFolders) {
builder.addArgs("-I" + f.getAbsolutePath());
}
// create a temp file for the dependency
File depFile = File.createTempFile("aidl", ".d");
builder.addArgs("-d" + depFile.getAbsolutePath());
builder.addArgs(path.toAbsolutePath().toString());
ProcessResult result = mProcessExecutor.execute(
builder.createProcess(), mProcessOutputHandler);
...
}
简单梳理下,第三部就是生成dependency.store文件了,这个就过了,大家有兴趣自己看好啦。
增量操作这里简单说下主要分几步操作
依赖任务:preBuildTask
public AidlCompile createAidlTask(@NonNull VariantScope scope) {
AidlCompile aidlCompileTask = taskFactory.create(new AidlCompile.ConfigAction(scope));
scope.getTaskContainer().setAidlCompileTask(aidlCompileTask);
scope.getTaskContainer().getSourceGenTask().dependsOn(aidlCompileTask);
//依赖preBuildTask
aidlCompileTask.dependsOn(scope.getTaskContainer().getPreBuildTask());
return aidlCompileTask;
}
RenderScript 是用于在 Android 上以高性能运行计算密集型任务的框架。RenderScript 主要用于数据并行计算,不过串行工作负载也可以从中受益。RenderScript 运行时可在设备上提供的多个处理器(如多核 CPU 和 GPU)间并行调度工作。这样您就能够专注于表达算法而不是调度工作。RenderScript 对于执行图像处理、计算摄影或计算机视觉的应用来说尤其有用。
taskName:compileDebugRenderscript
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/debug/rs
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/src/main/rs
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/rs/debug/lib
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/rs/debug/obj
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/res/rs/debug
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/generated/source/rs/debug
套路和任务3差不多,调用工具(llvm-rs-cc)生成源文件
核心代码
@TaskAction
void taskAction() throws IOException, InterruptedException, ProcessException {
// 1.预操作,清理作用
// this is full run (always), clean the previous outputs
File sourceDestDir = getSourceOutputDir();
FileUtils.cleanOutputDir(sourceDestDir);
File resDestDir = getResOutputDir();
FileUtils.cleanOutputDir(resDestDir);
File objDestDir = getObjOutputDir();
FileUtils.cleanOutputDir(objDestDir);
File libDestDir = getLibOutputDir();
FileUtils.cleanOutputDir(libDestDir);
Set<File> sourceDirectories = sourceDirs.getFiles();
//2. 编译所有rs文件,套路和aidl差不多
getBuilder()
.compileAllRenderscriptFiles(
sourceDirectories,
getImportFolders(),
sourceDestDir,
resDestDir,
objDestDir,
libDestDir,
getTargetApi(),
isDebugBuild(),
getOptimLevel(),
isNdkMode(),
isSupportMode(),
useAndroidX(),
getNdkConfig() == null ? null : getNdkConfig().getAbiFilters(),
new LoggedProcessOutputHandler(getILogger()));
}
具体细节不再阐述了,大家有兴趣自己看源码
https://developer.android.com/studio/build/dependencies#resolution_errors
compileOnly的限制
Android新配置说明
https://developer.android.com/guide/topics/renderscript/compute?hl=zh-cn