Android Build Crash by add "com.google.gms.google-services" in the build.gradle.kts

I Changed my Native Android Build Process to the newest (Corona-3721)
Everything looks fine so far, but.

I use:
Android Studio Narwhal Feature Drop | 2025.1.2

compileSdk = 34
defaultConfig {
    applicationId = coronaAppPackage
    targetSdk = 34
    minSdk = (extra["minSdkVersion"] as Int)
    versionCode = coronaVersionCode
    versionName = coronaVersionName
    multiDexEnabled = true
}

When I add in this File:
“source/android/app/build.gradle.kts”

plugins {
id(“com.android.application”)
id(“com.google.gms.google-services”) ← This Line
}

(its needed in my Project, it works with the old implemenation)

Than Happens the follow Build Issue with all Assets (png, mp3 …)

AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/slide_small_3.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_3.mp3"}},{"file":{"description":"assets/sounds/slide_small_3.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_3.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/slide_small_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_1.mp3"}},{"file":{"description":"assets/sounds/slide_small_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_1.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/buy_game_sheet.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/buy_game_sheet.mp3"}},{"file":{"description":"assets/sounds/buy_game_sheet.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/buy_game_sheet.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/rf_notification.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/rf_notification.mp3"}},{"file":{"description":"assets/sounds/rf_notification.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/rf_notification.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/slide_small_4.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_4.mp3"}},{"file":{"description":"assets/sounds/slide_small_4.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/slide_small_4.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/pop_1_low.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/pop_1_low.mp3"}},{"file":{"description":"assets/sounds/pop_1_low.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/pop_1_low.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/rf_game_finished.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/rf_game_finished.mp3"}},{"file":{"description":"assets/sounds/rf_game_finished.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/rf_game_finished.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/challenge_task_fade_in.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/challenge_task_fade_in.mp3"}},{"file":{"description":"assets/sounds/challenge_task_fade_in.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/challenge_task_fade_in.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/woosh_out.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/woosh_out.mp3"}},{"file":{"description":"assets/sounds/woosh_out.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/woosh_out.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/correct_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/correct_1.mp3"}},{"file":{"description":"assets/sounds/correct_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/correct_1.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/button_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/button_1.mp3"}},{"file":{"description":"assets/sounds/button_1.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/button_1.mp3"}}],"tool":"Resource and asset merger"}
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[{"file":{"description":"assets/sounds/purchase_finished.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/purchase_finished.mp3"}},{"file":{"description":"assets/sounds/purchase_finished.mp3","path":"/Users/MyNAME/Documents/spell-quiz/source/android/app/build/generated/corona_assets/debug/assets/sounds/purchase_finished.mp3"}}],"tool":"Resource and asset merger"}

Problem Summary: I’ve been using Solar2D’s Android build template successfully for 2+ years. Recently updated to the newest Android Build Template and now encountering critical duplicate resource errors when adding the Google Services plugin.

Test - Source-Code:
source_build_test.zip (1.5 MB)

What Works:

  • :white_check_mark: Old Template (2+ years ago): Everything builds perfectly with Google Services plugin
  • :white_check_mark: New Template WITHOUT Google Services: Builds successfully

What Fails:

  • :x: New Template WITH Google Services plugin: Duplicate resource errors

Build Configuration:

kotlin

plugins {
    id("com.android.application")
    id("com.google.gms.google-services")  // ← This causes the issue
}


Thanks to Claude

Now the app is building and working.

I need to integrate this plugins to my project, because i have additional native functions.

/android/app/build.gradle.kts

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("com.google.gms.google-services") 
    id("com.google.firebase.crashlytics")   
    id("com.google.firebase.firebase-perf")   
}

Fixed File Example:

build.gradle.kts (46.7 KB)

Added a Issue in Git-Hub

Solar2D/Corona SDK: Fixing “Duplicate Resources” Error with google-services Plugin

Problem Summary

When integrating the Google Services Plugin (com.google.gms.google-services) into a Solar2D/Corona SDK Native Android build, the build fails with duplicate resource errors for all assets, particularly:

  • resource.car (compiled Lua archive)
  • iOS-specific files (Icon.png, Images.xcassets, LaunchScreen.storyboardc)
  • All Corona assets in the generated assets directory

