Gradle脚本,用于选择Android库的构建变体

Gradle脚本,用于选择Android库的构建变体,android,eclipse,gradle,Android,Eclipse,Gradle,我正在使用Eclipse和Android项目。我不能使用Android Studio有很多原因。不幸的是,Eclipse不能使用AAR归档。经过长期的努力,我们决定让Eclipse项目成为非GRADLE项目(从所有Eclipse项目中消除GRADLE性质),并用一个特殊的GRADLE脚本准备一个依赖项列表。 为了能够使用Android,我编写了以下gradle脚本,它执行以下操作: 搜索所有项目中的所有依赖项 将依赖项从gradle缓存复制到一个特殊的Eclipse项目“jars from gr

我正在使用Eclipse和Android项目。我不能使用Android Studio有很多原因。不幸的是,Eclipse不能使用AAR归档。经过长期的努力,我们决定让Eclipse项目成为非GRADLE项目(从所有Eclipse项目中消除GRADLE性质),并用一个特殊的GRADLE脚本准备一个依赖项列表。 为了能够使用Android,我编写了以下gradle脚本,它执行以下操作:

  • 搜索所有项目中的所有依赖项
  • 将依赖项从gradle缓存复制到一个特殊的Eclipse项目“jars from gradle”

  • 为所有项目编写“.classpath”,以便只使用找到的库

  • 下面是gradle脚本:

    apply plugin: "eclipse"
    
    configurations {
        eclipseOnly {
            description = 'this is used only to build eclipse classpath'
        }
    }
    
    afterEvaluate{
    
      project.tasks['eclipseProject'].dependsOn(project.tasks['cleanEclipseProject'])
      project.tasks['eclipseClasspath'].dependsOn(project.tasks['cleanEclipseClasspath'])
    
      eclipse{
    
        File f = rootProject.ext.find("explodedAarsDir");
        if(f == null) {
            f = new File("${rootProject.projectDir}/jars-from-gradle/explodedAars/");
            rootProject.ext.set("explodedAarsDir", f)
            f.mkdirs();
        }
        f = rootProject.ext.find("globalDependenciesRepo");
        if(f == null) {
            f = new File("${rootProject.projectDir}/jars-from-gradle/libs");
            rootProject.ext.set("globalDependenciesRepo", f)
            f.mkdirs();
        }
        org.gradle.plugins.ide.eclipse.model.internal.FileReferenceFactory frf = rootProject.ext.find("fileReferenceFactory");
        if(frf == null) {
            frf = new org.gradle.plugins.ide.eclipse.model.internal.FileReferenceFactory();
            rootProject.ext.set("fileReferenceFactory", frf)
        }
    
        if(!rootProject.ext.has("eclipseFileMapping")) {
            rootProject.ext.set("eclipseFileMapping", new HashMap<File, File>())
        }
        Map<File, File> eclipseFileMapping = rootProject.ext.get("eclipseFileMapping")
        eclipseFileMapping.put(new File("bin/main"), new File("bin"))
        eclipseFileMapping.put(new File("bin/test"), new File("bin"))
        eclipseFileMapping.put(new File("${buildDir}/classes/java/main"), new File("${projectDir.parentFile}/${project.name}/bin"))
        eclipseFileMapping.put(new File("${buildDir}/classes/java/test"), new File("${projectDir.parentFile}/${project.name}/bin"))
        eclipseFileMapping.put(new File("${buildDir}/resources/main"), new File("${projectDir.parentFile}/${project.name}/bin"))
        eclipseFileMapping.put(new File("${buildDir}/resources/test"), new File("${projectDir.parentFile}/${project.name}/bin"))
    
        configurations {
          eclipsePlusConfig {
            description = "files to include into eclipse classpath"
            transitive = false
          }
          eclipseMinusConfig {
            description = "files to exclude from eclipse classpath"
            transitive = false
          }
        }
    
        project{
          setupEclipseProject()
        }
    
        classpath{
          defaultOutputDir = new File("${projectDir}/bin")
          plusConfigurations += [project.configurations.eclipseOnly]
          if(project.extensions.findByName("android") != null) {
              plusConfigurations += [project.configurations.compile]
              plusConfigurations += [project.configurations.runtime]
              project.eclipse.project{
                  natures 'org.eclipse.andmore.AndroidNature'
                  buildCommands.clear()
                  buildCommand "org.eclipse.andmore.ResourceManagerBuilder"
                  buildCommand "org.eclipse.andmore.PreCompilerBuilder"
                  buildCommand "org.eclipse.jdt.core.javabuilder"
                  buildCommand "org.eclipse.andmore.ApkBuilder"
                  containers 'org.eclipse.andmore.DEPENDENCIES', 'org.eclipse.andmore.LIBRARIES', 'org.eclipse.andmore.ANDROID_FRAMEWORK'
              }
          } else {
              plusConfigurations += [project.configurations.compile]
              plusConfigurations += [project.configurations.runtime]
          }
    
          file {
            beforeMerged { classpath ->
               eclipse.classpath.sourceSets.each {
                   println "    source set "+ it.getName()
               }
               eclipse.classpath.plusConfigurations.each{ processConf(it, "    ", "plus conf: ") }
               eclipse.classpath.minusConfigurations.each{ processConf(it, "    ", "minus conf: ") }
    
               eclipse.classpath.plusConfigurations.add(project.configurations['eclipsePlusConfig'])
               eclipse.classpath.minusConfigurations.add(project.configurations['eclipseMinusConfig'])
            }
            whenMerged { classpath ->
               List<org.gradle.plugins.ide.eclipse.model.ClasspathEntry> replacementEclipseClasspath = createEclipseReplacementClasspath(classpath);
               classpath.setEntries(replacementEclipseClasspath)
            }
            withXml { n ->
                Set<File> existingPaths = new HashSet<File>();
                def rootNode = n.asNode();
                for(int nodeIndex = 0; nodeIndex<rootNode.children().size(); nodeIndex++) {
                   def chld = rootNode.children().get(nodeIndex);
                   if("classpathentry".equals(chld.name())) {
                      removeGradleAttributes(chld);
                      chld.attributes().remove("output");
                      String kind = chld.attributes().get("kind");
                      for(Map.Entry entry : chld.attributes().entrySet()) {
                          if("path".equals(entry.key) || "sourcepath".equals(entry.key)) {
                            f = new File(entry.value);
                            if(f.toPath().isAbsolute()) {
                                String relativeName = rootProject.projectDir.toPath().relativize(f.toPath()).toString();
                                entry.value = "/"+ relativeName.replace('\\', '/');
                            }
                            if("path".equals(entry.key) && existingPaths.contains(f)) {
                                rootNode.children().remove(nodeIndex--);
                                break;
                            }
                            if(entry.value.startsWith("/")) {
                                if("src".equals(kind)) {
                                    chld.attributes().put("combineaccessrules", "false");
                                }
                            }
                            existingPaths.add(f);
                          }
                      }
                      if("lib".equals(kind)) {
                          chld.attributes().put("exported", "true");
                      }
                   }
                }
            }
          }
        }
    
        task prepareEclipse{
          doFirst{
            mkDirIfNotExists(new File("${projectDir}/src/main/java"))
            mkDirIfNotExists(new File("${projectDir}/src/main/resources"))
            mkDirIfNotExists(new File("${projectDir}/src/test/java"))
            mkDirIfNotExists(new File("${projectDir}/src/test/resources"))
          }
        }
    
        tasks['eclipseClasspath'].dependsOn(prepareEclipse)
      }
    }
    
    List<org.gradle.plugins.ide.eclipse.model.ClasspathEntry> createEclipseReplacementClasspath(org.gradle.plugins.ide.eclipse.model.Classpath eclipseClasspath) {
        Map<String, org.gradle.plugins.ide.eclipse.model.ClasspathEntry> replacementEclipseClasspathAsMap = new HashMap<String, org.gradle.plugins.ide.eclipse.model.ClasspathEntry>(); 
        eclipseClasspath.entries.each{ clspthentry ->
            dumpClassPathEntry(clspthentry)
            if (clspthentry instanceof org.gradle.plugins.ide.eclipse.model.Library) {
                org.gradle.plugins.ide.eclipse.model.Library library = clspthentry;
                String moduleId = library.getModuleVersion().toString();
                String groupId = null;
                String artifactId = null;
                String artifactVersion = null;
                int index = moduleId.indexOf(":");
                if(index >= 0) {
                    groupId = moduleId.substring(0, index);
                    String tmp = moduleId.substring(++index);
                    index = tmp.indexOf(":")
                    if(index >= 0) {
                        artifactId = tmp.substring(0, index);
                        artifactVersion = tmp.substring(++index);
                    }
                }
                moduleId = moduleId.replaceAll(":", "-");
                println("    classpath entry found: moduleId="+ moduleId);
                if (library.getPath().endsWith(".aar")) {
                    explodeAarJarFiles(moduleId, groupId, artifactId, artifactVersion, library, replacementEclipseClasspathAsMap);
                } else {
                    copyLibraryFromGradleCache(moduleId, groupId, artifactId, artifactVersion, library, replacementEclipseClasspathAsMap)
                }
            } else {
                replacementEclipseClasspathAsMap.put(clspthentry.kind+ "_"+ clspthentry.path, clspthentry);
            }
        }
        List<org.gradle.plugins.ide.eclipse.model.ClasspathEntry> replacementEclipseClasspath = new ArrayList<org.gradle.plugins.ide.eclipse.model.ClasspathEntry>();
        replacementEclipseClasspath.addAll(replacementEclipseClasspathAsMap.values());
        List<String> KINDS = new ArrayList<String>();
        KINDS.add('src');
        KINDS.add('con');
        KINDS.add('lib');
        KINDS.add('output');
        Collections.sort(replacementEclipseClasspath, new Comparator<org.gradle.plugins.ide.eclipse.model.ClasspathEntry>() {
    
            private int detectKindIndex(String entryKind) {
                for(int i = 0; i<KINDS.size(); i++) {
                    if(KINDS[i].equals(entryKind)) {
                        return i;
                    }
                }
                return KINDS.size();
            }
    
            public int compare(org.gradle.plugins.ide.eclipse.model.ClasspathEntry entry1, org.gradle.plugins.ide.eclipse.model.ClasspathEntry entry2) {
                int kindDiff = detectKindIndex(entry1.getKind()) - detectKindIndex(entry2.getKind());
                if(kindDiff != 0) {
                    return kindDiff;
                }
                if(entry1 instanceof org.gradle.plugins.ide.eclipse.model.ProjectDependency) {
                    if(!(entry2 instanceof org.gradle.plugins.ide.eclipse.model.ProjectDependency)) {
                        return 11;
                    }
                } else if(entry2 instanceof org.gradle.plugins.ide.eclipse.model.ProjectDependency) {
                    return -1;
                }
                return entry1.path.compareTo(entry2.path);
            }
        });
        return replacementEclipseClasspath;
    }
    
    void copyLibraryFromGradleCache(String moduleId, String groupId, String artifactId, String artifactVersion, org.gradle.plugins.ide.eclipse.model.Library library, Map<String, org.gradle.plugins.ide.eclipse.model.Library> replacementEclipseClasspathAsMap) {
        String artifactIdAndVersion = artifactId + "-"+ artifactVersion;
        int fileSuffixIndex = -1;
        if(artifactId != null) {
            fileSuffixIndex = library.getPath().lastIndexOf(artifactIdAndVersion);
        }
        if(fileSuffixIndex >= 0) {
            fileSuffixIndex += artifactIdAndVersion.length();
        } else {
            fileSuffixIndex = library.getPath().lastIndexOf(".");
        }
        if(moduleId == null || fileSuffixIndex <= 0) {
            println("      non-movable library found: "+ library.getPath())
            replacementEclipseClasspathAsMap.put(moduleId, library);
        } else {
            File targetGroupFolder = null; 
            if (groupId==null || groupId.trim().length()==0) {
                targetGroupFolder = new File(globalDependenciesRepo.getAbsolutePath());
            } else {
                targetGroupFolder = new File(globalDependenciesRepo.getAbsolutePath(), groupId);
                if(!targetGroupFolder.exists()){
                    targetGroupFolder.mkdirs()
                }
            }
            String fileSuffix = library.getPath().substring(fileSuffixIndex);
            String targetFileName = artifactIdAndVersion;
            println("      target filename: "+ targetGroupFolder+ " -> "+ targetFileName)
            java.nio.file.Path targetFile = java.nio.file.Paths.get(targetGroupFolder.getAbsolutePath(), targetFileName + fileSuffix);
            java.nio.file.Path sourceFile = java.nio.file.Paths.get(library.getPath());
            if(sourceFile.toFile().exists() && !sourceFile.toFile().isDirectory()) {
                java.nio.file.Files.copy(sourceFile, targetFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
                library.setPath(targetFile.toString());
            }
            if(library.getSourcePath() != null) {
                java.nio.file.Path sourceSourceFile = java.nio.file.Paths.get(library.getSourcePath().getPath());
                if(sourceFile.toFile().exists() && !sourceFile.toFile().isDirectory()) {
                    java.nio.file.Path sourceTargetFile = java.nio.file.Paths.get(targetGroupFolder.getAbsolutePath(), targetFileName + "_source"+ fileSuffix);
                    println("      copying source file: "+ sourceSourceFile + " into "+ sourceTargetFile);
                    java.nio.file.Files.copy(sourceSourceFile, sourceTargetFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
                    //println( "          TROLOLO "+ rootProject.projectDir.toPath().relativize(sourceTargetFile) );
                    library.setSourcePath(fileReferenceFactory.fromFile(sourceTargetFile.toFile()));
                }
            }
            replacementEclipseClasspathAsMap.put(moduleId + "_"+ targetFileName + fileSuffix, library);
        }
    }
    
    void explodeAarJarFiles(String moduleId, String groupId, String artifactId, String artifactVersion, org.gradle.plugins.ide.eclipse.model.Library aarLibrary, Map<String, org.gradle.plugins.ide.eclipse.model.Library> replacementEclipseClasspathAsMap) {
        File aarFile = new File(aarLibrary.getPath());
        println("    exploding AAR dependency: "+ aarFile.getAbsolutePath());
        File targetFolder = new File(explodedAarsDir, moduleId);
        println("      target folder: "+ targetFolder.getAbsolutePath());
        if (targetFolder.exists()) {
            println("        target folder exists. deleting ");
            project.delete(files(targetFolder))
        }
        if (!targetFolder.mkdirs()) {
            throw new RuntimeException("Cannot create folder: ${targetFolder.getAbsolutePath()}");
        }
        try {
            if(aarLibrary.getSourcePath() != null) {
                java.nio.file.Path sourceSourceFile = java.nio.file.Paths.get(aarLibrary.getSourcePath().getPath());
                if(sourceSourceFile.toFile().exists() && !sourceSourceFile.toFile().isDirectory()) {
                    String sourceFileExt = sourceSourceFile.toString();
                    int extensionIndex = sourceFileExt.lastIndexOf(".");
                    if(extensionIndex >= 0) {
                        sourceFileExt = sourceFileExt.substring(extensionIndex);
                    } else {
                        sourceFileExt = ".jar";
                    }
                    java.nio.file.Path sourceTargetFile = java.nio.file.Paths.get(targetFolder.toString(), moduleId+ "_source"+ sourceFileExt);
                    println("      copying source file: "+ sourceSourceFile + " into "+ sourceTargetFile);
                    java.nio.file.Files.copy(sourceSourceFile, sourceTargetFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
                    aarLibrary.setSourcePath(fileReferenceFactory.fromFile(sourceTargetFile.toFile()));
                }
            }
            java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(aarFile);
            zipFile.entries().each{ fileInsideAar -> 
                if (fileInsideAar.getName().endsWith(".jar")) {
                    String targetName = moduleId+ "_"+ fileInsideAar.getName().replace('/', '_').replace('\\', '_');
                    println("          jar inside aar: "+ fileInsideAar.getName());
                    println("          copying to: "+ targetName);
                    File targetFile = new File(targetFolder, targetName);
                    int index = 1;
                    while (targetFile.exists()) {
                        targetFile = new File(targetFolder, format("${targetName}_${++index}"));
                    }
                    try {
                        InputStream inputStream = zipFile.getInputStream(fileInsideAar);
                        java.nio.file.Files.copy(inputStream, targetFile.toPath());
                        org.gradle.plugins.ide.eclipse.model.Library library = new org.gradle.plugins.ide.eclipse.model.Library(fileReferenceFactory.fromFile(targetFile));
                        library.setSourcePath(aarLibrary.getSourcePath())
                        replacementEclipseClasspathAsMap.put(targetFile.getName(), library);
                    } catch (IOException e) {
                        throw new RuntimeException(
                                "Cannot write entry to file: ${e.getMessage()}: ${targetFile.getAbsolutePath()}", e);
                    }
                }
            };
        } catch (IOException e) {
            throw new RuntimeException(
                   "Cannot explode aar: ${e.getMessage()}: ${aarFile.getAbsolutePath()}", e);
        }
    }
    
    void removeGradleAttributes(Node node) {
        for(int i = 0; i<node.children().size(); i++) {
            Node attrs = node.children().get(i);
            if("attributes".equals(attrs.name())) {
                for(int j = 0; j<attrs.children().size(); j++) {
                    Node attr = attrs.children().get(j);
                    boolean isGradleAttr = false;
                    for(Map.Entry entry : attr.attributes().entrySet()) {
                        if(entry.key.toLowerCase().contains("gradle") || entry.value.toLowerCase().contains("gradle")) {
                            isGradleAttr = true;
                        }
                    }
                    if(isGradleAttr) {
                        attrs.remove(attr);
                        j--;
                    }
                }
                if(attrs.children().size()==0) {
                    node.remove(attrs);
                }
            }
        }
    }
    
    void mkDirIfNotExists(File file) {
        if(!file.exists()) {
            file.mkdir()
        }
    }
    
    void processConf(org.gradle.api.internal.artifacts.configurations.DefaultConfiguration cnf, String startIndent, String prefix) {
        println(startIndent + prefix + cnf.name+ ", path: "+ cnf.path)
        StringBuilder indent = new StringBuilder();
        for(int i = 0; i<startIndent.length(); i++) {
            indent.append(" ");
        }
        indent.append("  ");
    
        cnf.dependencies.each{ dep ->
            maskDependencyIfNeeded(indent.toString(), dep)
        }
        cnf.allDependencies.each{ dep ->
            maskDependencyIfNeeded(indent.toString(), dep)
        }
    }
    
    void maskDependencyIfNeeded(String indent, org.gradle.api.internal.artifacts.dependencies.AbstractDependency dep) {
        if(dep instanceof org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency) {
            boolean needToExcludeDep = false;
            Set<File> maskedDepFiles = new HashSet<File>();
            dep.files.each{ depFile ->
                File f = findMaskedFile(depFile, null, true);
                if(f != null) {
                  maskedDepFiles.add(f)
                  needToExcludeDep = true;
                  println(indent.toString()+ "  mask dep file "+ depFile+ " -> "+ f)
                }
            }
            if(needToExcludeDep) {
                project.configurations['eclipseMinusConfig'].dependencies.add(dep)
                if(!maskedDepFiles.isEmpty()) {
                    org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency newDep = new org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency(dep.targetComponentId, project.files(maskedDepFiles))
                    project.configurations['eclipsePlusConfig'].dependencies.add(newDep)
                }
            }
        }
    }
    
    File findMaskedFile(File f, String postfix, boolean initiallyUnmasked) {
      if(f != null) {
          for(Map.Entry<File, File> efm : eclipseFileMapping) {
               boolean masked = false;
               if(initiallyUnmasked) {
                   if(efm.key.equals(f)) {
                       masked = true;
                   }
               } else {
                   if(efm.value.equals(f)) {
                       masked = true;
                   }
               }
               if(masked) {
                   if(postfix != null) {
                       return new File(efm.value, postfix)
                   } else {
                       return efm.value;
                   }
               }
          }
          return findMaskedFile(f.parentFile, postfix==null ? f.name : f.name + File.pathSeparator+ postfix, initiallyUnmasked);
      }
      return null;
    }
    
    void dumpClassPathEntry(org.gradle.plugins.ide.eclipse.model.ClasspathEntry clspthentry) {
        if("output".equals(clspthentry.kind)) {
            // the clspthentry is instance of org.gradle.plugins.ide.eclipse.model.Output
            println("  output: "+ clspthentry.path)
        } else if("src".equals(clspthentry.kind)) {
            if(clspthentry instanceof org.gradle.plugins.ide.eclipse.model.ProjectDependency) {
                 // the clspthentry is instance of org.gradle.plugins.ide.eclipse.model.ProjectDependency
                 println("  project: exported="+ clspthentry.exported+ "; path="+ clspthentry.path)
            } else {
                 // the clspthentry is instance of org.gradle.plugins.ide.eclipse.model.SourceFolder
                 println("  src folder: "+ clspthentry.name+ " ("+ clspthentry.dir+ ") -> output: "+ clspthentry.output)
                 if(clspthentry.excludes != null && clspthentry.excludes.size()>0) {
                     println("    excludes:")
                     clspthentry.excludes.each{ excl ->
                         println("      "+ excl)
                     }
                 }
                 if(clspthentry.includes != null && clspthentry.includes.size()>0) {
                     println("    includes:")
                     clspthentry.includes.each{ incl ->
                         println("      "+ incl)
                     }
                 }
             }
        } else if("con".equals(clspthentry.kind)) {
            //the clspthentry is instance of org.gradle.plugins.ide.eclipse.model.Container
            println("  con: exported="+ clspthentry.exported+ "; path="+ clspthentry.path)
        } else if("lib".equals(clspthentry.kind)) {
            //the clspthentry is instance of org.gradle.plugins.ide.eclipse.model.Library
            println("  lib: file="+ clspthentry.library.path)
        } else {
            println("  UNKNOWN "+ clspthentry.kind+ " -> "+ clspthentry.getClass().getName())
        }
    }
    
    // Gradle adds all custom sourceSets to eclipse's linkedResources. We do not need them in eclipse project, but we do not understand how and when the source is linked.
    // So, JUST HACK IT: clear the linked resourcces after evaluating the project!
    // But gradle is such a misterious thing! just clearing does not help. We need to put something there
    // so lets put the existing linked resource, but with relative path :(
    void setupEclipseProject() {
      if(project.name.contains("-android")) {
        project.eclipse.project{
    
            linkedResource name: 'AndroidManifest.xml', type: '1', location: 'PROJECT_LOC/src/main/AndroidManifest.xml'
            linkedResource name: 'android-java', type: '2', location: 'PARENT-1-PROJECT_LOC/assets/build/android/java'
            linkedResource name: 'res', type: '2', location: 'PROJECT_LOC/src/main/res'
        }
      }
    }
    
    我试图实现的是将android特定类型的依赖项添加到Eclipse中。首先,我从依赖项中排除了所有“发布”变体:

    def androidExtension = project.extensions.findByName("android")
      if (androidExtension != null) {
          android.variantFilter { variant ->
              def names = variant.flavors*.name
              def buildTypeName = variant.buildType.name
              // if buildtype is required for filtering use
              // the above field
              if (variant.name.contains("elease")) {
                  variant.ignore = true
              }
          }
       }
    
    其次,我尝试将Android变体配置添加到Eclipse类路径(“plusConfiguration”):

    我们的项目中有一些Android库,这些库是以不同的风格构建的。所以我得到了以下例外:

    org.gradle.internal.component.AmbiguousVariantSelectionException: More than one variant of project :proj1-android matches the consumer a
    ttributes:
      - Configuration ':proj1-android:debugApiElements' variant android-aidl:
          - Found artifactType 'android-aidl' but wasn't required.
          - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
          - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
          - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
          - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
      - ...
      - ...
      - Configuration ':proj1-android:debugApiElements' variant jar:
          - Found artifactType 'jar' but wasn't required.
          - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
          - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
          - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
          - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    
    有人能帮我找出解决办法吗

  • 从集合中选择任何配置(“调试”)
  • 完全跳过子项目的所有配置,并将其作为项目依赖项包含到.classpath中
  • 提前感谢,, 安德烈

    我也有同样的问题。 找到了几个解决方案,但不是最终的

    谷歌已经在android.tools.build 3.4中实现了数据绑定和androidx,我正试图根据这些条款定制我的项目

    def androidExtension = project.extensions.findByName("android")
        if (androidExtension != null) {
          boolean applicationBuild = rootProject.hasProperty("applicationBuild")
          if (androidExtension.getClass().getName().contains("LibraryExtension")){
              android.libraryVariants.all { variant ->
                  eclipse.classpath.plusConfigurations += variant.compileConfiguration
                  eclipse.classpath.plusConfigurations += variant.runtimeConfiguration
              }
          } else {
              android.applicationVariants.all { variant ->
                  eclipse.classpath.plusConfigurations += variant.compileConfiguration
                  eclipse.classpath.plusConfigurations += variant.runtimeConfiguration
              }
          }
        }
    
    org.gradle.internal.component.AmbiguousVariantSelectionException: More than one variant of project :proj1-android matches the consumer a
    ttributes:
      - Configuration ':proj1-android:debugApiElements' variant android-aidl:
          - Found artifactType 'android-aidl' but wasn't required.
          - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
          - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
          - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
          - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
      - ...
      - ...
      - Configuration ':proj1-android:debugApiElements' variant jar:
          - Found artifactType 'jar' but wasn't required.
          - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
          - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
          - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
          - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.