React Native Android Duplicate file error при создании apk

Когда я пытаюсь создать android apk с помощью ./gradlew installRelease, я получаю эту ошибку в консоли:

~/React-Native/mockingbird/android/app/build/intermediates/res/merged/release/drawable-mdpi-v4/src_resources_img_loading.gif: error: Duplicate file.
~/React-Native/mockingbird/android/app/build/intermediates/res/merged/release/drawable-mdpi/src_resources_img_loading.gif: Original is here. The version qualifier may be implied.

Я попробовал Build->Clean Project через Android Studio и снова запустил ./gradlew installRelease; это тоже не сработало.

Кроме того, я попытался удалить папку build, но это тоже не помогает.

Ответ 1

Дайте несколько советов для вас, надеюсь, это сработает.

Обновите с помощью "реакции": "16.7.0", "реакция-нативная": "0.57.8"

Пользовательский узел_модулей/реагировать-нативный/реагировать .gradle, чтобы идеально решить ошибку Duplicate file. Добавьте следующий код в блок создания currentBundleTask (после блока doFirst)

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("${resourcesDir}/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

Вы можете создать скрипт, чтобы сделать это автоматически.

  1. Создать android-react-gradle-fix файл
  2. Создать скрипт android-release-gradle-fix.js файл
  3. Обновите файл package.json:

    "сценарии": {    "postinstall": "node./android-release-gradle-fix.js" },

Это! Запустите npm install, чтобы стать классным.

Примечание: Если вы запускаете npm install на ci, как jenkins, вы можете получить ошибку: postinstall: cannot run in wd %s %s (wd=%s) node => просто используйте вместо этого npm install --unsafe-perm

Ответ 2

Удалите файлы, которые у вас могут быть:

android/app/src/main/res/drawable-mdpi/
android/app/src/main/res/drawable-xhdpi/
android/app/src/main/res/drawable-xxhdpi/

Запустите Build снова, это исправило проблему для меня.

Ответ 3

На момент написания этой статьи более поздние версии React Native (> 0.57.0) увеличили уровень оболочки Gradle до 4.4, а плагин Gradle - до 3.1.4, как указано в changelog. В результате процесс сборки Gradle сохраняет результаты AAPT, которые теперь необходимы, в другом каталоге, чем ранее.

С точки зрения Нхан Цаопотрясающего обходного пути, нам нужно внести небольшие изменения, чтобы предотвратить повторяющиеся конфликты ресурсов, так как он выглядит как направленный на старый каталог, а не на каталог app generated. Изменив целевой каталог, в котором эти дубликаты объединены вместе после того, как ресурсы были сгенерированы, мы все еще можем дедуплировать ресурсы.

Существующий react.gradle ссылается на путь ниже:

$buildDir === <project-working-directory>/android/app/build

Повторяющиеся пути к файлам могут появляться между:

file("$buildDir/../src/main/res/drawable-${resSuffix}")
file("$buildDir/generated/res/react/release/drawable-${resSuffix}")

В качестве обходного пути мы можем обновить решение Nhan следующим образом (обязательно включите его в currentBundleTask после объявления doFirst в react.gradle:

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

Если ваше приложение также зависит от ресурсов /raw, вам поможет описанный ниже метод:

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
     }
     moveFunc.curry("drawable-ldpi").call()
     moveFunc.curry("drawable-mdpi").call()
     moveFunc.curry("drawable-hdpi").call()
     moveFunc.curry("drawable-xhdpi").call()
     moveFunc.curry("drawable-xxhdpi").call()
     moveFunc.curry("drawable-xxxhdpi").call()
     moveFunc.curry("raw").call()
}

Ответ 4

Не запускайте react-native bundle до ./gradlew assembleRelease.

Для себя я использовал react-native bundle до запуска ./gradlew assembleRelease.

Я получал похожее двойное сообщение об ошибке с одним из моих активов.

Глядя на вывод ./gradlew assembleRelease, я мог бы сказать, что он сам собирает JS-пакет (благодаря apply from: "../node_modules/react-native/react.gradle" в вашем файле build.gradle), поэтому нет необходимости вручную запускать react-native bundle перед этим.

Если бы я просто не запустил react-native bundle до запуска ./gradlew assembleRelease, все работало бы отлично.

Я протестировал Release APK и пакет JS загружается нормально, включая все изображения.

Меня беспокоит только то, будут ли созданы исходные карты --sourcemap-output (для Bugsnag). Если нет, я уверен, что есть способ, чтобы ./gradlew assembleRelease генерировал их тоже. Я просто еще не проверял это.

Ответ 5

Чтобы моя сборка работала на React Native 0.57.5, я использовал ответ Mapsy с небольшим улучшением. Мне нужно было иметь возможность строить для разных вкусов, и, как правило, я стараюсь избегать жесткого кодирования. Просматривая мой файл react.gradle, я обнаружил, что в нем определена следующая переменная:

def resourcesDir = file("$buildDir/generated/res/react/${targetPath}")

Таким образом, вместо жесткого кодирования типа сборки/разновидности в пути, вот так:

File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");

Вместо этого я использовал переменную resourcesDir для установки пути originalDir следующим образом:

File originalDir = file("${resourcesDir}/drawable-${resSuffix}");

В результате мой doLast выглядит так:

doLast {
            def moveFunc = { resSuffix ->
                File originalDir = file("${resourcesDir}/drawable-${resSuffix}");
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
                    ant.move(file: originalDir, tofile: destDir);
                }
            }
            moveFunc.curry("ldpi").call()
            moveFunc.curry("mdpi").call()
            moveFunc.curry("hdpi").call()
            moveFunc.curry("xhdpi").call()
            moveFunc.curry("xxhdpi").call()
            moveFunc.curry("xxxhdpi").call()
        }

Ответ 6

Для меня это работает, чтобы удалить папку: android/build и запустить ./gradlew assembleRelease снова.

Ответ 7

Способ устранения ошибки:

  • поместите ваши изображения в папку android/app/src/main/res/drawable (создайте "drawable" папку, если таковой не существует)
  • удалите все папки для рисования, которые имеют суффиксы (т.е. drawable-hdpi, drawable-mdpi и т.д.)
  • не связывать активы (т.е. не запускать: реагировать на нативную связку…)
  • запустить Gradles собрать

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

Я нашел одно удобное решение - использовать плагин Android Studio под названием Android Drawable Importer. Чтобы использовать его после его установки:

  • откройте свой проект в Android-студии и перейдите по адресу: Android/App/SRC/Main/Res/Drawable
  • щелкните правой кнопкой мыши на папке и выберите: "Создать"> "Пакетный импорт"
  • выбрать и настроить изображения для импорта

Плагин будет обрабатывать создание нарисованных папок и корректные размеры изображений. После того, как вы импортировали свое изображение, вы сможете запускать Gradles assemblyRelease без ошибки повторяющихся ресурсов.

Ответ 8

Для меня сработало просто добавить эту дополнительную команду в package.json и использовать ее для сборки:

    "android-build-release": "cd ./android && rm -rf app/src/main/res/drawable* && ./gradlew app:assembleRelease",