حزمة إعادة التعبئة في الدرج

في مقالتي أريد أن أتحدث عن خدعة أخرى يمكن تنفيذها بسهولة شديدة باستخدام حزم مكتبة إعادة ضبط Gradle. يعلم كل من عمل قليلاً مع نظام الإنشاء هذا أنه يمكنه حل تعارضات الإصدارات المختلفة من المكتبات تلقائيًا ، وإذا كنت ترغب في ذلك ، فيمكنك التأثير على هذا ، على سبيل المثال ، لإصلاح إصدار محدد من المكتبة:


configurations.all { resolutionStrategy { force "org.ow2.asm:asm:7.2" } } 

لسوء الحظ ، هذا لا يساعد دائمًا في حل مشكلة تعارض الإصدار. على سبيل المثال ، هناك مشكلة معروفة في أن بعض أجهزة htc الموجودة في البرنامج الثابت لديها بالفعل مكتبة gson ، وإذا كان إصدار gson لديك يختلف عن الإصدار المدمج ، فقد تحدث مشكلات ، لأن ClassLoader سيقوم بتحميل فئة واحدة فقط في الذاكرة ، وفي هذه الحالة سيكون نظامًا واحدًا.


يمكن أن تحدث هذه المشكلة أيضًا عند تطوير المكتبات. إذا قمت بتوصيل مكتبتين بمشروعك الذي يستخدم نفس مكتبة الجهة الخارجية ذات الإصدارات المختلفة ، على سبيل المثال 1 و 2 ، فسيحل Gradle وسيأخذ الإصدار الأحدث ، الثاني. ولكن إذا لم يكن هناك توافق مع الإصدارات السابقة في مكتبة الطرف الثالث هذه ولا يمكن استخدام الإصدار الثاني فقط بدلاً من الإصدار الأول ، فستكون هناك مشكلات سيكون من الصعب للغاية تتبعها بالتتبع. ستتلقى مكتبة في انتظار الإصدار الأول الفصول الثانية وتعطل فقط.


لقد واجهت تعارضًا في الإصدار عند كتابة ملحق grad ، فإنه يستخدم مكتبة asm ، التي تتعارض. بعد كتابة المكوّن الإضافي ، قمت بفحص أدائه في مشروع اختبار: كل شيء على ما يرام ، ودقق في مشروع حيوان أليف ، كل شيء على ما يرام ، ولكن عندما قمت بتوصيله بمشروع عمل حقيقي مع مجموعة من تبعيات الطرف الثالث ، واجهت مشكلة.



الحل لمشكلة تحت الخفض.


ومع ذلك نجحت ، ما الخطأ الذي حدث؟


حصلنا على تتبع الخطأ الكامل:



نرى أن الخطأ في مُنشئ مكتبة ClassVisitor asm موجود على السطر 79. دعونا ننظر هناك ، ولكن عند محاولة فتح ClassVisitor ، عرض الاستوديو خيارين



يستخدم المكون الإضافي الخاص بي asm الإصدار 7.2 ، لذلك نذهب إلى هناك وعلى السطر 79 نرى ما يلي:



من الواضح أن هذا ليس ما نحتاجه. انتقل الآن إلى الإصدار 6 من ClassVisitor :



فقط لدينا IllegalArgumentException دون رسالة. يستخدم المكون الإضافي الخاص بي إصدار ASM api 7 من Opcodes.ASM7 ، وفي الإصدار 6 من المكتبة لا توجد هذه api بعد ، لذلك ، IllegalArgumentException في المنشئ. يمكننا أن نستنتج أن البرنامج المساعد يتلقى نسخة غير صحيحة من المكتبة.


السؤال القمامة ، فكرت ، وفعلت هذا:


 configurations.all { resolutionStrategy { force "org.ow2.asm:asm:7.2" } } 

يؤسفني أن هذا لم يكن له أي تأثير على الإطلاق. ما زلت لا أستطيع معرفة السبب الدقيق لعدم إمكانية استبدال إصدار asm ، على الرغم من أن ./gradlew app:dependencies الأمر يوضح أنه تم استبدال الإصدار بـ 7.2. إذا كان لدى شخص ما أفكار أو افتراضات ، سأكون سعيدًا لسماع رأي.


يجب حل المشكلة بطريقة ما


