ניפוי באגים במקרים של שגיאות שקשורות לפתרון התלות

כשאתם מוסיפים יחסי תלות, יכול להיות שתתקלו בבעיות שקשורות ליחסי התלות שנדרשים ליחס התלות המקורי, ובהתנגשויות בין גרסאות שונות של יחסי התלות. כאן מוסבר איך לנתח את תרשים התלות ולפתור בעיות נפוצות שעשויות להתעורר.

הנחיות לתיקון שגיאות בפתרון יחסי התלות שכוללות לוגיקה מותאמת אישית של build מפורטות במאמר אסטרטגיות מותאמות אישית לפתרון יחסי תלות.

ניפוי באגים בשגיאות של פתרון יחסי התלות

ההנחיה הזו מבקשת עזרה בניפוי באגים של התנגשויות בין יחסי תלות.

מריצים את ההנחיה הזו ב-Android Studio כשהקובץ build.gradle פתוח.

I'm getting the following error in my build: Conflict with dependency. Resolved versions for runtime classpath and compile classpath differ. What changes do I need to make to my dependencies to resolve this error.

שימוש בהנחיות ל-AI

ההנחיות של AI מיועדות לשימוש ב-Gemini ב-Android Studio (נדרשת הגרסה העדכנית ביותר של Canary)

מידע נוסף על Gemini ב-Studio זמין בכתובת https://developer.android.com/studio/preview/gemini

הצגת יחסי התלות בין המודולים

לחלק מהתלויות הישירות יכולות להיות תלויות משלהם. יחסי התלות האלה נקראים יחסי תלות טרנזיטיביים. במקום לחייב אתכם להצהיר באופן ידני על כל יחסי התלות הטרנזיטיביים, Gradle אוסף אותם ומוסיף אותם בשבילכם באופן אוטומטי. הפלאגין של Android ל-Gradle מספק משימה שמציגה רשימה של יחסי התלות ש-Gradle פותר במודול נתון.

לכל מודול, הדוח גם מקבצ את יחסי התלות על סמך וריאנט ה-build, קבוצת מקורות הבדיקה ונתיב ה-classpath. הדוח הבא הוא דוגמה לדוח של classpath של מודול אפליקציה בסביבת זמן הריצה של גרסת build לניפוי באגים, ושל classpath של קבוצת מקורות הבדיקה המתווספים.

debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...

debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...

כדי להריץ את המשימה:

  1. בוחרים באפשרות תצוגה > חלונות כלים > Gradle (או לוחצים על Gradle בסרגל חלונות הכלים).
  2. מרחיבים את AppName > Tasks > android ולוחצים לחיצה כפולה על androidDependencies. אחרי ש-Gradle יבצע את המשימה, החלון Run אמור להיפתח כדי להציג את הפלט.

מידע נוסף על ניהול יחסי תלות ב-Gradle זמין בקטע יסודות של ניהול יחסי תלות במדריך למשתמש של Gradle.

החרגת יחסי תלות טרנזיטיביים

ככל שהיקף האפליקציה גדל, היא יכולה להכיל מספר יחסי תלות, כולל יחסי תלות ישירים ותלות טרנזיטיבית (ספריות שהספריות המיובאות של האפליקציה תלויות בהן). כדי להחריג יחסי תלות טרנזיטיביים שאתם כבר לא צריכים, תוכלו להשתמש במילות המפתח exclude כפי שמפורט בהמשך:

Kotlin

dependencies {
    implementation("some-library") {
        exclude(group = "com.example.imgtools", module = "native")
    }
}

Groovy

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

החרגת יחסי תלות טרנזיטיביים מהגדרות הבדיקה

אם אתם צריכים להחריג מהבדיקות יחסי תלות טרנזיטיביים מסוימים, יכול להיות שקוד הדוגמה שמוצג למעלה לא יפעל כצפוי. הסיבה לכך היא שהגדרת בדיקה (למשל, androidTestImplementation) מרחיב את ההגדרה של implementation של המודול. כלומר, הוא תמיד מכיל את יחסי התלות של implementation כש-Gradle פותר את ההגדרות.

לכן, כדי להחריג מהבדיקות יחסי תלות טרנזיטיביים, צריך לעשות זאת בזמן הביצוע, כפי שמתואר בהמשך:

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Groovy

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

הערה: עדיין אפשר להשתמש במילות המפתח exclude בבלוק יחסי התלות, כפי שמוצג בדוגמת הקוד המקורית בקטע החרגת יחסי תלות טרנזיטיביים כדי להשמיט יחסי תלות טרנזיטיביים שספציפיים להגדרת הבדיקה ולא נכללים בהגדרות אחרות.

תיקון שגיאות בפתרון יחסי התלות

כשמוסיפים כמה יחסי תלות לפרויקט האפליקציה, יכול להיות שיהיו התנגשויות בין יחסי התלות הישירים והעקיפים. הפלאגין של Android Gradle מנסה לפתור את ההתנגשויות האלה בצורה חלקה, אבל חלק מההתנגשויות עלולות להוביל לשגיאות בזמן הידור או בזמן ריצה.

