{"id":32330,"date":"2023-05-30T14:06:43","date_gmt":"2023-05-30T06:06:43","guid":{"rendered":"https:\/\/docs.pingcode.com\/?p=32330"},"modified":"2023-07-31T01:59:50","modified_gmt":"2023-07-30T17:59:50","slug":"gradle-transform%e5%88%b0%e5%ba%95%e6%98%af%e4%bb%80%e4%b9%88%e6%80%8e%e4%b9%88%e7%94%a8","status":"publish","type":"post","link":"https:\/\/docs.pingcode.com\/ask\/32330.html","title":{"rendered":"Gradle Transform\u5230\u5e95\u662f\u4ec0\u4e48\u600e\u4e48\u7528"},"content":{"rendered":"<blockquote class=\"wp-block-quote\">\n<p>Gradle Transform\u662fAndroid\u5b98\u65b9\u63d0\u4f9b\u7ed9\u5f00\u53d1\u8005\u5728\u9879\u76ee\u6784\u5efa\u9636\u6bb5\uff08.class -&gt; .dex\u8f6c\u6362\u671f\u95f4\uff09\u7528\u6765\u4fee\u6539.class\u6587\u4ef6\u7684\u4e00\u5957\u6807\u51c6API\uff0c\u5373\u628a\u8f93\u5165\u7684.class\u6587\u4ef6\u8f6c\u53d8\u6210\u76ee\u6807\u5b57\u8282\u7801\u6587\u4ef6\u3002Gradle Transform\u7684\u4f7f\u7528\uff1a1\u3001\u5728build.gradle\u6587\u4ef6\u4e2d\u6dfb\u52a0Gradle\u63d2\u4ef6\u4f9d\u8d56\uff1b2\u3001\u7f16\u5199Transform\u7c7b\uff1b3\u3001\u914d\u7f6eTransform\u3002<\/p>\n<\/blockquote>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img fetchpriority=\"high\" alt=\"\" class=\"wp-image-32331\" decoding=\"async\" height=\"576\" sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-1024x576.png?x-oss-process=image\/auto-orient,1\/format,webp\" srcset=\"https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-1024x576.png?x-oss-process=image\/auto-orient,1\/format,webp 1024w, https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-300x169.png 300w, https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-768x432.png 768w, https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-270x152.png 270w, https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11-1536x865.png 1536w, https:\/\/cdn-docs.pingcode.com\/wp-content\/uploads\/2023\/05\/3-11.png 1993w\" width=\"1024\"\/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">\u4e00\u3001Gradle Transform\u5230\u5e95\u662f\u4ec0\u4e48<\/h2>\n<p>Gradle Transform\u662fAndroid\u5b98\u65b9\u63d0\u4f9b\u7ed9\u5f00\u53d1\u8005\u5728\u9879\u76ee\u6784\u5efa\u9636\u6bb5\uff08.class -&gt; .dex\u8f6c\u6362\u671f\u95f4\uff09\u7528\u6765\u4fee\u6539.class\u6587\u4ef6\u7684\u4e00\u5957\u6807\u51c6API\uff0c\u5373\u628a\u8f93\u5165\u7684.class\u6587\u4ef6\u8f6c\u53d8\u6210\u76ee\u6807\u5b57\u8282\u7801\u6587\u4ef6\uff0c\u76ee\u524d\u6bd4\u8f83\u7ecf\u5178\u7684\u5e94\u7528\u662f\u5b57\u8282\u7801\u63d2\u6869\u3001\u4ee3\u7801\u6ce8\u5165\u7b49\u3002<\/p>\n<h2 class=\"wp-block-heading\">\u4e8c\u3001Gradle Transform\u600e\u4e48\u7528<\/h2>\n<h3 class=\"wp-block-heading\">1\u3001\u5728build.gradle\u6587\u4ef6\u4e2d\u6dfb\u52a0Gradle\u63d2\u4ef6\u4f9d\u8d56<\/h3>\n<pre class=\"wp-block-code\"><code>buildscript {\n    dependencies {\n        classpath 'com.android.tools.build:gradle:x.x.x'\n        \/\/ \u5176\u4ed6\u63d2\u4ef6\u4f9d\u8d56\n    }\n}\n\napply plugin: 'com.android.application' \/\/ \u6216\u5176\u4ed6\u6240\u9700\u63d2\u4ef6\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">2\u3001\u7f16\u5199Transform\u7c7b<\/h3>\n<p>\u7f16\u5199Transform\u7c7b\uff0c\u5728\u5176\u4e2d\u5b9e\u73b0\u5bf9Java\u5b57\u8282\u7801\u8fdb\u884c\u7684\u4fee\u6539\u3002Transform\u7c7b\u9700\u8981\u7ee7\u627f\u81eaTransform\u63a5\u53e3\u5e76\u5b9e\u73b0\u5176\u4e24\u4e2a\u65b9\u6cd5\uff1a<\/p>\n<pre class=\"wp-block-code\"><code>public class MyTransform extends Transform {\n   @Override\n   public String getName() {\n       return \"myTransform\";\n   }\n\n   @Override\n   public Set&lt;QualifiedContent.ContentType&gt; getInputTypes() {\n       return TransformManager.CONTENT_CLASS;\n   }\n\n   @Override\n   public Set&lt;? super QualifiedContent.Scope&gt; getScopes() {\n       return TransformManager.SCOPE_FULL_PROJECT;\n   }\n\n   @Override\n   public boolean isIncremental() {\n       return false;\n   }\n\n   @Override\n   public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {\n       \/\/ \u5b9e\u73b0Transform\u903b\u8f91\n   }\n}\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">3\u3001\u914d\u7f6eTransform<\/h3>\n<p>\u5728build.gradle\u6587\u4ef6\u4e2d\u914d\u7f6eTransform\uff0c\u5c06\u5176\u4f5c\u4e3a\u7f16\u8bd1\u671f\u95f4\u7684\u4e00\u4e2a\u4efb\u52a1\u6267\u884c\uff1a<\/p>\n<pre class=\"wp-block-code\"><code>android {\n    ...\n\n    \/\/ \u914d\u7f6eTransform\n    transformClassesWithMyTransformForDebug {\n        \/\/ \u53ef\u9009\u914d\u7f6e\u9879\uff0c\u5982\u4e0b\u6240\u793a\n        \/\/ enable false\n        \/\/ ignoreWarnings true\n        \/\/ enableTransformForJar false\n    }\n}\n\ndependencies {\n    ...\n}\n<\/code><\/pre>\n<p>\u5b8c\u6210\u4ee5\u4e0a\u6b65\u9aa4\u540e\uff0cGradle\u4f1a\u5728\u7f16\u8bd1\u671f\u95f4\u6267\u884cTransform\u5bf9Java\u5b57\u8282\u7801\u8fdb\u884c\u4fee\u6539\uff0c\u4ece\u800c\u5b9e\u73b0\u5404\u79cd\u81ea\u52a8\u751f\u6210\u4ee3\u7801\u3001\u5b57\u8282\u7801\u589e\u5f3a\u7b49\u529f\u80fd\u3002<\/p>\n<h2 class=\"wp-block-heading\">\u4e09\u3001Transform\u7f16\u5199\u6a21\u677f<\/h2>\n<h3 class=\"wp-block-heading\">1\u3001\u65e0\u589e\u91cf\u7f16\u8bd1<\/h3>\n<p>AspectJTransform.groovy\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre class=\"wp-block-preformatted\">class AspectJTransform extends Transform {\n\n    final String NAME =  \"JokerwanTransform\"\n\n    @Override\n    String getName() {\n        return NAME\n    }\n\n    @Override\n    Set&lt;QualifiedContent.ContentType&gt; getInputTypes() {\n        return TransformManager.CONTENT_CLASS\n    }\n\n    @Override\n    Set&lt;? super QualifiedContent.Scope&gt; getScopes() {\n        return TransformManager.SCOPE_FULL_PROJECT\n    }\n\n    @Override\n    boolean isIncremental() {\n        return false\n    }\n\n      @Override\n    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {\n        super.transform(transformInvocation)\n\n        \/\/ OutputProvider\u7ba1\u7406\u8f93\u51fa\u8def\u5f84\uff0c\u5982\u679c\u6d88\u8d39\u578b\u8f93\u5165\u4e3a\u7a7a\uff0c\u4f60\u4f1a\u53d1\u73b0OutputProvider == null\n        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();\n\n        transformInvocation.inputs.each { TransformInput input -&gt;\n            input.jarInputs.each { JarInput jarInput -&gt;\n                \/\/ \u5904\u7406Jar\n                processJarInput(jarInput, outputProvider)\n            }\n\n            input.directoryInputs.each { DirectoryInput directoryInput -&gt;\n                \/\/ \u5904\u7406\u6e90\u7801\u6587\u4ef6\n                processDirectoryInputs(directoryInput, outputProvider)\n            }\n        }\n    }\n\n    void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {\n        File dest = outputProvider.getContentLocation(\n                jarInput.getFile().getAbsolutePath(),\n                jarInput.getContentTypes(),\n                jarInput.getScopes(),\n                Format.JAR)\n                \n        \/\/ to do some transform\n        \n        \/\/ \u5c06\u4fee\u6539\u8fc7\u7684\u5b57\u8282\u7801copy\u5230dest\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7f16\u8bd1\u671f\u95f4\u5e72\u9884\u5b57\u8282\u7801\u7684\u76ee\u7684\u4e86        \n        FileUtils.copyFiley(jarInput.getFile(), dest)\n    }\n\n    void processDirectoryInputs(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {\n        File dest = outputProvider.getContentLocation(directoryInput.getName(),\n                directoryInput.getContentTypes(), directoryInput.getScopes(),\n                Format.DIRECTORY)\n        \/\/ \u5efa\u7acb\u6587\u4ef6\u5939        \n        FileUtils.forceMkdir(dest)\n        \n        \/\/ to do some transform\n        \n        \/\/ \u5c06\u4fee\u6539\u8fc7\u7684\u5b57\u8282\u7801copy\u5230dest\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7f16\u8bd1\u671f\u95f4\u5e72\u9884\u5b57\u8282\u7801\u7684\u76ee\u7684\u4e86        \n        FileUtils.copyDirectory(directoryInput.getFile(), dest)\n    }\n}\n<\/pre>\n<h3 class=\"wp-block-heading\">2\u3001\u6709\u589e\u91cf\u7f16\u8bd1<\/h3>\n<p>AspectJTransform.groovy\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre class=\"wp-block-preformatted\">class AspectJTransform extends Transform {\n\n    final String NAME = \"JokerWanTransform\"\n\n    @Override\n    String getName() {\n        return NAME\n    }\n\n    @Override\n    Set&lt;QualifiedContent.ContentType&gt; getInputTypes() {\n        return TransformManager.CONTENT_CLASS\n    }\n\n    @Override\n    Set&lt;? super QualifiedContent.Scope&gt; getScopes() {\n        return TransformManager.SCOPE_FULL_PROJECT\n    }\n\n    @Override\n    boolean isIncremental() {\n        return true\n    }\n\n    @Override\n    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {\n        super.transform(transformInvocation)\n\n        boolean isIncremental = transformInvocation.isIncremental()\n\n        \/\/ OutputProvider\u7ba1\u7406\u8f93\u51fa\u8def\u5f84\uff0c\u5982\u679c\u6d88\u8d39\u578b\u8f93\u5165\u4e3a\u7a7a\uff0c\u4f60\u4f1a\u53d1\u73b0OutputProvider == null\n        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()\n\n        if (!isIncremental) {\n            \/\/ \u4e0d\u9700\u8981\u589e\u91cf\u7f16\u8bd1\uff0c\u5148\u6e05\u9664\u5168\u90e8\n            outputProvider.deleteAll()\n        }\n\n        transformInvocation.getInputs().each { TransformInput input -&gt;\n            input.jarInputs.each { JarInput jarInput -&gt;\n                \/\/ \u5904\u7406Jar\n                processJarInputWithIncremental(jarInput, outputProvider, isIncremental)\n            }\n\n            input.directoryInputs.each { DirectoryInput directoryInput -&gt;\n                \/\/ \u5904\u7406\u6587\u4ef6\n                processDirectoryInputWithIncremental(directoryInput, outputProvider, isIncremental)\n            }\n        }\n    }\n\n    void processJarInputWithIncremental(JarInput jarInput, TransformOutputProvider outputProvider, boolean isIncremental) {\n        File dest = outputProvider.getContentLocation(\n                jarInput.getFile().getAbsolutePath(),\n                jarInput.getContentTypes(),\n                jarInput.getScopes(),\n                Format.JAR)\n        if (isIncremental) {\n            \/\/ \u5904\u7406\u589e\u91cf\u7f16\u8bd1\n            processJarInputWhenIncremental(jarInput, dest)\n        } else {\n            \/\/ \u4e0d\u5904\u7406\u589e\u91cf\u7f16\u8bd1\n            processJarInput(jarInput, dest)\n        }\n    }\n\n    void processJarInput(JarInput jarInput, File dest) {\n        transformJarInput(jarInput, dest)\n    }\n\n    void processJarInputWhenIncremental(JarInput jarInput, File dest) {\n        switch (jarInput.status) {\n            case Status.NOTCHANGED:\n                break\n            case Status.ADDED:\n            case Status.CHANGED:\n                \/\/ \u5904\u7406\u6709\u53d8\u5316\u7684\n                transformJarInputWhenIncremental(jarInput.getFile(), dest, jarInput.status)\n                break\n            case Status.REMOVED:\n                \/\/ \u79fb\u9664Removed\n                if (dest.exists()) {\n                    FileUtils.forceDelete(dest)\n                }\n                break\n        }\n    }\n\n    void transformJarInputWhenIncremental(JarInput jarInput, File dest, Status status) {\n        if (status == Status.CHANGED) {\n            \/\/ Changed\u7684\u72b6\u6001\u9700\u8981\u5148\u5220\u9664\u4e4b\u524d\u7684\n            if (dest.exists()) {\n                FileUtils.forceDelete(dest)\n            }\n        }\n        \/\/ \u771f\u6b63transform\u7684\u5730\u65b9\n        transformJarInput(jarInput, dest)\n    }\n\n    void transformJarInput(JarInput jarInput, File dest) {\n    \n        \/\/ to do some transform\n        \n        \/\/ \u5c06\u4fee\u6539\u8fc7\u7684\u5b57\u8282\u7801copy\u5230dest\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7f16\u8bd1\u671f\u95f4\u5e72\u9884\u5b57\u8282\u7801\u7684\u76ee\u7684\u4e86\n        FileUtils.copyFile(jarInput.getFile(), dest)\n    }\n\n    void processDirectoryInputWithIncremental(DirectoryInput directoryInput, TransformOutputProvider outputProvider, boolean isIncremental) {\n        File dest = outputProvider.getContentLocation(\n                directoryInput.getFile().getAbsolutePath(),\n                directoryInput.getContentTypes(),\n                directoryInput.getScopes(),\n                Format.DIRECTORY)\n        if (isIncremental) {\n            \/\/ \u5904\u7406\u589e\u91cf\u7f16\u8bd1\n            processDirectoryInputWhenIncremental(directoryInput, dest)\n        } else {\n            processDirectoryInput(directoryInput, dest)\n        }\n    }\n\n    void processDirectoryInputWhenIncremental(DirectoryInput directoryInput, File dest) {\n        FileUtils.forceMkdir(dest)\n        String srcDirPath = directoryInput.getFile().getAbsolutePath()\n        String destDirPath = dest.getAbsolutePath()\n        Map&lt;File, Status&gt; fileStatusMap = directoryInput.getChangedFiles()\n        fileStatusMap.each { Map.Entry&lt;File, Status&gt; entry -&gt;\n            File inputFile = entry.getKey()\n            Status status = entry.getValue()\n            String destFilePath = inputFile.getAbsolutePath().replace(srcDirPath, destDirPath)\n            File destFile = new File(destFilePath)\n            switch (status) {\n                case Status.NOTCHANGED:\n                    break\n                case Status.REMOVED:\n                    if (destFile.exists()) {\n                        FileUtils.forceDelete(destFile)\n                    }\n                    break\n                case Status.ADDED:\n                case Status.CHANGED:\n                    FileUtils.touch(destFile)\n                    transformSingleFile(inputFile, destFile, srcDirPath)\n                    break\n            }\n        }\n    }\n\n    void processDirectoryInput(DirectoryInput directoryInput, File dest) {\n        transformDirectoryInput(directoryInput, dest)\n    }\n\n    void transformDirectoryInput(DirectoryInput directoryInput, File dest) {\n    \n        \/\/ to do some transform\n        \n        \/\/ \u5c06\u4fee\u6539\u8fc7\u7684\u5b57\u8282\u7801copy\u5230dest\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7f16\u8bd1\u671f\u95f4\u5e72\u9884\u5b57\u8282\u7801\u7684\u76ee\u7684\u4e86\n        FileUtils.copyDirectory(directoryInput.getFile(), dest)\n    }\n\n    void transformSingleFile(File inputFile, File destFile, String srcDirPath) {\n        FileUtils.copyFile(inputFile, destFile)\n    }\n}\n<\/pre>\n<p><strong><em>\u5ef6\u4f38\u9605\u8bfb1\uff1a<\/em>TransformInput<\/strong><\/p>\n<p>TransformInput\u662f\u6307\u8f93\u5165\u6587\u4ef6\u7684\u4e00\u4e2a\u62bd\u8c61\uff0c\u5305\u62ec\uff1a<\/p>\n<ul>\n<li>DitectoryInput\u96c6\u5408\uff1a\u662f\u6307\u4ee5\u6e90\u7801\u7684\u65b9\u5f0f\u53c2\u4e0e\u9879\u76ee\u7f16\u8bd1\u7684\u6240\u6709\u76ee\u5f55\u7ed3\u6784\u53ca\u5176\u76ee\u5f55\u4e0b\u7684\u6e90\u7801\u6587\u4ef6<\/li>\n<li>JarInput\u96c6\u5408\uff1a\u662f\u6307\u4ee5jar\u5305\u65b9\u5f0f\u53c2\u4e0e\u9879\u76ee\u7f16\u8bd1\u7684\u6240\u6709\u672c\u5730jar\u5305\u548c\u8fdc\u7a0bjar\u5305\uff08\u6b64\u5904\u7684jar\u5305\u5305\u62ecaar\uff09<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"Gradle Transform\u662fAndroid\u5b98\u65b9\u63d0\u4f9b\u7ed9\u5f00\u53d1\u8005\u5728\u9879\u76ee\u6784\u5efa\u9636\u6bb5\uff08.class -&gt; .d [&hellip;]","protected":false},"author":1,"featured_media":32331,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[37],"tags":[119],"acf":[],"_links":{"self":[{"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/posts\/32330"}],"collection":[{"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/comments?post=32330"}],"version-history":[{"count":0,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/posts\/32330\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/media\/32331"}],"wp:attachment":[{"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/media?parent=32330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/categories?post=32330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/docs.pingcode.com\/wp-json\/wp\/v2\/tags?post=32330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}