بدأت سلسلة من غوغل وتعميق في عمل البرد. نتيجة لذلك ، ذهبت إلى موقع asm على الويب ، وربما كانوا يعرفون شيئًا عن هذا. اتضح أنهم كانوا يعرفون حقًا أن إجابة سؤالي كانت في قسم الأسئلة الشائعة. يقولون ليحلوا محل حزمة asm مع آخر ، حتى أنها توفر أداة مساعدة لهذا الغرض. حسنا ، دعنا نحاول. تحتاج فقط إلى توصيل المكون الإضافي وإعداد القليل من الإعداد:


 apply plugin: 'org.anarres.jarjar' ... dependencies { implementation fileTree(dir: 'build/jarjar', include: ['*.jar']) implementation jarjar.repackage('asm') { from 'org.ow2.asm:asm:7.2' classRename "org.objectweb.asm.**", "stater.org.objectweb.asm.@1" } } 

build/jarjar في هذه الحالة ، الدليل الذي سيتم إنشاء ملف جرة مكتبة asm مع الحزم المعاد fileTree ، لذلك تحتاج إلى فتح وصول التبعية إلى هذا الدليل عبر fileTree . ستكون المكتبة متاحة الآن مع استيراد stater.org.objectweb.asm.* بدلاً من org.objectweb.asm.* . يحتوي هذا المكون الإضافي على إعدادات مختلفة ، ولكن في مثالي ، كان مجرد تغيير الحزم كافٍ.


بعد ذلك ، انتقل من خلال المشروع بالكامل وتغيير الاستيراد في كل مكان من org.objectweb.asm إلى
stater.org.objectweb.asm . في رأيي ، أداة مريحة للغاية ، وأسهل من القيام بذلك يدويًا عدة مرات ، خاصة عند تحديث المكتبة ، from 'org.ow2.asm:asm:7.2' فقط from 'org.ow2.asm:asm:7.2' إلى الإصدار الجديد وسيتم إنشاء لقب جرة معاد from 'org.ow2.asm:asm:7.2' مع الإصدار الجديد آلة أوتوماتيكية.


إذا كان لديك مشروع (وليس مكتبة) ، فسيكون هذا كافياً لحل النزاعات غير القابلة للذوبان ، مثل gson المذكورة في بداية المقال. لكن إذا كنت ، مثلي ، تكتب مكتبة ، فهذا ليس كل شيء.


لقد حللنا مشكلة إعادة التعبئة ، لكن الآن asm متصل بالمشروع ليس من خلال التبعية على مستودع maven البعيد ، ولكن من خلال ملف jar المحلي ، والذي سوف يتم فقده ببساطة عند نشر مكتبتك وسيكون هناك خطأ NoClassDefFoundError . ولكن هذه المشكلة بسيطة للغاية لحلها:


  1. في ملف gradle الخاص بنا ، قم بإنشاء تكوين جديد:


     configurations { extraLibs implementation.extendsFrom(extraLibs) } 

  2. التالي نغير


     implementation fileTree(dir: 'build/jarjar', include: ['*.jar']) 

    في


     extraLibs fileTree(dir: 'build/jarjar', include: ['*.jar']) 

  3. أعد تحديد المهمة المسؤولة عن جمع ملف الجرة النهائي الخاص بك وكتابة جميع المكتبات بتكويننا الجديد في لقب الجرة النهائي:


     jar { from { configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) } } } 


هذا كل شيء ، قم بنشر المكون الإضافي لدينا كما كان من قبل ، اتصل بالمشروع حيث كانت هناك تعارضات غير قابلة للحل وكل شيء يعمل بشكل جيد.
إعادة التغليف هذه تجعل مكتبتنا أكثر تحملاً للأخطاء عند الاتصال بأنواع مختلفة من المشاريع مع مكتبات أخرى.


وإذا قمت فقط بتوصيل ملف jar الخاص بالمكتبة المتعارضة بالبرنامج المساعد دون إعادة تغليفه؟


فكرة سيئة ، لن تؤدي إلى أي شيء جيد. في عملية بناء المشروع ، هناك مهمة شيقة check...DuplicateClasses ، والتي تقوم ببساطة بقص الملفات بنفس الحزم. أي الملفات التي تم الحصول عليها من ملف jar الخاص بالمكتبة المتصلة والملفات من نفس المكتبة المتصلة من خلال مستودع التخزين البعيد. ستكون النتيجة هي هذا الخطأ:



هذا كل شيء. شكرا لكل من قرأ!


تولسا لإعادة حزم
مثال المساعد

Source: https://habr.com/ru/post/ar472002/


All Articles