بهینه سازی برای نویسندگان کتابخانه

به عنوان یک نویسنده کتابخانه، باید مطمئن شوید که توسعه دهندگان برنامه می توانند به راحتی کتابخانه شما را در برنامه خود بگنجانند و در عین حال تجربه کاربر نهایی با کیفیت بالا را حفظ کنند. باید مطمئن شوید که کتابخانه شما بدون راه‌اندازی اضافی با بهینه‌سازی Android سازگار است - یا سندی مبنی بر اینکه کتابخانه ممکن است برای استفاده در Android نامناسب باشد.

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

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

از کدژن بر روی بازتاب استفاده کنید

در صورت امکان، از تولید کد ( کدژن ) بر روی بازتاب استفاده کنید. کدژن و انعکاس هر دو رویکردهای رایج برای جلوگیری از کد دیگ بخار در هنگام برنامه نویسی هستند، اما کدژن با بهینه ساز برنامه مانند R8 سازگارتر است:

  • با کدژن، کد در طول فرآیند ساخت، تجزیه و تحلیل و اصلاح می شود. از آنجایی که پس از زمان کامپایل هیچ تغییر عمده‌ای وجود ندارد، بهینه‌ساز می‌داند که در نهایت به چه کدی نیاز است و چه چیزی را می‌توان با خیال راحت حذف کرد.
  • با بازتاب، کد در زمان اجرا تجزیه و تحلیل و دستکاری می شود. از آنجایی که کد تا زمانی که اجرا نشود واقعاً نهایی نمی شود، بهینه ساز نمی داند چه کدی را می توان با خیال راحت حذف کرد. احتمالاً کدهایی را که به صورت پویا از طریق بازتاب در زمان اجرا استفاده می‌شوند، حذف می‌کند، که باعث خرابی برنامه برای کاربران می‌شود.

بسیاری از کتابخانه های مدرن به جای بازتاب از کدژن استفاده می کنند. KSP را برای یک ورودی مشترک که توسط Room ، Dagger2 و بسیاری دیگر استفاده می‌شود، ببینید.

وقتی انعکاس مشکلی نداره

اگر باید از بازتاب استفاده کنید، فقط باید به یکی از موارد زیر فکر کنید:

  • انواع هدفمند خاص (پیاده‌کننده‌های رابط یا زیر کلاس‌های خاص)
  • کد با استفاده از یک حاشیه نویسی زمان اجرا خاص

استفاده از بازتاب در این روش هزینه زمان اجرا را محدود می کند و نوشتن قوانین حفظ مشتری هدفمند را امکان پذیر می کند.

این شکل خاص و هدفمند انعکاس، الگویی است که می‌توانید هم در چارچوب Android (مثلاً هنگام افزایش فعالیت‌ها، نماها و نقشه‌ها) و هم در کتابخانه‌های AndroidX (به عنوان مثال هنگام ساخت WorkManager ListenableWorkers یا RoomDatabases) مشاهده کنید. در مقابل، بازتاب باز Gson برای استفاده در برنامه‌های Android مناسب نیست .

قوانین حفظ مصرف کننده را بنویسید

کتابخانه‌ها باید قوانین نگهداری «مصرف‌کننده» را بسته‌بندی کنند، که از همان قالب قوانین نگهداری برنامه استفاده می‌کنند. این قوانین در مصنوعات کتابخانه (AAR یا JAR) قرار می‌گیرند و در هنگام بهینه‌سازی برنامه Android در هنگام استفاده از کتابخانه، به‌طور خودکار مصرف می‌شوند.

کتابخانه های AAR

برای افزودن قوانین مصرف کننده برای یک کتابخانه AAR، از گزینه consumerProguardFiles در اسکریپت ساخت ماژول کتابخانه Android استفاده کنید. برای اطلاعات بیشتر، به راهنمای ما در مورد ایجاد ماژول های کتابخانه مراجعه کنید.

کاتلین

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

شیار

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

کتابخانه های JAR

برای بسته‌بندی قوانین با کتابخانه Kotlin/Java خود که به صورت JAR ارسال می‌شود، فایل قوانین خود را با هر نام فایلی در فهرست نهایی META-INF/proguard/ JAR قرار دهید. به عنوان مثال، اگر کد شما در <libraryroot>/src/main/kotlin ، یک فایل قوانین مصرف کننده را در <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro قرار دهید و قوانین در مکان صحیح در JAR خروجی شما قرار می گیرند.

با بررسی اینکه قوانین در دایرکتوری META-INF/proguard قرار دارند، بررسی کنید که قوانین بسته‌بندی نهایی JAR به درستی انجام می‌شود.

بهینه سازی ساخت کتابخانه AAR (پیشرفته)

