0

Aus besonderen Gründen für meine App möchte ich zwei verschiedene Versionen einer Google Play Services-Bibliothek in zwei verschiedenen productFlavors verwenden. Aber gradle gibt mir die bekannte Fehlermeldung:Wie werden zwei verschiedene Versionen von GooglePlayServices-Bibliotheken in zwei verschiedenen Produktvarianten verwendet?

Bitte reparieren Versionskonflikt entweder durch die Version des Google-Services-Plug-Aktualisierung (Informationen über die neueste Version ist verfügbar unter https://bintray.com/android/android-tools/com.google.gms.google-services/) oder die Aktualisierung der Version von com.google .android.gms bis 10.2.4.

Normalerweise würde ich dies beheben, indem Sie konsistente Versionen von GPS-Bibliotheken verwenden. Aber in diesem Fall dachte ich, die Inkonsistenz wäre in Ordnung, denn ich kompiliere die App in zwei verschiedene Geschmacksrichtungen. Es ist nicht ganz Arbeitens:

App build.gradle

apply plugin: 'com.android.application' 

android { 
    compileSdkVersion 25 
    buildToolsVersion '25.0.2' 

    defaultConfig { 
     applicationId "com.albertcbraun.googleplayservicesversionconflicttestcase" 
     minSdkVersion 16 
     targetSdkVersion 25 
     versionCode 1 
     versionName "1.0" 
     testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
    productFlavors { 
     flavor1 { 
      applicationId 'com.albertcbraun.flavor1' 
     } 

     flavor2 { 
      applicationId 'com.albertcbraun.flavor2' 
     } 
    } 
} 


dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 
    compile 'com.android.support:appcompat-v7:25.3.1' 
    compile 'com.android.support.constraint:constraint-layout:1.0.2' 
    testCompile 'junit:junit:4.12' 

    // these are the problematic lines. GPS versions differ: 
    flavor1Compile 'com.google.android.gms:play-services-identity:10.2.4' 
    flavor2Compile 'com.google.android.gms:play-services-identity:9.6.1' 
} 

apply plugin: 'com.google.gms.google-services' 

Projekt build.gradle

buildscript { 
    repositories { 
     jcenter() 
    } 
    dependencies { 
     classpath 'com.android.tools.build:gradle:2.3.1' 
     classpath 'com.google.gms:google-services:3.0.0' 
    } 
} 

allprojects { 
    repositories { 
     jcenter() 
    } 
} 

task clean(type: Delete) { 
    delete rootProject.buildDir 
} 

Gradle Version: 3.3

Android Studio Version: 2.3.1

+0

https://stackoverflow.com/questions/18196974/how-to-define-different-dependencies-for-different-product-flavors – akash93

Antwort

0

======== ======== REVISED 2017.04.05

Dies ist experimentell, aber FWIW, ich war in der Lage zu hack in "Flavour Awareness" auf Version 3.0.0 von GoogleServicesTask.java und GoogleServicesPlugin.groovy (die das GoogleServicesPlugin für grandle ausmachen).

Das ursprüngliche Plugin leitet die GPS-Bibliothek-Version durch Prüfung der 'compile' Anweisungen in Ihrem build.gradle (in einer Methode namens findTargetVersion). Aber ich habe das geändert. Mit diesem Hack geben Sie diese Versionen pro Flavor in den Erweiterungseigenschaften vor.

Dieser Ansatz ist weder gut getestet noch produktionstauglich, aber es ist in der Lage, zwei verschiedene Versionen der GPS-Bibliotheken mit zwei verschiedenen Produktaromen zu kompilieren. Beachten Sie außerdem: Android Studio beklagt sich ein wenig über die Tatsache, dass Sie zwei verschiedene Versionen haben (rote Unterstreichung), aber AS sollte Ihnen weiterhin erlauben, einen Ihrer Geschmacksrichtungen in Build-Varianten auszuwählen und tatsächlich einen Build auszuführen. (Zumindest hat es für mich.)

Zuerst fügen Sie diese beiden Verlängerungswerte (oder was auch immer Versionen, die Sie verwenden möchten) in der gleichen build.gradle, irgendwo sinnvoll:

ext.flavor1GPSVersion = "10.2.1" 
ext.flavor2GPSVersion = "10.2.4" 

Zweitens Kommentar aus oder entfernen Sie diese Anwendungszeile aus dem Build Ihres App-Moduls.gradle:

apply plugin: GoogleServicesPlugin 

Schließlich einfügen, direkt die folgende modifizierte Versionen des GoogleServicesTask.java und GoogleServicesPlugin.groovy in den Boden dieser build.gradle-Datei (und erinnere mich an die neue ‚anwenden Plugin‘ Zeile am unteren Rand schließen):

// ************************************************************// 
// ********** Multi Flavor Google Services Plugin *************// 
// ************************************************************// 

import org.gradle.api.tasks.Optional; 

import com.google.common.base.Charsets; 
import com.google.common.base.Strings; 
import com.google.common.io.Files; 
import com.google.gson.JsonArray; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonObject; 
import com.google.gson.JsonParser; 
import com.google.gson.JsonPrimitive; 


class MultiFlavorGoogleServicesPlugin implements Plugin<Project> { 

    public final static String JSON_FILE_NAME = 'google-services.json' 

    public final static String MODULE_GROUP = "com.google.android.gms" 
    public final static String MODULE_GROUP_FIREBASE = "com.google.firebase" 
    public final static String MODULE_CORE = "firebase-core" 
    public final static String MINIMUM_VERSION = "9.0.0" 

    private static final String TAG = "GoogleServicesPlugin"; 

    @Override 
    void apply(Project project) { 
     if (project.plugins.hasPlugin("android") || 
       project.plugins.hasPlugin("com.android.application")) { 
      // this is a bit fragile but since this is internal usage this is ok 
      // (another plugin could declare itself to be 'android') 
      for (def flavor : project.android.productFlavors) { 
       addDependency(project, flavor.name) 
      } 
      setupPlugin(project, false) 
      return 
     } 
     if (project.plugins.hasPlugin("android-library") || 
       project.plugins.hasPlugin("com.android.library")) { 
      // this is a bit fragile but since this is internal usage this is ok 
      // (another plugin could declare itself to be 'android-library') 
      for (def flavor : project.android.productFlavors) { 
       addDependency(project, flavor.name) 
      } 
      setupPlugin(project, true) 
      return 
     } 
     // If the google-service plugin is applied before any android plugin. 
     // We should warn that google service plugin should be applied at 
     // the bottom of build file. 
     showWarningForPluginLocation(project) 

     // Setup google-services plugin after android plugin is applied. 
     project.plugins.withId("android", { 
      setupPlugin(project, false) 
     }) 
     project.plugins.withId("android-library", { 
      setupPlugin(project, true) 
     }) 

     // Add dependencies after the build file is evaluate and hopefully it 
     // can be execute before android plugin process the dependencies. 
     for (def flavor : project.android.productFlavors) { 
      project.afterEvaluate({ 
       addDependency(project, flavor.name) 
      }) 
     } 
    } 

    private static void showWarningForPluginLocation(Project project) { 
     project.getLogger().warn(
       "please apply google-services plugin at the bottom of the build file.") 
    } 

    private static boolean checkMinimumVersion(Project project, String flavorName) { 
     String[] subTargetVersions = findTargetVersion(project, flavorName).split("\\.") //targetVersion.split("\\.") 
     String[] subMinimumVersions = MINIMUM_VERSION.split("\\.") 
     for (int i = 0; i < subTargetVersions.length && i < subMinimumVersions.length; i++) { 
      Integer subTargetVersion = Integer.valueOf(subTargetVersions[i]) 
      Integer subMinimumVersion = Integer.valueOf(subMinimumVersions[i]) 
      if (subTargetVersion > subMinimumVersion) { 
       return true; 
      } else if (subTargetVersion < subMinimumVersion) { 
       return false; 
      } 
     } 
     return subTargetVersions.length >= subMinimumVersions.length; 
    } 

    private void addDependency(Project project, String flavorName) { 
     //targetVersion = findTargetVersion(project).split("-")[0] 
     if (checkMinimumVersion(project, flavorName)) { 
      // If the target version is not lower than the minimum version 
      project.dependencies.add('compile', MODULE_GROUP_FIREBASE + ':' + MODULE_CORE + ':' + findTargetVersion(project, flavorName).split("-")[0]) 
     } else { 
      throw new GradleException("Version: " + targetVersion + " is lower than the minimum version (" + 
        MINIMUM_VERSION + ") required for google-services plugin.") 
     } 
    } 

    private static String findTargetVersion(Project project, String flavorName) { 
     return project.ext[flavorName + "GPSVersion"]; 
    } 

    private void setupPlugin(Project project, boolean isLibrary) { 
     if (isLibrary) { 
      project.android.libraryVariants.all { variant -> 
       handleVariant(project, variant) 
      } 
     } else { 
      project.android.applicationVariants.all { variant -> 
       handleVariant(project, variant) 
      } 
     } 
    } 

    private static void handleVariant(Project project, 
             def variant) { 

     File quickstartFile = null 

     String variantName = "$variant.dirName"; 
     String[] variantTokens = variantName.split('/') 

     List<String> fileLocation = new ArrayList<>() 

     FlavorAwareGoogleServicesTask task = project.tasks 
       .create("process${variant.name.capitalize()}GoogleServices", 
       FlavorAwareGoogleServicesTask) 

     if (variantTokens.length == 2) { 
      // If flavor and buildType are found. 
      String flavorName = variantTokens[0] 
      String buildType = variantTokens[1] 
      fileLocation.add('src/' + flavorName + '/' + buildType) 
      fileLocation.add('src/' + buildType + '/' + flavorName) 
      fileLocation.add('src/' + flavorName) 
      fileLocation.add('src/' + buildType) 
      task.moduleVersion = findTargetVersion(project, flavorName) 
      task.flavorName = flavorName; 
     } else if (variantTokens.length == 1) { 
      // If only buildType is found. 
      fileLocation.add('src/' + variantTokens[0]) 
     } 

     String searchedLocation = System.lineSeparator() 
     for (String location : fileLocation) { 
      File jsonFile = project.file(location + '/' + JSON_FILE_NAME) 
      searchedLocation = searchedLocation + jsonFile.getPath() + System.lineSeparator() 
      if (jsonFile.isFile()) { 
       quickstartFile = jsonFile 
       break 
      } 
     } 

     if (quickstartFile == null) { 
      quickstartFile = project.file(JSON_FILE_NAME) 
      searchedLocation = searchedLocation + quickstartFile.getPath() 
     } 

     File outputDir = 
       project.file("$project.buildDir/generated/res/google-services/$variant.dirName") 

     task.quickstartFile = quickstartFile 
     task.intermediateDir = outputDir 
     task.packageName = variant.applicationId 
     task.moduleGroup = MODULE_GROUP 
     // Use the target version for the task. 
     //task.moduleVersion = targetVersion; 
     variant.registerResGeneratingTask(task, outputDir) 
     task.searchedLocation = searchedLocation 
    } 

} 


/** 
* Helper task for plugin 
* */ 
public class FlavorAwareGoogleServicesTask extends DefaultTask { 

    private static final String STATUS_DISABLED = "1"; 
    private static final String STATUS_ENABLED = "2"; 

    private static final String OAUTH_CLIENT_TYPE_WEB = "3"; 

    /** 
    * The input is not technically optional but we want to control the error message. 
    * Without @Optional, Gradle will complain itself the file is missing. 
    */ 
    @InputFile @Optional 
    public File quickstartFile; 

    @OutputDirectory 
    public File intermediateDir; 

    @Input 
    public String packageName; 

    @Input 
    public String moduleGroup; 

    @Input 
    public String moduleVersion; 

    @Input 
    public String searchedLocation; 

    @Input 
    public String flavorName; 

    @TaskAction 
    public void action() throws IOException { 
     checkVersionConflict(); 
     if (!quickstartFile.isFile()) { 
      throw new GradleException(String.format("File %s is missing. " + 
        "The Google Services Plugin cannot function without it. %n Searched Location: %s", 
        quickstartFile.getName(), searchedLocation)); 
     } 

     getProject().getLogger().warn("Parsing json file: " + quickstartFile.getPath()); 

     // delete content of outputdir. 
     deleteFolder(intermediateDir); 
     if (!intermediateDir.mkdirs()) { 
      throw new GradleException("Failed to create folder: " + intermediateDir); 
     } 

     JsonElement root = new JsonParser().parse(Files.newReader(quickstartFile, Charsets.UTF_8)); 

     if (!root.isJsonObject()) { 
      throw new GradleException("Malformed root json"); 
     } 

     JsonObject rootObject = root.getAsJsonObject(); 

     Map<String, String> resValues = new TreeMap<String, String>(); 
     Map<String, Map<String, String>> resAttributes = new TreeMap<String, Map<String, String>>(); 

     handleProjectNumberAndProjectId(rootObject, resValues); 
     handleFirebaseUrl(rootObject, resValues); 

     JsonObject clientObject = getClientForPackageName(rootObject); 

     if (clientObject != null) { 
      handleAnalytics(clientObject, resValues); 
      handleMapsService(clientObject, resValues); 
      handleGoogleApiKey(clientObject, resValues); 
      handleGoogleAppId(clientObject, resValues); 
      handleWebClientId(clientObject, resValues); 
     } else { 
      throw new GradleException("No matching client found for package name '" + packageName + "'"); 
     } 

     // write the values file. 
     File values = new File(intermediateDir, "values"); 
     if (!values.exists() && !values.mkdirs()) { 
      throw new GradleException("Failed to create folder: " + values); 
     } 

     Files.write(getValuesContent(resValues, resAttributes), new File(values, "values.xml"), Charsets.UTF_8); 
    } 

    /** 
    * Check if there is any conflict between Play-Services Version 
    */ 
    private void checkVersionConflict() { 
     Project project = getProject(); 
     ConfigurationContainer configurations = project.getConfigurations(); 
     if (configurations == null) { 
      return; 
     } 
     boolean hasConflict = false; 
     for (Configuration configuration : configurations) { 
      if (configuration == null) { 
       continue; 
      } 
      if (configuration.name.startsWith(flavorName + "Compile")) { 
       DependencySet dependencies = configuration.getDependencies(); 
       if (dependencies == null) { 
        continue; 
       } 

       for (Dependency dependency : dependencies) { 
        if (dependency == null || dependency.getGroup() == null || dependency.getVersion() == null) { 
         continue; 
        } 
        println("checkVersionConflict for flavor:" + flavorName + 
          " comparing moduleGroup:" + moduleGroup + " to " + dependency.getGroup() + 
          " moduleVersion:" + moduleVersion + " to " + dependency.getVersion()); 
        if (dependency.getGroup().equals(moduleGroup) 
          && !dependency.getVersion().equals(moduleVersion)) { 
         hasConflict = true; 
         project.getLogger().warn("Found " + dependency.getGroup() + ":" + 
           dependency.getName() + ":" + dependency.getVersion() + ", but version " + 
           moduleVersion + " is needed for the google-services plugin."); 
        } 
       } 
      } 

     } 
     if (hasConflict) { 
      throw new GradleException("Please fix the version conflict either by updating the version " + 
        "of the google-services plugin (information about the latest version is available at " + 
        "https://bintray.com/android/android-tools/com.google.gms.google-services/) or updating " + 
        "the version of " + moduleGroup + " to " + moduleVersion + "."); 
     } 
    } 

    private void handleFirebaseUrl(JsonObject rootObject, Map<String, String> resValues) 
      throws IOException { 
     JsonObject projectInfo = rootObject.getAsJsonObject("project_info"); 
     if (projectInfo == null) { 
      throw new GradleException("Missing project_info object"); 
     } 

     JsonPrimitive firebaseUrl = projectInfo.getAsJsonPrimitive("firebase_url"); 
     if (firebaseUrl != null) { 
      resValues.put("firebase_database_url", firebaseUrl.getAsString()); 
     } 
    } 

    /** 
    * Handle project_info/project_number for @string/gcm_defaultSenderId, and fill the res map with the read value. 
    * @param rootObject the root Json object. 
    * @throws IOException 
    */ 
    private void handleProjectNumberAndProjectId(JsonObject rootObject, Map<String, String> resValues) 
      throws IOException { 
     JsonObject projectInfo = rootObject.getAsJsonObject("project_info"); 
     if (projectInfo == null) { 
      throw new GradleException("Missing project_info object"); 
     } 

     JsonPrimitive projectNumber = projectInfo.getAsJsonPrimitive("project_number"); 
     if (projectNumber == null) { 
      throw new GradleException("Missing project_info/project_number object"); 
     } 

     resValues.put("gcm_defaultSenderId", projectNumber.getAsString()); 

     JsonPrimitive bucketName = projectInfo.getAsJsonPrimitive("storage_bucket"); 
     if (bucketName != null) { 
      resValues.put("google_storage_bucket", bucketName.getAsString()); 
     } 
    } 

    private void handleWebClientId(JsonObject clientObject, Map<String, String> resValues) { 
     JsonArray array = clientObject.getAsJsonArray("oauth_client"); 
     if (array != null) { 
      final int count = array.size(); 
      for (int i = 0 ; i < count ; i++) { 
       JsonElement oauthClientElement = array.get(i); 
       if (oauthClientElement == null || !oauthClientElement.isJsonObject()) { 
        continue; 
       } 
       JsonObject oauthClientObject = oauthClientElement.getAsJsonObject(); 
       JsonPrimitive clientType = oauthClientObject.getAsJsonPrimitive("client_type"); 
       if (clientType == null) { 
        continue; 
       } 
       String clientTypeStr = clientType.getAsString(); 
       if (!OAUTH_CLIENT_TYPE_WEB.equals(clientTypeStr)) { 
        continue; 
       } 
       JsonPrimitive clientId = oauthClientObject.getAsJsonPrimitive("client_id"); 
       if (clientId == null) { 
        continue; 
       } 
       resValues.put("default_web_client_id", clientId.getAsString()); 
       return; 
      } 
     } 
    } 

    /** 
    * Handle a client object for analytics (@xml/global_tracker) 
    * @param clientObject the client Json object. 
    * @throws IOException 
    */ 
    private void handleAnalytics(JsonObject clientObject, Map<String, String> resValues) 
      throws IOException { 
     JsonObject analyticsService = getServiceByName(clientObject, "analytics_service"); 
     if (analyticsService == null) return; 

     JsonObject analyticsProp = analyticsService.getAsJsonObject("analytics_property"); 
     if (analyticsProp == null) return; 

     JsonPrimitive trackingId = analyticsProp.getAsJsonPrimitive("tracking_id"); 
     if (trackingId == null) return; 

     resValues.put("ga_trackingId", trackingId.getAsString()); 

     File xml = new File(intermediateDir, "xml"); 
     if (!xml.exists() && !xml.mkdirs()) { 
      throw new GradleException("Failed to create folder: " + xml); 
     } 

     Files.write(getGlobalTrackerContent(
       trackingId.getAsString()), 
       new File(xml, "global_tracker.xml"), 
       Charsets.UTF_8); 
    } 

    /** 
    * Handle a client object for maps (@string/google_maps_key). 
    * @param clientObject the client Json object. 
    * @throws IOException 
    */ 
    private void handleMapsService(JsonObject clientObject, Map<String, String> resValues) 
      throws IOException { 
     JsonObject mapsService = getServiceByName(clientObject, "maps_service"); 
     if (mapsService == null) return; 

     String apiKey = getAndroidApiKey(clientObject); 
     if (apiKey != null) { 
      resValues.put("google_maps_key", apiKey); 
      return; 
     } 
     throw new GradleException("Missing api_key/current_key object"); 
    } 

    private void handleGoogleApiKey(JsonObject clientObject, Map<String, String> resValues) { 
     String apiKey = getAndroidApiKey(clientObject); 
     if (apiKey != null) { 
      resValues.put("google_api_key", apiKey); 
      // TODO: remove this once SDK starts to use google_api_key. 
      resValues.put("google_crash_reporting_api_key", apiKey); 
      return; 
     } 

     // if google_crash_reporting_api_key is missing. 
     // throw new GradleException("Missing api_key/current_key object"); 
     throw new GradleException("Missing api_key/current_key object"); 
    } 

    private String getAndroidApiKey(JsonObject clientObject) { 
     JsonArray array = clientObject.getAsJsonArray("api_key"); 
     if (array != null) { 
      final int count = array.size(); 
      for (int i = 0 ; i < count ; i++) { 
       JsonElement apiKeyElement = array.get(i); 
       if (apiKeyElement == null || !apiKeyElement.isJsonObject()) { 
        continue; 
       } 
       JsonObject apiKeyObject = apiKeyElement.getAsJsonObject(); 
       JsonPrimitive currentKey = apiKeyObject.getAsJsonPrimitive("current_key"); 
       if (currentKey == null) { 
        continue; 
       } 
       return currentKey.getAsString(); 
      } 
     } 
     return null; 
    } 


    /** 
    * find an item in the "client" array that match the package name of the app 
    * @param jsonObject the root json object. 
    * @return a JsonObject representing the client entry or null if no match is found. 
    */ 
    private JsonObject getClientForPackageName(JsonObject jsonObject) { 
     JsonArray array = jsonObject.getAsJsonArray("client"); 
     if (array != null) { 
      final int count = array.size(); 
      for (int i = 0 ; i < count ; i++) { 
       JsonElement clientElement = array.get(i); 
       if (clientElement == null || !clientElement.isJsonObject()) { 
        continue; 
       } 

       JsonObject clientObject = clientElement.getAsJsonObject(); 

       JsonObject clientInfo = clientObject.getAsJsonObject("client_info"); 
       if (clientInfo == null) continue; 

       JsonObject androidClientInfo = clientInfo.getAsJsonObject("android_client_info"); 
       if (androidClientInfo == null) continue; 

       JsonPrimitive clientPackageName = androidClientInfo.getAsJsonPrimitive("package_name"); 
       if (clientPackageName == null) continue; 

       if (packageName.equals(clientPackageName.getAsString())) { 
        return clientObject; 
       } 
      } 
     } 

     return null; 
    } 

    /** 
    * Handle a client object for Google App Id. 
    */ 
    private void handleGoogleAppId(JsonObject clientObject, Map<String, String> resValues) 
      throws IOException { 
     JsonObject clientInfo = clientObject.getAsJsonObject("client_info"); 
     if (clientInfo == null) { 
      // Should not happen 
      throw new GradleException("Client does not have client info"); 
     } 

     JsonPrimitive googleAppId = clientInfo.getAsJsonPrimitive("mobilesdk_app_id"); 
     if (googleAppId == null) return; 

     String googleAppIdStr = googleAppId.getAsString(); 
     if (Strings.isNullOrEmpty(googleAppIdStr)) return; 

     resValues.put("google_app_id", googleAppIdStr); 
    } 

    /** 
    * Finds a service by name in the client object. Returns null if the service is not found 
    * or if the service is disabled. 
    * 
    * @param clientObject the json object that represents the client. 
    * @param serviceName the service name 
    * @return the service if found. 
    */ 
    private JsonObject getServiceByName(JsonObject clientObject, String serviceName) { 
     JsonObject services = clientObject.getAsJsonObject("services"); 
     if (services == null) return null; 

     JsonObject service = services.getAsJsonObject(serviceName); 
     if (service == null) return null; 

     JsonPrimitive status = service.getAsJsonPrimitive("status"); 
     if (status == null) return null; 

     String statusStr = status.getAsString(); 

     if (STATUS_DISABLED.equals(statusStr)) return null; 
     if (!STATUS_ENABLED.equals(statusStr)) { 
      getLogger().warn(String.format("Status with value '%1$s' for service '%2$s' is unknown", 
        statusStr, 
        serviceName)); 
      return null; 
     } 

     return service; 
    } 

    private static String getGlobalTrackerContent(String ga_trackingId) { 
     return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 
       "<resources>\n" + 
       " <string name=\"ga_trackingId\" translatable=\"false\">" + ga_trackingId + "</string>\n" + 
       "</resources>\n"; 
    } 

    private static String getValuesContent(Map<String, String> values, 
              Map<String, Map<String, String>> attributes) { 
     StringBuilder sb = new StringBuilder(256); 

     sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 
       "<resources>\n"); 

     for (Map.Entry<String, String> entry : values.entrySet()) { 
      String name = entry.getKey(); 
      sb.append(" <string name=\"").append(name).append("\" translatable=\"false\""); 
      if (attributes.containsKey(name)) { 
       for (Map.Entry<String, String> attr : attributes.get(name).entrySet()) { 
        sb.append(" ").append(attr.getKey()).append("=\"") 
          .append(attr.getValue()).append("\""); 
       } 
      } 
      sb.append(">").append(entry.getValue()).append("</string>\n"); 
     } 

     sb.append("</resources>\n"); 

     return sb.toString(); 
    } 

    private static void deleteFolder(final File folder) { 
     if (!folder.exists()) { 
      return; 
     } 
     File[] files = folder.listFiles(); 
     if (files != null) { 
      for (final File file : files) { 
       if (file.isDirectory()) { 
        deleteFolder(file); 
       } else { 
        if (!file.delete()) { 
         throw new GradleException("Failed to delete: " + file); 
        } 
       } 
      } 
     } 
     if (!folder.delete()) { 
      throw new GradleException("Failed to delete: " + folder); 
     } 
    } 
} 


