اشکال زدایی خطاهای تفکیک وابستگی

وقتی یک وابستگی اضافه می‌کنید، ممکن است با مشکلات مربوط به وابستگی‌های مورد نیاز وابستگی اصلی و تضاد بین نسخه‌های وابستگی مختلف مواجه شوید. در اینجا نحوه تجزیه و تحلیل نمودار وابستگی و رفع مشکلات رایجی که به وجود می آیند آورده شده است.

برای راهنمایی در مورد رفع خطاهای تفکیک وابستگی که شامل منطق ساخت سفارشی می‌شوند، به استراتژی‌های تفکیک وابستگی سفارشی مراجعه کنید.

مشاهده وابستگی های ماژول

برخی از وابستگی های مستقیم ممکن است وابستگی های خاص خود را داشته باشند. به این وابستگی های گذرا می گویند. Gradle به جای اینکه از شما بخواهد که هر وابستگی گذرا را به صورت دستی اعلام کنید، به طور خودکار آنها را جمع آوری و برای شما اضافه می کند. افزونه اندروید برای Gradle وظیفه ای را ارائه می دهد که لیستی از وابستگی هایی را که Gradle برای یک ماژول معین حل می کند، نمایش می دهد.

برای هر ماژول، گزارش همچنین وابستگی ها را بر اساس نوع ساخت، مجموعه منبع آزمایشی و مسیر کلاس گروه بندی می کند. در زیر گزارش نمونه ای از مسیر کلاس زمان اجرا یک ماژول برنامه از نوع ساخت اشکال زدایی آن و کامپایل مسیر کلاس مجموعه منبع آزمایش ابزاری آن است.

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. View > Tool Windows > Gradle را انتخاب کنید (یا روی Gradle کلیک کنید در نوار ابزار ویندوز).
  2. AppName > Tasks > android را باز کنید و روی androidDependencies دوبار کلیک کنید. پس از اجرای Gradle، پنجره Run باید برای نمایش خروجی باز شود.

برای اطلاعات بیشتر در مورد مدیریت وابستگی ها در Gradle، به اصول مدیریت وابستگی در راهنمای کاربر Gradle مراجعه کنید.

حذف وابستگی های گذرا

با افزایش دامنه برنامه، می‌تواند شامل تعدادی وابستگی از جمله وابستگی‌های مستقیم و وابستگی‌های گذرا باشد (کتابخانه‌هایی که کتابخانه‌های وارداتی برنامه شما به آنها وابسته هستند). برای حذف وابستگی‌های گذرا که دیگر به آن‌ها نیاز ندارید، می‌توانید از کلمه کلیدی exclude مانند زیر استفاده کنید:

کاتلین

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

شیار

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

وابستگی های گذرا را از پیکربندی های آزمایشی حذف کنید

اگر نیاز دارید که وابستگی‌های گذرا خاصی را از آزمایش‌های خود حذف کنید، نمونه کد نشان داده شده در بالا ممکن است آنطور که انتظار می‌رود کار نکند. دلیل آن این است که یک پیکربندی آزمایشی (مثلاً androidTestImplementation ) پیکربندی implementation ماژول را گسترش می‌دهد. به این معنا که وقتی Gradle پیکربندی را حل می کند، همیشه دارای وابستگی های implementation است.

بنابراین، برای حذف وابستگی های گذرا از تست های خود، باید این کار را در زمان اجرا مانند شکل زیر انجام دهید:

کاتلین

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

شیار

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

توجه: همچنان می‌توانید از کلمه کلیدی exclude در بلوک وابستگی‌ها همانطور که در نمونه کد اصلی از بخش Exclude transitive dependencies نشان داده شده است استفاده کنید تا وابستگی‌های متعدی را که مخصوص پیکربندی آزمایشی هستند و در پیکربندی‌های دیگر گنجانده نشده‌اند حذف کنید.

رفع خطاهای تفکیک وابستگی

وقتی چند وابستگی را به پروژه برنامه خود اضافه می کنید، این وابستگی های مستقیم و گذرا ممکن است با یکدیگر تضاد داشته باشند. پلاگین Android Gradle سعی می کند این تضادها را به خوبی حل کند، اما برخی از تداخل ها ممکن است منجر به خطاهای زمان کامپایل یا زمان اجرا شود.

برای کمک به بررسی وابستگی‌هایی که در ایجاد خطا نقش دارند، درخت وابستگی برنامه‌تان را بررسی کنید و به دنبال وابستگی‌هایی باشید که بیش از یک بار یا با نسخه‌های متناقض ظاهر می‌شوند.

