Как использовать две разные версии файлов GooglePlayServices в двух разных продуктах?

0 albert c braun [2017-05-02 06:10:00]

По причинам, особенно для моего приложения, я хотел бы использовать две разные версии библиотеки Google Play Services в двух разных продуктах. Но gradle дает мне знакомое сообщение об ошибке:

Исправьте конфликт версии либо путем обновления версии плагина google-services (информация о последней версии доступна на странице https://bintray.com/android/android-tools/com.google.gms.google-services/) или обновить версию com.google.android.gms до 10.2.4.

Обычно я исправляю это, используя согласованные версии библиотек GPS. Но в этом случае я думал, что несогласованность будет в порядке, потому что я собираю приложение в два отдельных вкуса. Это не совсем работает:

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'

проект 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 Версия: 3.3

Версия Android: 2.3.1

android android-studio android-gradle google-play-services


2 ответа


0 Решение albert c braun [2017-05-04 05:27:00]

======== ПЕРЕСМОТРЕН 04/05/2017 ========

Это экспериментально, но, FWIW, я смог взломать "понимание вкуса" до версии 3.0.0 GoogleServicesTask.java и GoogleServicesPlugin.groovy (которые составляют GoogleServicesPlugin для градиента).

Оригинальный плагин передает версию библиотеки GPS, изучая инструкции "компиляции" в вашем build.gradle (в методе findTargetVersion). Но я это изменил. С помощью этого хака вы предварительно указываете эти версии на каждый вкус в свойствах расширения.

Этот подход не является ни проверенным, ни готовым к производству, но он способен скомпилировать две разные версии библиотек GPS с двумя различными вкусами продукта. Также обратите внимание: Android Studio жалуется на то, что у вас есть две разные версии (красная подчеркивание), но AS все же должна позволить вам выбрать любой из ваших вкусов в buildvariants и фактически выполнить сборку. (По крайней мере, это было для меня.)

Сначала добавьте эти два значения расширения (или любые версии, которые вы хотите использовать) в том же build.gradle, где-то разумным:

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

Во-вторых, закомментируйте или удалите эту строку "apply" из вашего модуля приложения build.gradle:

apply plugin: GoogleServicesPlugin

Наконец, непосредственно вставьте следующие измененные версии GoogleServicesTask.java и GoogleServicesPlugin.groovy в нижнюю часть этого файла build.gradle (и не забудьте включить новую строку "применить плагин" внизу):

// ************************************************************//
// ********** 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

======== ОРИГИНАЛ 04/04/2017 =======

Изучив это, я обнаружил, что плагин google-services является источником сообщения об ошибке и ограничением, что можно использовать только одну версию зависимости библиотеки GPS. (Если вы прокомментируете применение плагина: com.google.gms.google-services в вышеприведенном build.gradle, сообщение об ошибке не произойдет. Но вам действительно нужен этот плагин, поэтому комментирование его не является решение.)

Для этого вам нужно будет создать модифицированную версию плагина google-services (который применяется в нижней части приложения build.gradle выше).

Плагин google-services состоит из двух файлов: GoogleServicesTask.java и GoogleServicesPlugin.groovy. (Они могут быть найдены глубоко под поддиретом "кэшей" дома градлей).

Похоже, что GoogleServicesTask.java настаивает только на использовании первой версии найденной GPS-библиотеки (в методе findTargetVersion).

(отредактирован для сохранения символов)


0 ZeroOne [2017-05-02 07:15:00]

Ни один град не поддерживает несколько версий одной и той же библиотеки. Он выберет самый новый, Gradle по умолчанию использует новейшие конфликтующие версии. Однако вы можете изменить это поведение. Используйте этот метод для того, чтобы настроить разрешение с ошибкой на любой конфликт версий, например, несколько разных версий одной и той же зависимости (группа и имя равны) в той же Конфигурации.

Источники отсюда https://gradle.org/docs/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html