apply plugin: MultiFlavorGoogleServicesPlugin 

======== ORIGINAL 2017.04.04 =======

in diese Suche gefunden weiter, ich, dass die google-Dienste-Plugin ist die Quelle der Fehlermeldung und der Einschränkung, dass nur eine Version einer GPS-Bibliothek abhängig ist cy kann verwendet werden. (Wenn Sie auskommentieren, verwenden Sie das Plug-in: 'com.google.gms.google-services' in der obigen build.gradle, dann tritt die Fehlermeldung nicht auf. Aber Sie brauchen dieses Plugin wirklich, also kommentieren Sie es keine Lösung.)

Um dies zu tun, müssten Sie eine modifizierte Version des Google-Services-Plugins erstellen (das unten in der App build.gradle oben angewendet wird).

Das Google-Services-Plug-in besteht aus zwei Dateien: GoogleServicesTask.java und GoogleServicesPlugin.groovy. (Diese können tief unter dem "Caches" -Unterverzeichnis von Gradle Home gefunden werden).

Offenbar besteht GoogleServicesTask.java darauf, nur die erste Version der GPS-Bibliothek zu verwenden, die es findet (in der Methode findTargetVersion).

(edited out Zeichen zu speichern)

0

Kein Gerät unterstützt mehrere Versionen derselben Bibliothek nicht. Es wählt das neueste, Gradle verwendet standardmäßig die neueste der widersprüchlichen Versionen. Sie können dieses Verhalten jedoch ändern. Verwenden Sie diese Methode, um die Auflösung so zu konfigurieren, dass sie bei jedem Versionskonflikt, z. Mehrere verschiedene Versionen derselben Abhängigkeit (Gruppe und Name sind gleich) in derselben Konfiguration.

Quellen von hier https://gradle.org/docs/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html

+0

Dank für Ihre Antwort und die Zeiger auf diese Dokumentation. es ist interessant. aber eine Sache, die ich bemerkt habe, ist, dass das Android Gradle Plugin erlaubt mir zwei verschiedene Versionen der gleichen Bibliothek in zwei verschiedenen Geschmacksrichtungen zu kompilieren, wenn die Bibliothek keine GPS-Bibliothek ist. (z. B. com.android.support:appcompat-v7:25.3.0 und com.android.support:appcompat-v7:25.3.1) –

Verwandte Themen