Few things derail a release sprint faster than a dependency conflict immediately following an SDK update. When upgrading the IronSource (LevelPlay) SDK—particularly when jumping major versions (e.g., v7.x to v8.x/v9.x)—Unity developers frequently encounter Gradle build failures or iOS linker errors.
The most common symptom on Android is the dreaded Duplicate class error:
java.lang.RuntimeException: Duplicate class com.ironsource.mediationsdk.utils.IronSourceUtils found in modules jetified-mediationsdk-8.0.0-runtime.jar and jetified-mediationsdk-7.9.0-runtime.jar
Or, you may see vague errors regarding CommandInvokationFailure: Gradle build failed, accompanied by complaints about program type already present.
This guide provides a rigorous technical breakdown of why this persistence occurs despite Unity's package management and offers a definitive, step-by-step solution to resolve adapter mismatches and duplicate dependencies.
The Root Cause: EDM4U and Persistent Assets
To fix the issue reliably, one must understand how Unity handles third-party SDKs compared to native Android/iOS development.
1. The .unitypackage Fallacy
When you import a newer .unitypackage, Unity does not automatically remove files from the previous installation unless they are explicitly tracked and overwritten. If IronSource renames a file, changes a folder structure, or if an adapter changes its naming convention (e.g., IronSourceAdMobAdapter.jar vs AdMobAdapter.jar), the old file remains in your Assets/Plugins/Android folder.
2. The Dependency Manager Conflict
Most professional Unity projects use the External Dependency Manager for Unity (EDM4U). IronSource relies on XML files located in Assets/IronSource/Editor/ to tell EDM4U which Maven repositories and artifacts to pull.
The Conflict:
- Old State: You have
Assets/IronSource/Editor/ISAdMobAdapter_v4.3.1.xml. - Action: You import the new IronSource SDK.
- New State: You now have
Assets/IronSource/Editor/ISAdMobAdapter_v4.3.3.xml. - Result: EDM4U scans both XML files. It attempts to fetch dependencies for both the old adapter and the new adapter. Since these adapters often depend on different versions of the underlying network SDK (e.g.,
play-services-ads), Gradle receives instructions to include multiple versions of the same library.
While Gradle attempts to resolve version conflicts by picking the highest version, the adapters themselves (the glue code) are distinct artifacts. Gradle sees them as two valid, separate dependencies, resulting in duplicate classes during the dexing process.
Step-by-Step Fix: The "Clean Slate" Protocol
Do not attempt to manually edit mainTemplate.gradle until you have cleaned the Unity-side definitions. Follow this strict protocol to align your dependencies.
Step 1: Sanitation of Editor XMLs
The Assets/IronSource/Editor directory is the source of truth for EDM4U. You must remove legacy definitions.
- Navigate to
Assets/IronSource/Editor. - Delete all XML files related to network adapters (e.g.,
ISAdMobAdapter.xml,ISUnityAdsAdapter.xml). - Crucial: Do not delete
IronSourceSDKDependencies.xmljust yet, as we want to ensure we have the clean version from the new import.
If you are unsure which files are safe to delete, it is often safer to delete the entire Assets/IronSource folder and re-import the .unitypackage fresh. This eliminates any orphaned scripts.
Step 2: Artifact Cleanup
You must remove pre-resolved artifacts that EDM4U may have downloaded directly into your project structure.
- Check
Assets/Plugins/Android. - Look for
.jaror.aarfiles referencing ad networks (e.g.,ironsource-adapter-admob.aar). - Delete them. We want EDM4U to resolve these via Gradle, not load them as local hard-files.
- Repeat this process for
Assets/Plugins/iOSif you have loose.frameworkfolders (though Cocoapods usually handles this better, static frameworks cause linker errors).
Step 3: Integration Manager Re-Sync
IronSource provides an Integration Manager that generates the correct dependency XMLs.
- In Unity, go to IronSource > Integration Manager.
- Wait for the network state to fetch the latest versions.
- Click Upgrade or Install on the adapters you need.
Why this works: This script downloads the specific dependencies.xml file for that adapter version into Assets/IronSource/Editor. By deleting the old ones in Step 1, you ensure 1:1 mapping between the definition and the desired version.
Step 4: Force Resolve
Now that the file system definitions are clean, instruct EDM4U to regenerate the Android build configs.
- Go to Assets > External Dependency Manager > Android Resolver > Force Resolve.
- Wait for the success message.
Automated Prevention: Editor Scripting
Manually hunting for duplicates is error-prone. As a Principal Engineer, you should implement tooling to detect this state.
Below is an Editor script that scans your IronSource/Editor folder for duplicate adapter definitions (e.g., two XML files defining dependencies for the same network).
#if UNITY_EDITOR
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class DependencyHealthCheck : EditorWindow
{
[MenuItem("Tools/IronSource/Check Duplicate Adapters")]
public static void ShowWindow()
{
GetWindow<DependencyHealthCheck>("Adapter Health");
}
private void OnGUI()
{
if (GUILayout.Button("Scan for Duplicates"))
{
ScanForDuplicates();
}
}
private static void ScanForDuplicates()
{
string basePath = Path.Combine(Application.dataPath, "IronSource", "Editor");
if (!Directory.Exists(basePath))
{
Debug.LogError($"Directory not found: {basePath}");
return;
}
string[] files = Directory.GetFiles(basePath, "*.xml", SearchOption.TopDirectoryOnly);
// Group files by a heuristic (usually the network name prefix)
// Example filename: ISAdMobAdapter_v4.3.40.xml
var adapterGroups = files
.Select(f => new FileInfo(f))
.GroupBy(f => ExtractNetworkName(f.Name))
.Where(g => g.Count() > 1 && g.Key != "Unknown");
bool issuesFound = false;
foreach (var group in adapterGroups)
{
issuesFound = true;
Debug.LogWarning($"<color=red>DUPLICATE DETECTED:</color> Network '{group.Key}' has {group.Count()} dependency files:");
foreach (var file in group)
{
Debug.LogWarning($"- {file.Name}");
}
}
if (!issuesFound)
{
Debug.Log("<color=green>Dependency Scan Passed: No duplicate adapter definitions found.</color>");
}
}
private static string ExtractNetworkName(string filename)
{
// Heuristic: IronSource adapter XMLs usually follow IS[Network]Adapter format
if (filename.StartsWith("IS") && filename.Contains("Adapter"))
{
// Simple split to grab the middle section.
// Input: ISAdMobAdapter_v4.3.xml -> AdMob
string name = filename.Replace("IS", "").Split(new[] { "Adapter" }, System.StringSplitOptions.None)[0];
return name;
}
return "Unknown";
}
}
#endif
Advanced Troubleshooting: Gradle & ProGuard
If the file cleanup doesn't work, the issue likely resides in mainTemplate.gradle or specific Gradle caches.
The mainTemplate.gradle Trap
If you have "Custom Main Gradle Template" checked in Project Settings, Unity will not automatically update the dependencies block when you resolve. It relies on the // Android Resolver Dependencies Start tag.
Ensure your mainTemplate.gradle looks exactly like this around the dependencies block:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Android Resolver Dependencies Start
implementation 'com.google.android.gms:play-services-ads:22.6.0' // Example
implementation 'com.ironsource.sdk:mediationsdk:7.9.0'
// Android Resolver Dependencies End
**DEPS**
}
Common Pitfall: Developers sometimes manually hardcode an implementation line outside the Resolver tags to fix a previous build error. If you manually added implementation 'com.ironsource.sdk:mediationsdk:7.6.0', and the resolver adds v7.9.0 inside the tags, you will get a duplicate class error. Remove all manual IronSource references from gradle templates.
ProGuard Stripping
Sometimes the build succeeds, but the app crashes on launch with ClassNotFoundException. This happens when IronSource updates use reflection for classes that ProGuard strips out during Minification (Release builds).
If updating to v8.x+, ensure your proguard-user.txt includes the updated rules. The namespace shifts in newer SDKs require updated keep rules.
Add this to Assets/Plugins/Android/proguard-user.txt:
-keep class com.ironsource.** { *; }
-keep class com.ironsource.adapters.** { *; }
-dontwarn com.ironsource.**
Conclusion
The "Duplicate Class" error is rarely a bug in the SDK itself; it is almost strictly a hygiene issue within the Unity Assets folder structure. The transition from local .jar management to Maven-based dependency resolution (EDM4U) creates a fragile state where old and new definitions can coexist destructively.
By aggressively cleaning the IronSource/Editor directory and forcing a fresh resolution of the dependency graph, you eliminate the artifact overlap that causes build failures. Treat your dependency definitions as transient—when in doubt, delete the definitions and let the Integration Manager regenerate them.