Android
محیط ساخت Android سه ویژگی اصلی و تعدادی ویژگی پشتیبان ارائه میدهد.
استفاده از androidenv با Android Studio
از صفت (attribute) android-studio-full برای یک Android SDK بسیار کامل، شامل تصاویر سیستم، استفاده کنید:
{ buildInputs = [ android-studio-full ]; } این کاملاً معادل است با:
{ buildInputs = [ androidStudioPackages.stable.full ]; } همچنین میتوانید composeAndroidPackages را به passthroughِ withSdk پاس دهید:
{
buildInputs = [
(android-studio.withSdk (androidenv.composeAndroidPackages { includeNDK = true; }).androidsdk)
];
} این موارد متغیرهای ANDROID_HOME و ANDROID_NDK_ROOT را به پوشههای SDK و NDK در محیط ساخت Android مشخصشده صادر میکنند.
استقرار یک نصب Android SDK به همراه افزونهها
همچنین میتوانید SDK را بهطور جداگانه با مجموعهٔ دلخواهی از افزونهها یا زیرمجموعههایی از یک SDK استقرار دهید.
with import <nixpkgs> { };
let
androidComposition = androidenv.composeAndroidPackages {
platformVersions = [
"34"
"35"
"latest"
];
systemImageTypes = [ "google_apis_playstore" ];
abiVersions = [
"armeabi-v7a"
"arm64-v8a"
];
includeNDK = true;
includeExtras = [ "extras;google;auto" ];
};
in
androidComposition.androidsdk فراخوانی تابع فوق مشخص میکند که ما یک Android SDK با نسخههای پلاگین تعیینشده در بالا میخواهیم. به طور پیشفرض، اکثر پلاگینها غیرفعال هستند. استثناهای قابل توجه، زیربستههای tools، platform-tools و build-tools هستند.
گزینههای زیر پشتیبانی میشوند:
cmdLineToolsVersionنسخه بستهcmdline-toolsمورد استفاده را مشخص میکند. مقدار پیشفرض آن آخرین نسخه است.toolsVersionنسخه بستهtoolsرا مشخص میکند. توجه داشته باشید کهtoolsمنسوخ شده است و در حال حاضر تنها نسخه26.1.1در دسترس است، بنابراین گزینههای زیادی در اینجا وجود ندارد؛ با این حال، اگر آن را نمیخواهید میتوانید مقدارش راnullقرار دهید. مقدار پیشفرض آن آخرین نسخه است.platformToolsVersionنسخه پلاگینplatform-toolsرا مشخص میکند. مقدار پیشفرض آن آخرین نسخه است.buildToolsVersionsنسخههای پلاگینهایbuild-toolsمورد استفاده را مشخص میکند. مقدار پیشفرض آن آخرین نسخه است.includeEmulatorمشخص میکند که آیا بسته شبیهساز استقرار یابد یا خیر (به طور پیشفرضfalse). در صورت فعال بودن، نسخه شبیهساز برای استقرار را میتوان با تنظیم پارامترemulatorVersionمشخص کرد. اگر روی"if-supported"تنظیم شود، در صورت پشتیبانی سیستم، شبیهساز استقرار داده میشود.includeCmakeمشخص میکند که آیا CMake باید گنجانده شود یا خیر. مقدار پیشفرض آن روی پلتفرمهای x86-64 و Darwin برابر با true است و از"if-supported"نیز پشتیبانی میکند.cmakeVersionsمشخص میکند که کدام نسخههای CMake باید استقرار یابند. مقدار پیشفرض آن آخرین نسخه است.includeNDKمشخص میکند که باندل Android NDK باید گنجانده شود یا خیر. مقدار پیشفرض آنfalseاست، اگرچه میتوان آن را رویtrueیا"if-supported"تنظیم کرد.ndkVersionsنسخههای NDK مورد استفاده را مشخص میکند. اینها در زیر پوشهndkدر ریشه SDK پیوند داده میشوند و اولین مورد در زیر پوشهndk-bundleپیوند داده میشود. مقدار پیشفرض آن آخرین نسخه است.ndkVersionمعادل مشخص کردن یک ورودی درndkVersionsاست و در صورت ارائه،ndkVersionsاین پارامتر را بازنویسی میکند.includeExtrasآرایهای از رشتههای شناسه است که به بستههای افزوده دلخواه که باید نصب شوند اشاره میکند. توجه داشته باشید که برنامههای اضافی ممکن است با همه پلتفرمها سازگار نباشند (به عنوان مثال، دستگاه Google TV head unit که کامپایل aarch64-linux ندارد).platformVersionsمشخص میکند که کدام نسخههای SDK پلتفرم باید گنجانده شوند. به طور پیشفرض تنها شامل آخرین سطح API میشود، اگرچه میتوانید موارد بیشتری اضافه کنید.numLatestPlatformVersionsمشخص میکند در صورت استفاده از مقدار پیشفرض برایplatformVersions، چه تعداد از آخرین سطوح API گنجانده شوند. مقدار پیشفرض آن 1 است، اگرچه میتوانید آن را مثلاً به 5 افزایش دهید تا بستههای API مربوط به 5 سال اخیر Android را دریافت کنید.minPlatformVersionوmaxPlatformVersionدر صورت ارائه هر دو، نسبت بهplatformVersionsاولویت دارند. توجه داشته باشید که مقدار پیشفرضmaxPlatformVersionهمیشه آخرین نسخه پلتفرم Android SDK است، که به شما امکان میدهد با تعیینminPlatformVersionحداقل نسخه SDK پشتیبانیشده توسط ترکیب Android خود را توصیف کنید.
برای هر نسخه پلتفرم مشخصشده، میتوانیم گزینههای زیر را اعمال کنیم:
includeSystemImagesمشخص میکند که آیا تصویر سیستم برای هر SDK پلتفرم باید گنجانده شود یا خیر.includeSourcesمشخص میکند که آیا کدهای منبع برای هر نسخه SDK باید گنجانده شوند یا خیر.useGoogleAPIsمشخص میکند که برای هر نسخه پلتفرم انتخابشده، Google API باید گنجانده شود.useGoogleTVAddOnsمشخص میکند که برای هر نسخه پلتفرم انتخابشده، افزودنی Google TV باید گنجانده شود.
برای هر تصویر سیستم درخواستی میتوانیم گزینههای زیر را مشخص کنیم:
systemImageTypesمشخص میکند که چه نوع ایمیجهای سیستمی باید شامل شوند. مقدار پیشفرض:default.abiVersionsمشخص میکند که چه نوع نسخه ABI از هر ایمیج سیستم باید شامل شود. مقادیر پیشفرضarmeabi-v7aوarm64-v8aهستند.
بیشتر آرگومانهای تابع دارای تنظیمات پیشفرض معقولی هستند و در صورت امکان، آخرین نسخههای ابزارها را ترجیح میدهند. همچنین میتوانید برای هر نسخه از افزونه که اهمیت خاصی برایتان ندارد و صرفاً آخرین نسخه آن را میخواهید، مقدار "latest" را مشخص کنید.
میتوانید نامهای مجوز را مشخص کنید:
extraLicensesفهرستی از نامهای مجوز است. میتوانید این نامها را از repo.json یاquerypackages.sh licensesبه دست آورید. اگر accept_license را روی true تنظیم کنید، مجوز SDK (android-sdk-license) برای شما پذیرفته میشود. اگر کاری مانند کار با SDKهای پیشنمایش انجام میدهید، بایدandroid-sdk-preview-licenseیا هر مجوزی که در اینجا مربوط میشود را اضافه کنید.
علاوه بر این، میتوانید مخازنی را که composeAndroidPackages از آنها دریافت میکند بازنشانی کنید:
repoJsonمسیر یک فایل repo.json تولیدشده را مشخص میکند. میتوانید این فایل را با اجرایgenerate.shتولید کنید، که به نوبه خودmkrepo.rbرا فراخوانی میکند.repoXmlsیک مجموعه ویژگی شامل مسیرهای فایلهای XML مخزن است. در صورت مشخص شدن، نسبت بهrepoJsonاولویت دارد و یک ساخت محلی را راهاندازی میکند که بر اساس XMLهای مخزن دادهشده، یک repo.json را در انبار Nix مینویسد. توجه داشته باشید که این قابلیت از import-from-derivation استفاده میکند.
{
repoXmls = {
packages = [ ./xml/repository2-1.xml ];
images = [
./xml/android-sys-img2-1.xml
./xml/android-tv-sys-img2-1.xml
./xml/android-wear-sys-img2-1.xml
./xml/android-wear-cn-sys-img2-1.xml
./xml/google_apis-sys-img2-1.xml
./xml/google_apis_playstore-sys-img2-1.xml
];
addons = [ ./xml/addon2-1.xml ];
};
} هنگام ساخت عبارت بالا با:
$ nix-build Android SDK همراه با تمامی نسخههای مورد نظر افزونه استقرار مییابد.
ما همچنین میتوانیم زیرمجموعههایی از Android SDK را استقرار دهیم. برای مثال، جهت استقرار تنها بسته platform-tools، میتوانید عبارت زیر را ارزیابی کنید:
with import <nixpkgs> { };
let
androidComposition = androidenv.composeAndroidPackages {
# ...
};
in
androidComposition.platform-tools استفاده از ترکیبهای ازپیشتعریفشده بستههای Android
علاوه بر ترکیب دستی مجموعهای از بستههای Android، استفاده از یک ترکیب ازپیشتعریفشده که شامل مجموعه نسبتاً کاملی از بستههای Android است نیز امکانپذیر است:
از عبارت نیکس (Nix expression) زیر میتوان برای استقرار کل SDK استفاده کرد:
with import <nixpkgs> { };
androidenv.androidPkgs.androidsdk همچنین میتوان تنها از یک پلاگین استفاده کرد:
with import <nixpkgs> { };
androidenv.androidPkgs.platform-tools ایجاد نمونههای شبیهساز
برای اهداف تست، تولید خودکار اسکریپتهایی که نمونههای شبیهساز را با تمام تنظیمات پیکربندی دلخواه راهاندازی میکنند، میتواند بسیار کاربردی باشد.
یک اسکریپت راهاندازی شبیهساز را میتوان با فراخوانی تابع emulateApp {'{'}'{'{'}'{'}'}{'{'}'{'}'}'{'}'} پیکربندی کرد:
with import <nixpkgs> { };
androidenv.emulateApp {
name = "emulate-MyAndroidApp";
platformVersion = "28";
abiVersion = "x86"; # armeabi-v7a, mips, x86_64
systemImageType = "google_apis_playstore";
} میتوان پرچمهای اضافی را از طریق متغیر محیطی زمان اجرا $NIX_ANDROID_EMULATOR_FLAGS به شبیهساز Android SDK اعمال کرد.
همچنین امکان مشخص کردن یک APK برای استقرار درون شبیهساز و نامهای بسته و activity برای راهاندازی آن وجود دارد:
with import <nixpkgs> { };
androidenv.emulateApp {
name = "emulate-MyAndroidApp";
platformVersion = "24";
abiVersion = "armeabi-v7a"; # mips, x86, x86_64
systemImageType = "default";
app = ./MyApp.apk;
package = "MyApp";
activity = "MainActivity";
} علاوه بر APKهای پیشساخته، میتوانید پارامتر APK را به فراخوانی تابع buildApp {'{'}'{'{'}'{'}'}{'{'}'{'}'}'{'}'} که در مثال قبلی نشان داده شد نیز متصل کنید.
نکاتی درباره متغیرهای محیطی در پروژههای Android
ANDROID_HOMEباید به Android SDK اشاره کند. در عبارتهای Nix شما، این مقدار باید${'{'}'{'{'}'{'}'}androidComposition.androidsdk{'{'}'{'}'}'{'}'}/libexec/android-sdkباشد. توجه داشته باشید کهANDROID_SDK_ROOTمنسوخ شده است، اما اگر به ابزارهایی متکی هستید که به آن نیاز دارند، میتوانید آن را نیز صادر (export) کنید.- اگر در حال توسعه NDK هستید،
ANDROID_NDK_ROOTباید به Android NDK اشاره کند. در عبارتهای Nix شما، این مقدار باید${'{'}'{'{'}'{'}'}ANDROID_HOME{'{'}'{'}'}'{'}'}/ndk-bundleباشد.
اگر در حال اجرای پلاگین Android Gradle هستید، باید GRADLE_OPTS را صادر کنید تا aapt2 را طوری بازنشانی کنید که به باینری aapt2 در انبار نیکس (Nix store) نیز اشاره کند، یا از یک محیط FHS استفاده کنید تا aapt2 بستهبندیشده بتواند اجرا شود. اگر نمیخواهید از یک محیط FHS استفاده کنید، چیزی مانند این باید کار کند:
let
buildToolsVersion = "30.0.3";
# Use buildToolsVersion when you define androidComposition
androidComposition = <...>;
in
pkgs.mkShell rec {
ANDROID_HOME = "${androidComposition.androidsdk}/libexec/android-sdk";
ANDROID_NDK_ROOT = "${ANDROID_HOME}/ndk-bundle";
# Use the same buildToolsVersion here
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_HOME}/build-tools/${buildToolsVersion}/aapt2";
} اگر از cmake استفاده میکنید، باید آن را در یک قلاب شل (shell hook) یا پروفایل محیطی FHS به PATH اضافه کنید. به انتهای این مسیر شماره ساخت اضافه میشود، اما پیشوند آن به شکل مناسبی شامل نسخه است. بنابراین، چیزی شبیه به این باید کافی باشد:
let
cmakeVersion = "3.10.2";
# Use cmakeVersion when you define androidComposition
androidComposition = <...>;
in
pkgs.mkShell rec {
ANDROID_HOME = "${androidComposition.androidsdk}/libexec/android-sdk";
ANDROID_NDK_ROOT = "${ANDROID_HOME}/ndk-bundle";
# Use the same cmakeVersion here
shellHook = ''
export PATH="$(echo "$ANDROID_HOME/cmake/${cmakeVersion}".*/bin):$PATH"
'';
} توجه داشته باشید که اجرای Android Studio با مقداردهی ANDROID_HOME، در صورت عدم وجود فایل local.properties، بهطور خودکار این فایل را ایجاد کرده و sdk.dir را روی $ANDROID_HOME تنظیم میکند. اگر از NDK نیز استفاده میکنید، ممکن است لازم باشد ndk.dir را به این فایل اضافه کنید.
یک نمونه shell.nix که تمام این کارها را برای شما انجام میدهد در examples/shell.nix ارائه شده است. این shell.nix شامل یک قلاب شل (shell hook) است که local.properties را با مقادیر صحیح sdk.dir و ndk.dir بازنویسی میکند. این امر تضمین میکند که هنگام اجرای Android Studio در داخل nix-shell، پوشههای SDK و NDK هر دو درست باشند.
نکاتی در مورد بهبود سازگاری build.gradle
اطمینان حاصل کنید که buildToolsVersion و ndkVersion شما با آنچه در androidenv تعریف شده مطابقت داشته باشد. اگر از cmake استفاده میکنید، مطمئن شوید که نسخه تعریفشده برای آن نیز درست است.
در غیر این صورت، ممکن است با خطاهای مبهمی از سوی aapt2 و پلاگین Android Gradle مواجه شوید که هشدار میدهند به دلیل قابل نوشتن نبودن پوشه SDK، امکان نصب ابزارهای ساخت وجود ندارد.
android {
buildToolsVersion "30.0.3"
ndkVersion = "22.0.7026061"
externalNativeBuild {
cmake {
version "3.10.2"
}
}
}
استعلام نسخههای موجود برای هر پلاگین
تمامی بستههای androidenv در search.nixos.org در دسترس هستند.
توجه داشته باشید که سازگاری aarch64-linux در حال حاضر نامنظم است، اگرچه x86_64-linux و aarch64-darwin به خوبی پشتیبانی میشوند. دلیل این امر آن است که تعاریف مخزن گوگل، برخی بستهها را برای "همه" معماریها علامتگذاری میکنند در حالی که واقعاً فقط برای x86_64 یا aarch64 هستند.
بهروزرسانی عبارتهای تولیدشده
فایل repo.json از فایلهای XML که مدیر بسته Android Studio استفاده میکند تولید میشود.
برای بهروزرسانی عبارتها، اسکریپت update.sh را که در زیرپوشه pkgs/development/mobile/androidenv/ ذخیره شده است اجرا کنید:
./update.sh این کار به صورت خودکار توسط اسکریپت بهروزرسانی nixpkgs اجرا میشود.
ساخت یک برنامه Android با Ant
علاوه بر SDK، امکان ساخت یک پروژه Android مبتنی بر Ant و استقرار خودکار تمام پلاگینهای Android مورد نیاز پروژه نیز وجود دارد. اکثر پروژههای جدیدتر Android از Gradle استفاده میکنند و این بخش صرفاً به دلایل تاریخی آورده شده است.
with import <nixpkgs> { };
androidenv.buildApp {
name = "MyAndroidApp";
src = ./myappsources;
release = true;
# If release is set to true, you need to specify the following parameters
keyStore = ./keystore;
keyAlias = "myfirstapp";
keyStorePassword = "mykeystore";
keyAliasPassword = "myfirstapp";
# Any Android SDK parameters that install all the relevant plugins that a
# build requires
platformVersions = [ "24" ];
# When we include the NDK, then ndk-build is invoked before Ant gets invoked
includeNDK = true;
} به غیر از پارامترهای ساخت مختص برنامه (name، src، release و پارامترهای keystore)، تابع buildApp {'{'}'{'{'}'{'}'}{'{'}'{'}'}'{'}'} از تمام پارامترهای تابعی که تابع ترکیب SDK (تابعی که در بخش قبلی نشان داده شد) پشتیبانی میکند، پشتیبانی میکند.
این تابع ساخت بهویژه زمانی مفید است که قصد داشته باشید از Hydra استفاده کنید: راهکار ادغام مداوم (CI) مبتنی بر Nix برای ساخت برنامههای Android. یک Android APK به عنوان یک فرآوردهٔ ساخت ارائه میشود و میتوان آن را با رفتن به صفحهٔ نتیجهٔ ساخت، روی هر دستگاه Android دارای مرورگر وب نصب کرد.