Nano Hash - криптовалюты, майнинг, программирование

Динамическое создание вкусов продуктов

Я создал приложение для Android, которое нужно создать во многих (30+) вариантах.

Моя идея заключалась в том, чтобы сгенерировать другой productFlavors непосредственно из структуры папок в моем каталоге src, поскольку конфигурация всегда очень похожа (в основном просто другое имя пакета, новый значок запуска и некоторые строки меняются).

Папка src выглядит так:

└── src
    ├── flavor1
    │   ├── flavor2.keystore
    │   ├── res
    ├── flavor2
    │   ├── res
    │   ├── flavor2.keystore    
    └── main
        ├── AndroidManifest.xml
        ├── java
        └── res

Если бы мне пришлось создавать свойства gradle вручную, это выглядело бы примерно так:

android {

    ....

    productFlavors {
        flavor1 {
            packageName 'com.example.flavor1'
        }
        flavor2 {
            packageName 'com.example.flavor2'
        }
    }

}

Каждый раз, когда я пытаюсь изменить конфигурацию productFlavors после ее создания, я получаю либо сообщение об ошибке, либо изменения/дополнения молча игнорируются.
Это может быть проблема, вызванная мной, потому что мой опыт работы с Gradle / Groovy очень ограничен, или это не так. не возможно.

В основном я получаю ошибку, говоря, что GroupableProductFlavorDsl_Decorated нельзя манипулировать так, как я хочу.

То, что я пытаюсь заархивировать, должно как-то выглядеть так:

android {

    ....

    def flavors = getMyFlavorsFromFileSystem()

    productFlavors {

    }

    flavors.each { name, config ->
        productFlavors[name] << config
    }

}

Примечание. Я знаю, что этот вопрос в основном является дубликатом старый вопрос, на который, к сожалению, так и не ответили. Поскольку Gradle является чем-то новым в мире Android, я надеюсь получить больше ответов, так как с тех пор, как в последний раз был задан вопрос, потому что сейчас все больше разработчиков используют Gradle.

Обновление:

Вот несколько очень простых подходов, которые я пробовал:

Вариант 1:

android {

    productFlavors {

    }

    productFlavors['flavor1'] << {
        packageName "com.example.flavor1"
    }

    productFlavors['flavor2'] << {
        packageName "com.example.flavor2"
    }
}

/*

A problem occurred evaluating root project 'MyProject'.
> GroupableProductFlavorDsl with name 'flavor1' not found.

*/

Вариант 2:

android {

    productFlavors {

    }

    productFlavors['flavor1'] = {
        packageName "com.example.flavor1"
    }

    productFlavors['flavor2'] = {
        packageName "com.example.flavor2"
    }
}

/*

no error, but does not work

*/

Вариант 3:

android {

    productFlavors {

    }

    productFlavors['flavor1'] = [packageName: "com.example.flavor1"]

    productFlavors['flavor2'] = [packageName: "com.example.flavor2"]
}

/*

no error, but does not work

*/

Все они представлены в виде Gist.


  • Каждый раз, когда я пытаюсь возиться с конфигурацией productFlavors, я получаю либо ошибку, либо изменения/дополнения игнорируются молча -- будет очень сложно вам помочь, когда вы не объясните, что за лажа со средствами, какие ошибки вы получаете, какие изменения /дополнения - это то, что молча игнорируется и т.д. 07.01.2014
  • зачем создавать столько сборок? Ваш код не может распознать, на какой сборке он работает, и соответствующим образом настроить свои методы? Ребята из Google/Android хорошо поработали над тем, чтобы библиотеки поддержки работали во всех вариантах. 07.01.2014
  • @Martin Мне нужно столько сборок, потому что эти приложения продаются клиентам как приложения с белой этикеткой (другое имя пакета, другая учетная запись разработчика Google, другое хранилище ключей). Моя компания работает в сфере печати для веб-сайтов, так что да: мне нужно столько-то сборок. 07.01.2014
  • (Предупреждение: UGLY HACK) Я бы создал сценарий Bash, который изменяет сценарий gradle, а затем создает приложение. 07.01.2014
  • @CommonsWare Я обновил раздел вопроса 07.01.2014
  • В основном я получаю сообщение об ошибке, говоря, что с GroupableProductFlavorDsl_Decorated нельзя манипулировать так, как я хочу, - это не особенно полезно. Ваш вопрос сродни визиту к врачу, который сообщает, что вы плохо себя чувствуете, а затем проводите 30 минут, болтая о своем любимом футбольном клубе без каких-либо симптомов. Что вы делаете, конкретно, что приводит к возникновению ошибок, и что такое полный вывод ошибки из сборки Gradle? 07.01.2014
  • @CommonsWare Я добавил 3 очень простых примера того, что я пробовал. Один выдает и ошибку, два других просто ничего не делают. Ошибки нет, но и не productFlavors. 07.01.2014
  • Ознакомьтесь с моим решением здесь: stackoverflow.com/a/36294908/1957401 сработало для меня довольно хорошо для более чем 300 вкусов. 29.03.2016