כדי לבדוק אילו יחסי תלות גורמים לשגיאות, בודקים את עץ יחסי התלות של האפליקציה ומחפשים יחסי תלות שמופיעים יותר מפעם אחת או עם גרסאות סותרות.

אם אתם לא מצליחים לזהות בקלות את התלות הכפולה, תוכלו להשתמש בממשק המשתמש של Android Studio כדי לחפש יחסי תלות שכוללים את הכיתה הכפולה באופן הבא:

  1. בסרגל התפריטים, בוחרים באפשרות ניווט > כיתה.
  2. בתיבת הדו-שיח של החיפוש הקופץ, מוודאים שהתיבה שלצד הכללת פריטים שאינם קשורים לפרויקט מסומנת.
  3. מקלידים את שם הכיתה שמופיע בשגיאת ה-build.
  4. בודקים את התוצאות כדי למצוא את יחסי התלות שכוללים את הכיתה.

בקטעים הבאים מתוארים הסוגים השונים של שגיאות בפתרון יחסי התלות שעשויות להופיע, ואת הדרכים לפתרון שלהן.

תיקון שגיאות של כיתה כפולה

אם כיתה מופיעה יותר מפעם אחת ב-classpath של סביבת זמן הריצה, תופיע הודעת שגיאה דומה להודעה הבאה:

Program type already present com.example.MyClass

בדרך כלל השגיאה הזו מתרחשת באחת מהנסיבות הבאות:

  • תלות בינארית כוללת ספרייה שהאפליקציה כוללת גם כן כתלות ישירה. לדוגמה, האפליקציה מצהירה על תלות ישירה בספרייה א' ובספרייה ב', אבל ספרייה א' כבר כוללת את ספרייה ב' בקובץ הבינארי שלה.
    • כדי לפתור את הבעיה, מסירים את ספרייה ב' כיחס תלות ישיר.
  • לאפליקציה יש תלות בינארית מקומית ותלות בינארית מרוחקת באותה ספרייה.
    • כדי לפתור את הבעיה, מסירים את אחת מהתלות הבינאריות.

תיקון התנגשויות בין נתיבי classpath

כש-Gradle פותר את נתיב ה-classpath ל-compile, הוא קודם פותר את נתיב ה-classpath ל-runtime ומשתמש בתוצאה כדי לקבוע אילו גרסאות של יחסי התלות צריך להוסיף לנתיב ה-classpath ל-compile. במילים אחרות, נתיב ה-classpath בסביבת זמן הריצה קובע את מספרי הגרסאות הנדרשים ליחסי תלות זהים בנתיבי classpath במורד הזרם.

נתיב ה-classpath בסביבת זמן הריצה של האפליקציה קובע גם את מספרי הגרסאות שנדרשים ל-Gradle כדי להתאים את יחסי התלות בנתיב ה-classpath בסביבת זמן הריצה של קובץ ה-APK לבדיקה של האפליקציה. היררכיית נתיבי ה-Classpath מתוארת באיור 1.

איור 1. מספרי הגרסאות של יחסי התלות שמופיעים במספר נתיבי classpath חייבים להיות תואמים בהתאם להיררכיה הזו.

קונפליקט שבו גרסאות שונות של אותו יחסי תלות מופיעות בכמה נתיבי classpath עשוי להתרחש, למשל, אם האפליקציה כוללת גרסה של יחסי תלות באמצעות הגדרת יחסי התלות של implementation, ומודול ספרייה כולל גרסה אחרת של יחסי התלות באמצעות ההגדרה של runtimeOnly.

כשפותרים יחסי תלות בנתיבי ה-classpath של זמן הריצה וזמן הידור, הפלאגין של Android Gradle מגרסה 3.3.0 ואילך מנסה לתקן באופן אוטומטי התנגשויות מסוימות בגרסאות במורד הזרם. לדוגמה, אם נתיב הספריות בסביבת זמן הריצה כולל את ספרייה א' בגרסה 2.0, ונתיב הספריות בתהליך הידור כולל את ספרייה א' בגרסה 1.0, הפלאגין מעדכן באופן אוטומטי את התלות בנתיב הספריות בתהליך הידור לספרייה א' בגרסה 2.0 כדי למנוע שגיאות.

עם זאת, אם נתיב הספריות בסביבת זמן הריצה כולל את ספרייה א' בגרסה 1.0, ונתיב הספריות בתהליך הידור כולל את ספרייה א' בגרסה 2.0, הפלאגין לא משדרג לאחור את התלות בנתיב הספריות בתהליך הידור לספרייה א' בגרסה 1.0, ועדיין תופיע שגיאה דומה לזו:

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

כדי לפתור את הבעיה, מבצעים אחת מהפעולות הבאות:

  • כוללים את הגרסה הרצויה של התלות כיחס תלות api למודול הספרייה. כלומר, רק מודול הספרייה מכריז על התלות, אבל גם למודול האפליקציה תהיה גישה ל-API שלו, באופן טרנזיטיבי.
  • לחלופין, אפשר להצהיר על התלות בשני המודולים, אבל צריך לוודא שכל מודול משתמש באותה גרסה של התלות. מומלץ להגדיר מאפיינים ברמת הפרויקט כדי לוודא שהגרסאות של כל יחסי התלות יהיו עקביות בכל הפרויקט.