به طور کلی، شما نباید ساخت کتابخانه را مستقیماً بهینه کنید زیرا بهینه سازی های ممکن در زمان ساخت کتابخانه بسیار محدود است. تنها در طول ساخت برنامه، زمانی که یک کتابخانه به عنوان بخشی از یک برنامه کاربردی گنجانده می شود، R8 می تواند بداند که چگونه از تمام روش های کتابخانه استفاده می شود، و کدام پارامترها ارسال می شوند. به‌عنوان یک توسعه‌دهنده کتابخانه، قبل از بهینه‌سازی کتابخانه، باید در مورد مراحل متعدد بهینه‌سازی و حفظ رفتار، هم در زمان ساخت کتابخانه و هم در زمان ساخت برنامه، استدلال کنید.

اگر همچنان می‌خواهید کتابخانه خود را در زمان ساخت بهینه کنید، این افزونه توسط Android Gradle پشتیبانی می‌شود.

کاتلین

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        configureEach {
            consumerProguardFiles("consumer-rules.pro")
        }
    }
}

شیار

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles
                getDefaultProguardFile('proguard-android-optimize.txt'),
                'proguard-rules.pro'
        }
        configureEach {
            consumerProguardFiles "consumer-rules.pro"
        }
    }
}

توجه داشته باشید که رفتار proguardFiles بسیار متفاوت از consumerProguardFiles است:

  • proguardFiles در زمان ساخت، اغلب همراه با getDefaultProguardFile("proguard-android-optimize.txt") استفاده می شود، تا مشخص کند کدام قسمت از کتابخانه شما باید در طول ساخت کتابخانه نگهداری شود. حداقل، این API عمومی شماست.
  • consumerProguardFiles در مقابل در کتابخانه بسته بندی می شود تا بر روی بهینه سازی هایی که بعداً در طول ساخت برنامه ای که کتابخانه شما را مصرف می کند تأثیر بگذارد.

برای مثال، اگر کتابخانه شما از بازتاب برای ساخت کلاس‌های داخلی استفاده می‌کند، ممکن است لازم باشد قوانین keep را هم در proguardFiles و هم consumerProguardFiles تعریف کنید.

اگر از -repackageclasses در ساخت کتابخانه خود استفاده می کنید، کلاس ها را به یک بسته فرعی در داخل بسته کتابخانه خود بسته بندی کنید. برای مثال، از -repackageclasses 'com.example.mylibrary.internal' به جای -repackageclasses 'internal' استفاده کنید.

پشتیبانی از کوچک کننده های مختلف (پیشرفته)

می‌توانید قوانینی را برای کوچک‌کننده‌های خاص (R8 یا ProGuard) و همچنین نسخه‌های کوچک‌کننده خاص تنظیم کنید. این کار کتابخانه شما را قادر می‌سازد تا در پروژه‌هایی که از نسخه‌های کوچک‌کننده جدید استفاده می‌کنند، بهینه کار کند، در حالی که اجازه می‌دهد از قوانین موجود در پروژه‌هایی با نسخه‌های کوچک‌کننده قدیمی‌تر استفاده شود.

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

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

این بدان معناست که قوانین کوچک کردن هدفمند در فهرست META-INF/com.android.tools یک JAR یا در فهرست META-INF/com.android.tools داخل classes.jar یک AAR ذخیره می‌شوند.

در زیر آن دایرکتوری، می‌توان چندین دایرکتوری با نام‌هایی به شکل r8-from-<X>-upto-<Y> یا proguard-from-<X>-upto-<Y> وجود داشته باشد تا مشخص شود قوانین داخل دایرکتوری‌ها برای کدام نسخه کوچک‌کننده نوشته شده‌اند. توجه داشته باشید که قسمت های - from-<X> و - upto-<Y> اختیاری هستند، نسخه <Y> انحصاری است و محدوده های نسخه باید پیوسته باشند.

برای مثال، r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0 و r8-from-8.2.0 مجموعه معتبری از قوانین کوچک کردن هدفمند را تشکیل می دهند. قوانین تحت پوشه r8-from-8.0.0-upto-8.2.0 توسط R8 از نسخه 8.0.0 تا نسخه 8.0.0 استفاده می شود، اما شامل نسخه 8.2.0 نمی شود .

با توجه به این اطلاعات، افزونه Android Gradle قوانین را از فهرست های R8 منطبق انتخاب می کند. اگر یک کتابخانه قوانین کوچک کردن هدفمند را مشخص نکند، افزونه Android Gradle قوانین را از مکان‌های قدیمی انتخاب می‌کند ( proguard.txt برای AAR یا META-INF/proguard/<ProGuard-rules-file> برای JAR).