Error Message:

> Task :app:mergeDebugAssets FAILED
AGPBI: {"kind":"error","text":"Duplicate resources","sources":[...]}

Build Environment:

  • Solar2D/Corona SDK Native Android
  • Android Gradle Plugin: 8.5.1
  • Google Services Plugin: 4.3.15+
  • Gradle: 8.7+

Root Cause

The issue occurs because Solar2D’s build system registers the Corona assets directory using:

kotlin

android.sourceSets[name].assets.srcDirs(generatedAssetsDir)

The google-services plugin scans all registered asset source directories during its processing phase. Since the same directory is already part of the asset merge pipeline, it gets registered twice, causing duplicate resource errors.

Additionally, iOS-specific assets that shouldn’t be in Android builds were not being excluded, adding to the duplicate warnings.

Solution

1. Exclude iOS-Specific Assets

In the coronaAssetsCopySpec function, add excludes for iOS files:

kotlin

fun coronaAssetsCopySpec(spec: CopySpec) {
    with(spec) {
        // ... existing excludes ...
        
        // ✅ Exclude iOS-specific assets (not needed for Android)
        exclude("Icon.png")                      // iOS App Icon
        exclude("Images.xcassets/**")            // iOS App Icons
        exclude("LaunchScreen.storyboardc/**")   // iOS Launch Screen
        exclude("google-services.json")          // Handled by google-services plugin
        
        // ... rest of function ...
    }
}

2. Replace srcDirs Registration with Manual Asset Copy

Replace the asset registration code in android.applicationVariants.all:

BEFORE (causes duplicates):

kotlin

android.applicationVariants.all {
    // ... taskCopyResources definition ...
    
    mergeAssetsProvider!!.configure {
        dependsOn(taskCopyResources)
    }
    
    // ❌ This causes duplicate resources with google-services plugin
    android.sourceSets[name].assets.srcDirs(generatedAssetsDir)
    
    // ...
}

AFTER (working solution):

kotlin

android.applicationVariants.all {
    // ... taskCopyResources definition ...
    
    mergeAssetsProvider!!.configure {
        dependsOn(taskCopyResources)
        
        // ✅ Copy assets AFTER the merge process
        // This prevents google-services plugin from double-registering the assets
        doLast {
            copy {
                from(generatedAssetsDir)
                into(outputDir.get().asFile)
                duplicatesStrategy = DuplicatesStrategy.INCLUDE
            }
        }
    }
    
    // ❌ DO NOT use srcDirs - causes duplicate resources with google-services
    // android.sourceSets[name].assets.srcDirs(generatedAssetsDir)
    
    // Ensure google-services runs AFTER Corona assets are ready
    tasks.findByName("process${baseNameCapitalized}GoogleServices")?.mustRunAfter(taskCopyResources)
    
    // ...
}

Why This Works

  1. Removes duplicate registration: By not using srcDirs(), we prevent the asset directory from being scanned twice by the google-services plugin
  2. Manual asset integration: The doLast block copies assets directly into the merge task’s output directory after all plugin processing is complete
  3. Task ordering: mustRunAfter ensures google-services processes its files before our assets are finalized
  4. iOS asset exclusion: Prevents unnecessary duplicate warnings for platform-specific files

Testing

After implementing this solution:

:white_check_mark: Build succeeds with google-services plugin enabled
:white_check_mark: Firebase services work correctly
:white_check_mark: No duplicate resource errors
:white_check_mark: resource.car and all Corona assets are properly included in the APK
:white_check_mark: App runs without crashes

Compatible Plugins

This solution works with:

  • com.google.gms.google-services
  • com.google.firebase.crashlytics
  • com.google.firebase.firebase-perf
  • All other Firebase plugins

For Solar2D Team

This appears to be a fundamental incompatibility between Solar2D’s asset management and modern Android Gradle plugins that scan asset directories. Consider:

  1. Updating the official Android build template with this fix
  2. Documenting this workaround in the Native Android build documentation
  3. Investigating whether this can be fixed in the core build system

Related Information