public abstract class Transform {
/**
* 用于指明 Transform 的名字,也对应了该 Transform 所代表的 Task 名称
*/
@NonNull
public abstract String getName();
/**
* Whether this transform should be applied to a given variant.
*
* @since 3.4
* @return true if the transform should be applied to a given variant, false otherwise.
* @param variant information about the current variant.
*/
@Incubating
public boolean applyToVariant(@NonNull VariantInfo variant) {
return true;
}
/**
* 用于指明 Transform 的输入类型,可以作为输入过滤的手段
*
// 代表 javac 编译成的 class 文件,常用
public static final Set<ContentType> CONTENT_CLASS;
public static final Set<ContentType> CONTENT_JARS;
// 这里的 resources 单指 java 的资源
public static final Set<ContentType> CONTENT_RESOURCES;
public static final Set<ContentType> CONTENT_NATIVE_LIBS;
public static final Set<ContentType> CONTENT_DEX;
public static final Set<ContentType> CONTENT_DEX_WITH_RESOURCES;
public static final Set<ContentType> DATA_BINDING_BASE_CLASS_LOG_ARTIFACT;
*/
@NonNull
public abstract Set<ContentType> getInputTypes();
/**
* Returns the type(s) of data that is generated by the Transform. This may be more than
* one type.
*
* <p>The default implementation returns {@link #getInputTypes()}.
*
* <p><strong>This must be of type {@link QualifiedContent.DefaultContentType}</strong>
*/
@NonNull
public Set<ContentType> getOutputTypes() {
return getInputTypes();
}
/**
* 用于指明 Transform 的作用域
public static final Set<Scope> SCOPE_FULL_PROJECT; // 常用,代表所有 Project
确定了ContentType和Scope后就确定了该自定义Transform需要处理的资源流。
比如CONTENT_CLASS和SCOPE_FULL_PROJECT表示了所有项目中java编译成的class组成的资源流。
*/
@NonNull
public abstract Set<? super Scope> getScopes();
/**
* Returns the referenced scope(s) for the Transform. These scopes are not consumed by
* the Transform. They are provided as inputs, but are still available as inputs for
* other Transforms to consume.
*
* <p>The default implementation returns an empty Set.
*/
@NonNull
public Set<? super Scope> getReferencedScopes() {
return ImmutableSet.of();
}
/**
* Returns a list of additional file(s) that this Transform needs to run. Preferably, use
* {@link #getSecondaryFiles()} API which allow eah secondary file to indicate if changes
* can be handled incrementally or not. This API will treat all additional file change as
* a non incremental event.
*
* <p>Changes to files returned in this list will trigger a new execution of the Transform
* even if the qualified-content inputs haven't been touched.
*
* <p>Any changes to these files will trigger a non incremental execution.
*
* <p>The default implementation returns an empty collection.
*
* @deprecated replaced by {@link #getSecondaryFiles()}
*/
@Deprecated
@NonNull
public Collection<File> getSecondaryFileInputs() {
return ImmutableList.of();
}
/**
* Returns a list of additional file(s) that this Transform needs to run.
*
* <p>Changes to files returned in this list will trigger a new execution of the Transform
* even if the qualified-content inputs haven't been touched.
*
* <p>Each secondary input has the ability to be declared as necessitating a non incremental
* execution in case of change. This Transform can therefore declare which secondary file
* changes it supports in incremental mode.
*
* <p>The default implementation returns an empty collection.
*/
@NonNull
public Collection<SecondaryFile> getSecondaryFiles() {
return ImmutableList.of();
}
/**
* Returns a list of additional (out of streams) file(s) that this Transform creates.
*
* <p>These File instances can only represent files, not directories. For directories, use
* {@link #getSecondaryDirectoryOutputs()}
*
*
* <p>Changes to files returned in this list will trigger a new execution of the Transform
* even if the qualified-content inputs haven't been touched.
*
* <p>Changes to these output files force a non incremental execution.
*
* <p>The default implementation returns an empty collection.
*/
@NonNull
public Collection<File> getSecondaryFileOutputs() {
return ImmutableList.of();
}
/**
* Returns a list of additional (out of streams) directory(ies) that this Transform creates.
*
* <p>These File instances can only represent directories. For files, use
* {@link #getSecondaryFileOutputs()}
*
* <p>Changes to directories returned in this list will trigger a new execution of the Transform
* even if the qualified-content inputs haven't been touched.
*
* <p>Changes to these output directories force a non incremental execution.
*
* <p>The default implementation returns an empty collection.
*/
@NonNull
public Collection<File> getSecondaryDirectoryOutputs() {
return ImmutableList.of();
}
/**
* Returns a map of non-file input parameters using a unique identifier as the map key.
*
* <p>Changes to values returned in this map will trigger a new execution of the Transform
* even if the content inputs haven't been touched.
*
* <p>Changes to these values force a non incremental execution.
*
* <p>The default implementation returns an empty Map.
*/
@NonNull
public Map<String, Object> getParameterInputs() {
return ImmutableMap.of();
}
/**
* 指明该 Transform 是否支持增量编译。需要注意的是,即使返回了 true ,在某些情况下运行时,它还是会返回 false 的。
*/
public abstract boolean isIncremental();
/**
* For Transforms that produce an output available though the [BuildArtifactsHolder] provider
* based interfaces should indicate the output directory of the produced artifact
*
* @param directory
*/
public void setOutputDirectory(@NonNull Property<Directory> directory) {}
public void setOutputFile(@NonNull Property<RegularFile> file) {}
/**
* @deprecated replaced by {@link #transform(TransformInvocation)}.
*/
@Deprecated
@SuppressWarnings("UnusedParameters")
public void transform(
@NonNull Context context,
@NonNull Collection<TransformInput> inputs,
@NonNull Collection<TransformInput> referencedInputs,
@Nullable TransformOutputProvider outputProvider,
boolean isIncremental) throws IOException, TransformException, InterruptedException {
}
/**
* 其中,inputs 是该 Transform 要消费的输入流,有两种格式:jar 和目录格式;referenced
Inputs 集合仅供参考,不应进行转换,它是受 getReferencedScopes 方法控制的;
outputProvider 是用来获取输出目录的,我们要将操作后的文件复制到输出目录中。
*/
public void transform(@NonNull TransformInvocation transformInvocation)
throws TransformException, InterruptedException, IOException {
// Just delegate to old method, for code that uses the old API.
//noinspection deprecation
transform(transformInvocation.getContext(), transformInvocation.getInputs(),
transformInvocation.getReferencedInputs(),
transformInvocation.getOutputProvider(),
transformInvocation.isIncremental());
}
/**
* Returns if this transform's outputs should be cached. Please read {@link
* org.gradle.api.tasks.CacheableTask} Javadoc if you would like to make your transform
* cacheable.
*/
public boolean isCacheable() {
return false;
}
}
public interface TransformInvocation {
// 上下文
@NonNull
Context getContext();
// transform 的输入/输出
@NonNull
Collection<TransformInput> getInputs();
// 返回不被这个 transformation 消费的 input
@NonNull Collection<TransformInput> getReferencedInputs();
/**
* Returns the list of secondary file changes since last. Only secondary files that this
* transform can handle incrementally will be part of this change set.
*/
@NonNull Collection<SecondaryInput> getSecondaryInputs();
// 返回允许创建内容的 output provider
@Nullable
TransformOutputProvider getOutputProvider();
boolean isIncremental();
}
public interface TransformOutputProvider {
void deleteAll() throws IOException;
// 根据 name、ContentType、QualifiedContent.Scope 返回对应的文件(jar / directory)
@NonNull
File getContentLocation(
@NonNull String name,
@NonNull Set<QualifiedContent.ContentType> types,
@NonNull Set<? super QualifiedContent.Scope> scopes,
@NonNull Format format);
}