Android Gradle插件提供的Transform API如何使用?
How to use the Transform API provided by Android Gradle plugin?
我用applicationVariants.dex.dependsOn任务在代码转换成dex文件之前做了一些额外的工作,在android[=70之前一切正常=] 插件 1.3。但是从1.4开始,dex任务被禁止访问,会出现这样的错误提示:
好的。我需要使用新的 Transform API 而不是 dex 任务。但问题是关于 Transform API 的文档真的很少。我能找到的是Google官方文档here,但是好像不太好理解
所以我尝试编写一个自定义转换,但我真的不知道我是否正确:
public class MyTransform extends Transform {
@Override
public String getName() {
return "MyTransformImpl";
}
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
Set<QualifiedContent.ContentType> set = new HashSet<QualifiedContent.ContentType>();
set.add(QualifiedContent.DefaultContentType.CLASSES);
return set;
}
@Override
public Set<QualifiedContent.Scope> getScopes() {
Set<QualifiedContent.Scope> set = new HashSet<QualifiedContent.Scope>();
set.add(QualifiedContent.Scope.PROJECT);
return set;
}
@Override
public boolean isIncremental() {
return false;
}
}
这是一个空的自定义转换。我没有添加转换逻辑,但这不是问题所在。
然后我使用 gradle 文件中记录的 api 注册了这个 Transform:
def transform = new MyTransform()
project.android.registerTransform(transform)
当我执行 assemble 任务时,我的自定义转换似乎有效。从正在执行的任务列表可以看到:
终于apk文件生成成功,一切正常。但是当我安装 apk 并启动应用程序时,它崩溃了。出现这样的错误:
这很奇怪。引发了 ClassNotFoundException,而我的 MainActivity 丢失了。怎么可能!然后我重新编译我的apk文件并在jd-gui中查看源代码,我完全糊涂了。
我的代码都不见了。仅保留支持库中的 classes。但实际上我的代码 .class 文件存在于 app/build/intermediates/classes/ 目录中。如果我在 gradle:
中注释掉注册行
// project.android.registerTransform(transform)
一切顺利。所以我猜我写错了custom transform,但我真的不知道如何写一个正确的
有人能帮忙吗?衷心感谢。
当您实施 Transform
时,您必须处理文件并将它们写入输出文件夹。即使您不处理 class 个文件,您仍然必须将它们复制到输出文件夹。如果您不这样做,所有 class 个文件都会被删除。
要使 Transform
正常工作,您必须执行以下步骤。首先,您需要指定您的转换处理输入 class 个文件并生成 class 个文件。
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return Collections.singleton(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set<QualifiedContent.ContentType> getOutputTypes() {
return EnumSet.of(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set<QualifiedContent.Scope> getScopes() {
return EnumSet.of(QualifiedContent.Scope.PROJECT)
}
然后在 transform
方法中,您需要获取输入和输出文件夹。
final DirectoryInput directoryInput = inputs.first().directoryInputs.first()
final File input = directoryInput.file
final File output = outputProvider.getContentLocation(
directoryInput.name, EnumSet.of(QualifiedContent.DefaultContentType.CLASSES),
EnumSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY)
最后,您必须将所有文件从 input
复制到 output
。
这是实现 Transformation
的 project。也许你会更容易理解转换是如何通过一个真实的例子来工作的。
我用applicationVariants.dex.dependsOn任务在代码转换成dex文件之前做了一些额外的工作,在android[=70之前一切正常=] 插件 1.3。但是从1.4开始,dex任务被禁止访问,会出现这样的错误提示:
好的。我需要使用新的 Transform API 而不是 dex 任务。但问题是关于 Transform API 的文档真的很少。我能找到的是Google官方文档here,但是好像不太好理解
所以我尝试编写一个自定义转换,但我真的不知道我是否正确:
public class MyTransform extends Transform {
@Override
public String getName() {
return "MyTransformImpl";
}
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
Set<QualifiedContent.ContentType> set = new HashSet<QualifiedContent.ContentType>();
set.add(QualifiedContent.DefaultContentType.CLASSES);
return set;
}
@Override
public Set<QualifiedContent.Scope> getScopes() {
Set<QualifiedContent.Scope> set = new HashSet<QualifiedContent.Scope>();
set.add(QualifiedContent.Scope.PROJECT);
return set;
}
@Override
public boolean isIncremental() {
return false;
}
}
这是一个空的自定义转换。我没有添加转换逻辑,但这不是问题所在。 然后我使用 gradle 文件中记录的 api 注册了这个 Transform:
def transform = new MyTransform()
project.android.registerTransform(transform)
当我执行 assemble 任务时,我的自定义转换似乎有效。从正在执行的任务列表可以看到:
终于apk文件生成成功,一切正常。但是当我安装 apk 并启动应用程序时,它崩溃了。出现这样的错误:
这很奇怪。引发了 ClassNotFoundException,而我的 MainActivity 丢失了。怎么可能!然后我重新编译我的apk文件并在jd-gui中查看源代码,我完全糊涂了。
我的代码都不见了。仅保留支持库中的 classes。但实际上我的代码 .class 文件存在于 app/build/intermediates/classes/ 目录中。如果我在 gradle:
中注释掉注册行// project.android.registerTransform(transform)
一切顺利。所以我猜我写错了custom transform,但我真的不知道如何写一个正确的
有人能帮忙吗?衷心感谢。
当您实施 Transform
时,您必须处理文件并将它们写入输出文件夹。即使您不处理 class 个文件,您仍然必须将它们复制到输出文件夹。如果您不这样做,所有 class 个文件都会被删除。
要使 Transform
正常工作,您必须执行以下步骤。首先,您需要指定您的转换处理输入 class 个文件并生成 class 个文件。
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return Collections.singleton(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set<QualifiedContent.ContentType> getOutputTypes() {
return EnumSet.of(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set<QualifiedContent.Scope> getScopes() {
return EnumSet.of(QualifiedContent.Scope.PROJECT)
}
然后在 transform
方法中,您需要获取输入和输出文件夹。
final DirectoryInput directoryInput = inputs.first().directoryInputs.first()
final File input = directoryInput.file
final File output = outputProvider.getContentLocation(
directoryInput.name, EnumSet.of(QualifiedContent.DefaultContentType.CLASSES),
EnumSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY)
最后,您必须将所有文件从 input
复制到 output
。
这是实现 Transformation
的 project。也许你会更容易理解转换是如何通过一个真实的例子来工作的。