احتیاط: از آگوست 2021، همه برنامههای جدید باید بهعنوان App Bundle منتشر شوند. اگر برنامه خود را در Google Play منتشر میکنید، یک Android App Bundle بسازید و آپلود کنید. وقتی این کار را انجام میدهید، Google Play بهطور خودکار فایلهای APK بهینهشده را برای پیکربندی دستگاه هر کاربر تولید و ارائه میکند، بنابراین آنها فقط کد و منابعی را که برای اجرای برنامه شما نیاز دارند دانلود میکنند. اگر در فروشگاهی منتشر می کنید که قالب AAB را پشتیبانی نمی کند، انتشار چندین APK مفید است. در این صورت، باید هر APK را خودتان بسازید، امضا کنید و مدیریت کنید.
اگرچه بهتر است هر زمان که امکان دارد یک APK واحد بسازید تا از همه دستگاههای مورد نظر خود پشتیبانی کند، اما به دلیل پشتیبانی فایلهایی که از چند تراکم صفحه یا رابطهای باینری برنامه (ABI) پشتیبانی میکنند، ممکن است یک APK بسیار بزرگ ایجاد کنید. یکی از راههای کاهش اندازه APK، ایجاد چندین APK است که حاوی فایلهایی برای تراکم صفحه نمایش یا ABIهای خاص هستند.
Gradle میتواند فایلهای APK جداگانه ایجاد کند که فقط حاوی کد و منابع خاص برای هر تراکم یا ABI هستند. این صفحه نحوه پیکربندی ساخت خود را برای تولید چندین APK توضیح میدهد. اگر میخواهید نسخههای مختلفی از برنامه خود را ایجاد کنید که بر اساس تراکم صفحه یا ABI نیستند، به جای آن از انواع ساخت استفاده کنید.
ساخت خود را برای چندین APK پیکربندی کنید
برای پیکربندی ساخت خود برای چندین APK، یک بلوک splits
به فایل build.gradle
در سطح ماژول خود اضافه کنید. در بلوک splits
، یک بلوک density
ارائه کنید که مشخص میکند چگونه میخواهید Gradle فایلهای APK با تراکم تولید کند یا یک بلوک abi
که مشخص میکند چگونه میخواهید Gradle فایلهای APK در هر ABI را تولید کند. شما می توانید هر دو بلوک تراکم و ABI را ارائه دهید و سیستم ساخت یک APK برای هر تراکم و ترکیب ABI ایجاد می کند.
چندین APK را برای تراکم صفحه پیکربندی کنید
برای ایجاد فایلهای APK مجزا برای تراکمهای صفحهنمایش مختلف، یک بلوک density
داخل بلوک splits
خود اضافه کنید. در بلوک density
خود، فهرستی از تراکم صفحه نمایش دلخواه و اندازه صفحه نمایش سازگار را ارائه دهید. فقط در صورتی از فهرست اندازههای صفحه سازگار استفاده کنید که به عناصر <compatible-screens>
خاصی در مانیفست هر APK نیاز دارید.
گزینه های Gradle DSL زیر برای پیکربندی چندین APK برای تراکم صفحه استفاده می شود:
-
enable
برای Groovy، برای اسکریپت KotlinisEnable
- اگر این عنصر را روی
true
تنظیم کنید، Gradle چندین APK را بر اساس تراکم صفحهای که شما تعریف میکنید تولید میکند. مقدار پیش فرضfalse
است. -
exclude
- فهرستی از تراکمهای جدا شده با کاما را مشخص میکند که نمیخواهید Gradle فایلهای APK جداگانه برای آنها ایجاد کند. اگر میخواهید برای بیشتر تراکمها فایلهای APK ایجاد کنید، اما باید چند تراکم را که برنامه شما پشتیبانی نمیکند حذف کنید، از
exclude
استفاده کنید. -
reset()
لیست پیش فرض تراکم صفحه نمایش را پاک می کند. فقط زمانی استفاده کنید که با عنصر
include
ترکیب شود تا چگالی هایی را که می خواهید اضافه کنید مشخص کنید.قطعه زیر لیست چگالی ها را با فراخوانی
reset()
برای پاک کردن لیست و سپس با استفاده ازinclude
رویldpi
وxxhdpi
تنظیم می کند:reset() // Clears the default list from all densities // to no densities. include "ldpi", "xxhdpi" // Specifies the two densities to generate APKs // for.
-
include
- فهرستی از تراکمهای جدا شده با کاما را مشخص میکند که میخواهید Gradle فایلهای APK را برای آنها تولید کند. فقط در ترکیب با
reset()
برای مشخص کردن لیست دقیقی از چگالی استفاده کنید. -
compatibleScreens
فهرستی از اندازه های صفحه سازگار با کاما را مشخص می کند. این یک گره
<compatible-screens>
منطبق را در مانیفست برای هر APK تزریق می کند.این تنظیم راهی مناسب برای مدیریت تراکم و اندازه صفحه نمایش در یک بخش
build.gradle
فراهم می کند. با این حال، استفاده از<compatible-screens>
می تواند انواع دستگاهی را که برنامه شما با آن کار می کند محدود کند. برای روشهای جایگزین برای پشتیبانی از اندازههای مختلف صفحه، به نمای کلی سازگاری صفحهنمایش مراجعه کنید.
از آنجا که هر APK مبتنی بر تراکم صفحه شامل یک برچسب <compatible-screens>
با محدودیتهای خاص در مورد نوع صفحهنمایش پشتیبانیشده APK است—حتی اگر چندین APK منتشر کنید—برخی دستگاههای جدید با فیلترهای APK متعدد شما مطابقت ندارند. به این ترتیب، Gradle همیشه یک APK جهانی اضافی ایجاد میکند که حاوی داراییهایی برای همه تراکمهای صفحه است و شامل برچسب <compatible-screens>
نمیشود. این APK جهانی را به همراه فایلهای APK با تراکم خود منتشر کنید تا برای دستگاههایی که با برچسب <compatible-screens>
با APK مطابقت ندارند، نسخهای جایگزین ارائه کنید.
مثال زیر یک APK جداگانه برای هر تراکم صفحه به جز ldpi
، xxhdpi
و xxxhdpi
ایجاد میکند. این کار با استفاده از exclude
برای حذف آن سه تراکم از لیست پیشفرض همه تراکمها انجام میشود.
شیار
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. enable true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" // Specifies a list of compatible screen size settings for the manifest. compatibleScreens 'small', 'normal', 'large', 'xlarge' } } }
کاتلین
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. isEnable = true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude("ldpi", "xxhdpi", "xxxhdpi") // Specifies a list of compatible screen size settings for the manifest. compatibleScreens("small", "normal", "large", "xlarge") } } }
برای جزئیات بیشتر در مورد سفارشی کردن انواع مختلف ساخت برنامه خود برای انواع صفحه نمایش و دستگاه های خاص، به اعلام پشتیبانی صفحه نمایش محدود شده مراجعه کنید.
چندین APK را برای ABI پیکربندی کنید
برای ایجاد APK جداگانه برای ABI های مختلف، یک بلوک abi
را در بلوک splits
خود اضافه کنید. در بلوک abi
خود، فهرستی از ABI های مورد نظر را ارائه دهید.
گزینه های Gradle DSL زیر برای پیکربندی چندین APK در هر ABI استفاده می شود:
- برای Groovy یا برای اسکریپت کاتلین
isEnable
enable
- اگر این عنصر را روی
true
تنظیم کنید، Gradle چندین APK را بر اساس ABI هایی که شما تعریف کرده اید تولید می کند. مقدار پیش فرضfalse
است. -
exclude
- فهرستی از ABIهای جدا شده با کاما را مشخص میکند که نمیخواهید Gradle فایلهای APK جداگانه برای آنها ایجاد کند. اگر میخواهید برای بیشتر ABIها APK ایجاد کنید،
exclude
استفاده کنید، اما باید چند ABI را که برنامه شما پشتیبانی نمیکند حذف کنید. -
reset()
لیست پیش فرض ABI ها را پاک می کند. فقط زمانی استفاده کنید که با عنصر
include
ترکیب شود تا ABI هایی را که می خواهید اضافه کنید مشخص کنید.قطعه زیر با فراخوانی
reset()
برای پاک کردن لیست، لیست ABI ها را فقط بهx86
وx86_64
تنظیم می کند و سپس ازinclude
استفاده می کند:reset() // Clears the default list from all ABIs to no ABIs. include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.
-
include
- فهرستی از ABI های جدا شده با کاما را مشخص می کند که می خواهید Gradle برای آنها APK ایجاد کند. فقط در ترکیب با
reset()
برای تعیین لیست دقیق ABI ها استفاده کنید. -
universalApk
برای Groovy یاisUniversalApk
برای اسکریپت Kotlin اگر
true
، Gradle یک APK جهانی علاوه بر APKهای هر ABI ایجاد میکند. یک APK جهانی حاوی کد و منابع برای همه ABI ها در یک APK واحد است. مقدار پیش فرضfalse
است.توجه داشته باشید که این گزینه فقط در بلوک
splits.abi
موجود است. هنگام ساخت چندین APK بر اساس تراکم صفحه، Gradle همیشه یک APK جهانی تولید میکند که حاوی کد و منابع برای همه تراکمهای صفحه است.
مثال زیر یک APK جداگانه برای هر ABI ایجاد می کند: x86
و x86_64
. این کار با استفاده از reset()
برای شروع با یک لیست خالی از ABI ها، به دنبال include
لیستی از ABI ها که هر کدام یک APK دریافت می کنند، انجام می شود.
شیار
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include "x86", "x86_64" // Specifies that you don't want to also generate a universal APK that includes all ABIs. universalApk false } } }
کاتلین
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. isEnable = true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include("x86", "x86_64") // Specifies that you don't want to also generate a universal APK that includes all ABIs. isUniversalApk = false } } }
برای فهرستی از ABI های پشتیبانی شده، ABI های پشتیبانی شده را ببینید.
پروژه های بدون کد Native/C++
برای پروژههای بدون کد Native/C++، پنل Build Variants دارای دو ستون است: Module و Active Build Variant ، همانطور که در شکل 1 نشان داده شده است.
شکل 1. پانل Build Variants دارای دو ستون برای پروژه های بدون کد Native/C++ است.
مقدار Active Build Variant برای ماژول، نوع ساختی را که در ویرایشگر مستقر و قابل مشاهده است، تعیین می کند. برای جابجایی بین انواع، روی سلول Active Build Variant برای یک ماژول کلیک کنید و نوع مورد نظر را از قسمت لیست انتخاب کنید.
پروژه هایی با کد Native/C++
برای پروژههایی با کد Native/C++، پنل Build Variants دارای سه ستون است: Module ، Active Build Variant و Active ABI ، همانطور که در شکل 2 نشان داده شده است.
شکل 2. پنل Build Variants ستون Active ABI را برای پروژه هایی با کد Native/C++ اضافه می کند.
مقدار Active Build Variant برای ماژول، نوع ساختی را تعیین می کند که مستقر شده و در ویرایشگر قابل مشاهده است. برای ماژولهای بومی، مقدار Active ABI ABI مورد استفاده ویرایشگر را تعیین میکند، اما بر آنچه که مستقر میشود تأثیری نمیگذارد.
برای تغییر نوع ساخت یا ABI:
- روی سلول مربوط به ستون Active Build Variant یا Active ABI کلیک کنید.
- نوع مورد نظر یا ABI را از قسمت لیست انتخاب کنید. یک همگام سازی جدید به طور خودکار اجرا می شود.
تغییر هر یک از ستون ها برای یک برنامه یا ماژول کتابخانه، این تغییر را در تمام ردیف های وابسته اعمال می کند.
پیکربندی نسخه
به طور پیشفرض، وقتی Gradle چندین APK تولید میکند، هر APK همان اطلاعات نسخه را دارد، همانطور که در فایل build.gradle
یا build.gradle.kts
در سطح ماژول مشخص شده است. از آنجایی که فروشگاه Google Play چندین APK را برای یک برنامه که همه اطلاعات نسخه یکسانی دارند، مجاز نمیداند، قبل از آپلود در فروشگاه Play باید مطمئن شوید که هر APK یک versionCode
منحصر به فرد دارد.
میتوانید فایل build.gradle
در سطح ماژول خود را پیکربندی کنید تا versionCode
برای هر APK لغو کند. با ایجاد نقشه ای که یک مقدار عددی منحصر به فرد را برای هر ABI و چگالی که چندین APK را برای آن پیکربندی می کنید، اختصاص می دهد، می توانید کد نسخه خروجی را با مقداری که کد نسخه تعریف شده در بلوک defaultConfig
یا productFlavors
را با مقدار عددی اختصاص داده شده به آن ترکیب می کند، لغو کنید. چگالی یا ABI.
در مثال زیر، APK برای x86
ABI versionCode
2004 و x86_64
ABI versionCode
کد 3004 دریافت می کند.
تخصیص کدهای نسخه به صورت افزایشی، مانند 1000، به شما این امکان را می دهد که بعداً در صورت نیاز به به روز رسانی برنامه، کدهای نسخه منحصر به فرد را اختصاص دهید. برای مثال، اگر defaultConfig.versionCode
در یک بهروزرسانی بعدی به عدد 5 تکرار شود، Gradle versionCode
2005 را به x86
APK و 3005 را به x86_64
APK اختصاص میدهد.
نکته: اگر ساخت شما دارای یک APK جهانی است، versionCode
را به آن اختصاص دهید که کمتر از هر یک از APK های دیگر شما باشد. از آنجایی که Google Play Store نسخهای از برنامه شما را نصب میکند که هم با دستگاه مورد نظر سازگار است و هم دارای بالاترین versionCode
است، اختصاص versionCode
کمتر نسخه به APK جهانی تضمین میکند که فروشگاه Google Play سعی میکند یکی از APKهای شما را قبل از بازگشت به نسخه جهانی نصب کند. APK. کد نمونه زیر با نادیده نگرفتن versionCode
پیشفرض یک APK جهانی با این مشکل مقابله میکند.
شیار
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3] // For per-density APKs, create a similar map: // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3] import com.android.build.OutputFile // For each APK output variant, override versionCode with a combination of // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. android.applicationVariants.all { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.each { output -> // Stores the value of ext.abiCodes that is associated with the ABI for this variant. def baseAbiVersionCode = // Determines the ABI for this variant and returns the mapped value. project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiVersionCode != null) { // Assigns the new version code to versionCodeOverride, which changes the // version code for only the output APK, not for the variant itself. Skipping // this step causes Gradle to use the value of variant.versionCode for the APK. output.versionCodeOverride = baseAbiVersionCode * 1000 + variant.versionCode } } }
کاتلین
android { ... defaultConfig { ... versionCode = 4 } splits { ... } } // Map for the version code that gives each ABI a value. val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3) // For per-density APKs, create a similar map: // val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" to 3) import com.android.build.api.variant.FilterConfiguration.FilterType.* // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0)) } } } }
برای مثالهای بیشتر از طرحهای کد نسخه جایگزین، به اختصاص کدهای نسخه مراجعه کنید.
چندین APK بسازید
هنگامی که فایل build.gradle
یا build.gradle.kts
در سطح ماژول خود را برای ساخت چندین APK پیکربندی کردید، روی Build > Build APK کلیک کنید تا همه APK ها برای ماژول انتخابی فعلی در پنجره پروژه ساخته شوند. Gradle فایلهای APK را برای هر تراکم یا ABI در دایرکتوری build/outputs/apk/
پروژه ایجاد میکند.
Gradle برای هر تراکم یا ABI که چندین APK را برای آن پیکربندی میکنید، یک APK میسازد. اگر چندین APK را برای تراکم و ABI فعال کنید، Gradle برای هر تراکم و ترکیب ABI یک APK ایجاد میکند.
به عنوان مثال، قطعه build.gradle
زیر ساخت چندین APK را برای تراکم mdpi
و hdpi
و همچنین x86
و x86_64
ABI را قادر میسازد:
شیار
... splits { density { enable true reset() include "mdpi", "hdpi" } abi { enable true reset() include "x86", "x86_64" } }
کاتلین
... splits { density { isEnable = true reset() include("mdpi", "hdpi") } abi { isEnable = true reset() include("x86", "x86_64") } }
خروجی از پیکربندی مثال شامل 4 APK زیر است:
-
app-hdpiX86-release.apk
: حاوی کد و منابعی برای تراکمhdpi
وx86
ABI است. -
app-hdpiX86_64-release.apk
: حاوی کد و منابعی برای چگالیhdpi
وx86_64
ABI است. -
app-mdpiX86-release.apk
: حاوی کد و منابعی برای تراکمmdpi
وx86
ABI است. -
app-mdpiX86_64-release.apk
: حاوی کد و منابعی برای تراکمmdpi
وx86_64
ABI است.
هنگام ساخت چندین APK بر اساس تراکم صفحه، Gradle همیشه یک APK جهانی ایجاد میکند که شامل کد و منابع برای همه تراکمها، علاوه بر APKهای هر تراکم است.
هنگام ساختن چندین APK بر اساس ABI، Gradle تنها در صورتی یک APK ایجاد میکند که شامل کد و منابع برای همه ABI باشد، در صورتی که universalApk true
در بلوک splits.abi
در فایل build.gradle
خود (برای Groovy) یا isUniversalApk = true
در splits.abi
بلوک splits.abi
در فایل build.gradle.kts
شما (برای اسکریپت Kotlin).
فرمت نام فایل APK
هنگام ساخت چندین APK، Gradle نام فایلهای APK را با استفاده از طرح زیر تولید میکند:
modulename - screendensity ABI - buildvariant .apk
اجزای طرح عبارتند از:
-
modulename
- نام ماژول در حال ساخت را مشخص می کند.
-
screendensity
- اگر چند APK برای تراکم صفحه فعال باشد، تراکم صفحه APK را مشخص میکند، مانند
mdpi
. -
ABI
اگر چند APK برای ABI فعال باشد، ABI را برای APK مشخص میکند، مانند
x86
.اگر چندین APK برای تراکم صفحه و ABI فعال باشد، Gradle نام تراکم را با نام ABI، به عنوان مثال
mdpiX86
، الحاق میکند. اگرuniversalApk
برای هر APK ABI فعال باشد، Gradle ازuniversal
به عنوان بخش ABI نام فایل APK جهانی استفاده میکند.-
buildvariant
- نوع ساخت در حال ساخت را مشخص می کند، مانند
debug
.
برای مثال، هنگام ساختن APK با تراکم صفحه نمایش mdpi
برای نسخه اشکال زدایی myApp، نام فایل APK myApp-mdpi-debug.apk
است. نسخه منتشر شده myApp که برای ساخت چندین APK برای تراکم صفحه mdpi
و x86
ABI پیکربندی شده است، نام فایل APK myApp-mdpiX86-release.apk
دارد.