اگر نمی‌توانید به راحتی وابستگی تکراری را شناسایی کنید، سعی کنید از رابط کاربری Android Studio برای جستجوی وابستگی‌هایی که شامل کلاس تکراری هستند استفاده کنید:

  1. Navigate > Class را از نوار منو انتخاب کنید.
  2. در گفتگوی جستجوی پاپ آپ، مطمئن شوید که کادر کنار شامل موارد غیر پروژه علامت زده شده باشد.
  3. نام کلاسی که در خطای ساخت ظاهر می شود را تایپ کنید.
  4. نتایج را برای وابستگی هایی که کلاس را شامل می شود بررسی کنید.

بخش‌های زیر انواع مختلفی از خطاهای تفکیک وابستگی را که ممکن است با آن‌ها مواجه شوید و نحوه رفع آن‌ها شرح می‌دهد.

رفع خطاهای کلاس تکراری

اگر یک کلاس بیش از یک بار در مسیر کلاس اجرا ظاهر شود، با خطای مشابه زیر مواجه می شوید:

Program type already present com.example.MyClass

این خطا معمولاً به دلیل یکی از شرایط زیر رخ می دهد:

  • یک وابستگی باینری شامل کتابخانه ای است که برنامه شما نیز به عنوان وابستگی مستقیم شامل آن می شود. به عنوان مثال، برنامه شما وابستگی مستقیم به کتابخانه A و کتابخانه B را اعلام می کند، اما کتابخانه A قبلاً کتابخانه B را در باینری خود دارد.
    • برای حل این مشکل ، کتابخانه B را به عنوان یک وابستگی مستقیم حذف کنید.
  • برنامه شما یک وابستگی باینری محلی و یک وابستگی باینری راه دور به همان کتابخانه دارد.
    • برای حل این مشکل ، یکی از وابستگی های باینری را حذف کنید.

تضاد بین مسیرهای کلاس را برطرف کنید

هنگامی که Gradle مسیر کلاس کامپایل را حل می کند، ابتدا مسیر کلاسی زمان اجرا را حل می کند و از نتیجه برای تعیین اینکه چه نسخه هایی از وابستگی ها باید به مسیر کلاس کامپایل اضافه شوند، استفاده می کند. به عبارت دیگر، مسیر کلاس زمان اجرا، شماره نسخه های مورد نیاز را برای وابستگی های یکسان در مسیرهای کلاس پایین دست تعیین می کند.

مسیر کلاس زمان اجرا برنامه شما همچنین شماره نسخه‌هایی را که Gradle برای مطابقت وابستگی‌ها در مسیر کلاس زمان اجرا برای APK آزمایشی برنامه نیاز دارد، تعیین می‌کند. سلسله مراتب مسیرهای کلاس در شکل 1 توضیح داده شده است.

شکل 1. تعداد نسخه‌های وابستگی که در چندین مسیر کلاس ظاهر می‌شوند باید مطابق این سلسله مراتب مطابقت داشته باشند.

تداخلی که در آن نسخه‌های مختلف وابستگی یکسان در چندین مسیر کلاس ظاهر می‌شود، ممکن است زمانی رخ دهد که، برای مثال، برنامه شما دارای نسخه‌ای از یک وابستگی با استفاده از پیکربندی وابستگی implementation و یک ماژول کتابخانه شامل نسخه متفاوتی از وابستگی با استفاده از پیکربندی runtimeOnly باشد.

هنگام حل وابستگی‌ها به زمان اجرا و مسیرهای کلاسی زمان کامپایل، افزونه Android Gradle نسخه 3.3.0 و بالاتر تلاش می‌کند تا به‌طور خودکار برخی تضادهای نسخه پایین‌دستی را برطرف کند. به عنوان مثال، اگر مسیر کلاسی زمان اجرا شامل Library A نسخه 2.0 و مسیر کلاس کامپایل شامل Library A نسخه 1.0 باشد، افزونه به طور خودکار وابستگی به مسیر کلاس کامپایل را به کتابخانه A نسخه 2.0 به روز می کند تا از خطا جلوگیری کند.

با این حال، اگر مسیر کلاس زمان اجرا شامل Library A نسخه 1.0 و مسیر کلاس کامپایل شامل Library A نسخه 2.0 باشد، این افزونه وابستگی به مسیر کلاس کامپایل را به Library A نسخه 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 خود دسترسی خواهد داشت.
  • همچنین، می‌توانید وابستگی را در هر دو ماژول اعلام کنید، اما باید مطمئن شوید که هر ماژول از نسخه یکسانی از وابستگی استفاده می‌کند. پیکربندی ویژگی‌های کل پروژه را در نظر بگیرید تا مطمئن شوید که نسخه‌های هر وابستگی در طول پروژه شما ثابت می‌مانند.