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

Posted

技术标签:

【中文标题】选择 Android 库的构建变体的 Gradle 脚本【英文标题】:Gradle script which selects a build variant of the Android library 【发布时间】:2019-07-18 23:21:25 【问题描述】:

我正在使用 Eclipse 并处理 android 项目。由于多种原因,我无法使用 Android Studio。不幸的是,Eclipse 不能处理 AAR 档案。经过长期的努力,我们决定让 Eclipse 项目成为 NON-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("combineacces-s-rules", "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'
    
  

我知道这不是 gradle 编程的顶峰,但它确实有效。 这个脚本的主要问题是它要求所有依赖项都是“编译”类型,但对于 Android,这已经过时了。新的依赖类型是'api'和'implementation'。 现在 'compile' 已被弃用,但恐怕它会完全消失。

有一个简单而丑陋的解决方案:使用 'eclipseOnly' 类型的依赖项复制所有非标准依赖项。上面的脚本中使用了此解决方案。这可行,但真的很难看,因为我们必须在所有项目中修改 gradle 脚本。但我的目标不是触及所有项目。现在脚本包含在一个单独的文件“eclipseHelper.gradle”中,并包含在根项目中,如下所示:

subprojects
   apply from: "$rootProject.projectDir/eclipseHelper.gradle"

我想要实现的是将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 类路径('plusConfigurations')中:

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
          
      
    

我们的项目中有一些 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中

提前致谢, 安德烈

【问题讨论】:

【参考方案1】:

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

https://github.com/greensopinion/gradle-android-eclipse

https://github.com/GinVavilon/gradle-android-eclipse

Google 在 android.tools.build 3.4 中实现了数据绑定和 androidx,我正在尝试根据这些条款自定义我的项目。

【讨论】:

以上是关于选择 Android 库的构建变体的 Gradle 脚本的主要内容,如果未能解决你的问题,请参考以下文章

Android 库 - 使用 Gradle 将多个变体发布到本地 Maven 存储库

Android - 仅在发布版本变体上执行 Gradle 任务

如何在 gradle kts 中排除(忽略)android 构建变体

Android知识要点整理(19)----Gradle 之构建变体

Android知识要点整理(19)----Gradle 之构建变体

Android Studio gradle 风味维度构建变体无法正常工作