Risoluzione delle dipendenze SDK su Android

Il problema delle dipendenze riguarda pacchetti o librerie condivisi su cui molti altri pacchetti hanno dipendenze, ma che dipendono da versioni diverse e incompatibili dei pacchetti condivisi. Gradle ha semplificato di molto il lavoro degli sviluppatori Android: basta aggiungere una dipendenza nel build.gradle e la libreria richiesta viene inclusa senza problemi nella build. Ma cosa succede quando due dipendenze hanno una dipendenza da versioni diverse della stessa libreria?

Gradle è in grado di risolvere automaticamente le dipendenze se entrambe appartengono alla stessa configurazione, cioè alla configurazione dell'app. Ad esempio, l'SDK Audience Network per Android dipende dalla libreria "exoplayer". Se hai bisogno di aggiungere una versione diversa della libreria "exoplayer", Gradle sceglierà la versione più recente da includere. Ma se entrambe le dipendenze appartengono a configurazioni diverse, ovvero app e test, Gradle genererà un errore. Di seguito verranno esaminati i diversi conflitti e le relative soluzioni.

Prerequisiti

Prima di proseguire, assicurati di aver consultato le guide Primi passi di Audience Network e Primi passi su Android.

Conflitti delle dipendenze

1. Librerie condivise in dipendenze della stessa configurazione

2. Librerie condivise in dipendenze da configurazioni diverse

Soluzioni ai conflitti delle dipendenze

1. Lasciare che Gradle risolva le dipendenze per te

2. Escludere la versione specifica della dipendenza

3. Definire esplicitamente la libreria in conflitto in Gradle

4. Forzare la risoluzione della libreria



Conflitti delle dipendenze

1. Librerie condivise in dipendenze dalla stessa configurazione

Considera il seguente esempio. Entrambe le dipendenze nel codice di seguito si trovano nella stessa configurazione e hanno una dipendenza interna su una libreria "org.hamcrest:hamcrest-core". Poiché le due dipendenze utilizzano internamente versioni diverse della stessa libreria, nella build viene inclusa la versione più recente. L'output della sincronizzazione di Gradle indicherà chiaramente che questa aggiorna automaticamente la versione della libreria hamcrest da 1.1 a 1.3 nella build finale.

// Depends on version 1.3 of org.hamcrest:hamcrest-core
androidTestImplementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19'  

2. Librerie condivise in dipendenze da configurazioni diverse

Se le due dipendenze appartengono a configurazioni diverse, ovvero configurazione di app e di test, Gradle genererà un errore. Considera il seguente snippet di codice. La prima dipendenza appartiene alla configurazione dell'app, mentre la seconda appartiene alla configurazione di test. Quindi, durante lo sviluppo del progetto, si verificherà un errore con un'eccezione.

Quando vengono eseguiti i test della strumentazione, l'APK principale e l'APK di test condividono lo stesso percorso di classe. La build di Gradle genererà un errore se l'APK principale e l'APK di test utilizzano la stessa libreria (ad es. Guava), ma in versioni diverse. Se Gradle non lo riconosce, la tua app potrebbe comportarsi in modo diverso durante i test rispetto alla normale esecuzione (andando anche in crash in qualche caso).

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 

Soluzioni ai conflitti delle dipendenze

1. Lasciare che Gradle risolva le dipendenze per te

Questo approccio è il più semplice ma è limitato alle dipendenze nelle stesse configurazioni. Ad esempio, il tuo modulo dipende esplicitamente da una versione specifica di ExoPlayer. Tuttavia, l'SDK Audience Network include già un'altra versione di ExoPlayer. Per impostazione predefinita, viene inclusa nella build la versione più recente. Con lo snippet di codice sotto, l'output della sincronizzazione di Gradle indicherà chiaramente che questa aggiorna automaticamente la versione della libreria ExoPlayer da r2.4.2 a 2.7.3 nella build finale.

implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation 'com.facebook.android:audience-network-sdk:4.28.1' 

2. Escludere la versione specifica della dipendenza

Nella maggior parte dei casi, gli sviluppatori vogliono poter decidere quale versione della libreria sarà inclusa nella build finale. Sei autorizzato a configurare build.gradle affinché questo sia possibile. Ad esempio, se lo sviluppatore preferisce la versione precedente ExoPlayer r2.4.0 invece della r2.4.2 nell'SDK Audience Network, puoi escludere quel modulo dichiarando la dipendenza "audience-network-sdk". Il tag di esclusione si applica anche alle dipendenze in configurazioni diverse.

In un progetto reale, ci saranno molte dipendenze che avranno versioni diverse della stessa libreria. In quel caso, per ogni dipendenza dovrai applicare il tag di esclusione in modo da poter includere la versione prevista di quella libreria.

Scenario 1: dipendenze nella stessa configurazione
implementation 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation ('com.facebook.android:audience-network-sdk:4.28.1') {
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-core'
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-dash'
}
Scenario 2: dipendenze in configurazioni diverse
// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation ('org.mockito:mockito-core:1.10.19'){
    exclude group: 'org.hamcrest', module:'hamcrest-core'
}

3. Definire esplicitamente la libreria in conflitto in Gradle

Questo è un modo più semplice per risolvere il conflitto per dipendenze da configurazioni diverse. In questo caso, è necessario menzionare esplicitamente la versione della libreria da includere nella build finale per una qualsiasi delle configurazioni.

Si tratta di un approccio più semplice per la risoluzione dei conflitti, ma il lato negativo è che, mentre aggiorna le dipendenze effettive come junit e mockito, lo sviluppatore deve aggiornare anche la libreria in conflitto.

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 
// Explictly mention that include version 1.3 of org.hamcrest:hamcrest-core
androidTestCompile 'org.hamcrest:hamcrest-core:1.3' 

4. Forzare la risoluzione della libreria

Questo è un altro modo di risolvere il conflitto in cui, invece di dichiarare la dipendenza per una configurazione, la forziamo per tutte le configurazioni. Nell'esempio sotto, puoi aggiungere la tua "resolutionStrategy" al build.gradle a livello del modulo, così da imporre l'inclusione della versione specificata del pacchetto indipendentemente dal fatto che le dipendenze si trovino in configurazioni uguali o diverse.

Questo approccio deve essere usato con cautela. Nel nostro primo esempio, anche nel caso in cui audience-network-sdk venisse aggiornata e queste librerie aggiornassero la versione delle librerie exoplayer-core ed exoplayer-dash, sarebbe ugualmente necessario forzare l'uso di una versione precedente. Sebbene lo scenario sia valido anche per il secondo approccio risolutivo, in questo approccio forziamo la versione della dipendenza su tutte le configurazioni invece che su una singola configurazione.

Scenario 1: dipendenze nella stessa configurazione
android {
    configurations.all {
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
    }
}
Scenario 2: dipendenze in configurazioni diverse
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

Passaggi successivi

Altre risorse

Guida introduttiva

Guida tecnica per muovere i primi passi con Audience Network

Riferimento per l'API

Riferimento per l'SDK di Facebook per iOS