【问题标题】:How to use the Transform API provided by Android Gradle plugin?如何使用 Android Gradle 插件提供的 Transform API?
【发布时间】:2016-04-12 08:21:28
【问题描述】:

在将代码转换为dex文件之前,我使用applicationVariants.dex.dependsOn任务做了一些额外的工作,并且在android gradle plugin 1.3之前它工作得很好。但是从1.4开始,dex任务被禁止访问,会出现这样的错误提示:

好的。我需要使用新的 Transform API 而不是 dex 任务。但问题是关于Transform API 的文档真的很少。查到的是谷歌官方文档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中查看了源代码,我完全糊涂了。

我的代码都不见了。只保留支持库中的类。但实际上我的代码 .class 文件存在于 app/build/intermediates/classes/ 目录中。如果我在 gradle 中注释掉注册行:

// project.android.registerTransform(transform)

一切顺利。所以我想我写了一个错误的自定义转换,但我真的不知道如何写一个正确的。

有人可以帮忙吗?衷心感谢。

【问题讨论】:

  • 您好 Tony,您能否在 GitHub 上提供一个用于 Transform API 的示例应用程序?

标签: android gradle transform gradle-plugin


【解决方案1】:

当您实现Transform 时,您必须处理文件并将它们写入输出文件夹。即使您不处理类文件,您仍然必须将它们复制到输出文件夹。如果你不这样做,所有的类文件都会被删除。

要使Transform 工作,您必须执行以下步骤。首先,您需要指定您的转换处理输入类文件并生成类文件。

  @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

这是一个实现Transformationproject。也许通过一个真实的例子你会更容易理解转换是如何工作的。

【讨论】:

  • 有什么更具体的吗?我真的不知道如何处理文件并将它们复制到输出文件夹。在文档上没有发现任何关于此的内容。谢谢
  • 我还添加了一个使用 Transform API 的项目的链接。
  • 对不起,我遇到了另一个问题。在转换方法中,我可以通过 directoryInput.file 获取应用程序模块路径并处理我的转换逻辑。但是我的项目在同一个项目中有一些库模块。我如何也转换这些库代码?我尝试了文档中的所有可用范围。但他们似乎都没有工作。再次感谢您的回复。
  • 不幸的是,我不知道该怎么做。无论如何,您应该创建另一个问题。
  • 嗨,Michael,我正在尝试通过查看 Git 项目来实现 Transform API。我的 android 应用程序仅使用 Java,而您的项目包含 groovy 和 kotlin,这使得概念有点复杂。你能帮忙提供一个更简单的项目吗?
猜你喜欢
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 2019-06-10
  • 2015-06-04
  • 2023-03-05
相关资源
最近更新 更多