Ответы:


1

Решено методом проб и ошибок:

android {

    // let's assume these are return by a function which reads the filesystem
    def myFlavors = [
        flavor1: [
            packageName: "com.example.flavor1"
        ],
        flavor2: [
            packageName: "com.example.flavor2"
        ]
    ]

    productFlavors {
        myFlavors.each { name, config ->
            "$name" {
                packageName config.packageName
            }
        }
    }

}
07.01.2014
  • Можете ли вы поделиться кодом, который читает файловую систему, чтобы получить имена пакетов? 19.08.2014
  • @SeanBarbeau Я бы не хотел. Это немного сложнее, как я описал выше. (Чтение каталогов, проверка различных файлов, разбор некоторых YAML и JSON...) 19.08.2014
  • @TheHippo Вы все еще создаете папки src/ вручную или они созданы где-то еще. Если они не создаются вручную, не могли бы вы опубликовать тот фрагмент кода, который создает структуру папок. Спасибо. 08.12.2014
  • Папки @danypata src создаются вручную. Они содержат различные значки приложений и пользовательские языковые строки. 10.12.2014
  • Привет, я пытаюсь сделать то же самое. Для чего нужно $name? (вернее, что это такое?) 15.10.2015
  • @hadez30 это переменная и то, как в Groovy можно создавать циклы. 15.10.2015
  • Спасибо, TheHippo. Выяснил это после публикации комментария (извините за это). Кстати, мы сделали то же самое, чтобы получить имя пакета? -- из моего ответа, или вы добились этого каким-то другим способом?) 15.10.2015
  • Ознакомьтесь с моим решением здесь: stackoverflow.com/a/36294908/1957401 сработало для меня довольно хорошо для более чем 300 вкусов. 29.03.2016

  • 2

    Я знаю, что на это уже есть ответ, но я как бы объединил подход Chris.Zou с TheHippo. И добавить мой собственный метод для этого.

    По сути, при работе с вариантами мы обычно работаем с разными каталогами в /app/src/, которые содержат ресурсы. А поскольку имя каталога совпадает с именем пакета, я просто перечислил каталоги в этой папке (исключая «main» и «androidTest»).

    Итак, вот мой полный рабочий скрипт Gradle:

    def map = [:]
    
    new File("./app/src").eachFile() { file->
    
        def fileName = file.getName()
        if( fileName == "main" || fileName == "androidTest") {
            return
        }
    
        map.put(fileName, 'com.mypackagename.' + fileName )
    
    
    }
    productFlavors {
        map.each { flavorName, packagename ->
            "$flavorName" {
                applicationId packagename
            }
        }
    }
    

    Редактировать:

    • Также хотел бы добавить, что com.mypackagename в основном является корневым путем для всех вариантов.
    • У меня есть отдельный скрипт, который копирует и вставляет каталог аромата в папку /app/src/.
    15.10.2015

    3

    Поскольку автор вопроса не хотел делиться своим кодом для чтения файлов. Я напишу о том, что я сделал. Я поместил все названия вариантов в файл с именем «app/build_variants.txt», по одной строке для каждого, примерно так:

    flavor1
    flavor2
    flavor3
    flavor4
    flavor5
    

    И в «приложении/build.gradle»:

    //...other configs...
    
    android {
        productFlavors {
            new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } }
        }
    }
    
    //...other configs
    

    Это будет иметь тот же результат, что и следующий код:

    //...other configs...
    
    android {
        productFlavors {
            flavor1 { resValue "string", "build_variant_name", "flavor1" } 
            flavor2 { resValue "string", "build_variant_name", "flavor2" } 
            flavor3 { resValue "string", "build_variant_name", "flavor3" } 
            flavor4 { resValue "string", "build_variant_name", "flavor4" } 
            flavor5 { resValue "string", "build_variant_name", "flavor5" } 
        }
    }
    
    //...other configs
    

    Ключевым здесь является строка new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } }. Он читает файл «app/build_variants.txt» и для каждой строки создает вариант продукта с именем в строке, которую он читает. $it - это строка, в которую он проходит. Это просто синтаксис закрытия Groovy. Если вы хотите более глубокого понимания. Я настоятельно рекомендую посмотреть видео @Daniel Lew о groovy и gradle. Это потрясающе!

    22.06.2015
  • Вопрос был о том, как динамически генерировать аромат, а не о том, как прочитать файл из сценария сборки gradle. 23.06.2015
  • @TheHippo Мой ответ также включает код для динамического создания вкуса, а также код для чтения файла, что может помочь людям, которые хотят сохранить вкусы своих продуктов в отдельном файле. 24.06.2015
  • что, если каждая строка содержит несколько значений, разделенных запятыми. Как я могу разделить и поместить их отдельно в сгенерированные ароматы? В вашем примере вы указываете всю строку (это просто название аромата). Что сработало для меня. Но я хочу передать идентификатор приложения и значения resValues ​​из файла. Это возможно? 29.03.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..