متغیرهای محیطی — مقادیر پویایی هستند که در مرحله راهاندازی به برنامه ارسال میشوند تا رفتار آن را بدون تغییر کد پیکربندی کنند. آنها امکان جداسازی پیکربندیهای توسعه، تست و تولید را فراهم میکنند. به گفته Twelve-Factor App, 2025، پیکربندی باید در متغیرهای محیطی ذخیره شود، نه در کد. متغیرهای محیطی مدیریت امن کلیدهای API، URL بکاند و پرچمهای قابلیت را تضمین میکنند.
نکات اصلی
متغیرهای محیطی یک جفت کلید-مقدار هستند که از طریق API سیستم عامل در دسترس فرآیند برنامه قرار میگیرند. آنها هنگام ایجاد فرآیند به آن ارسال میشوند و فقط در طول مدت اجرای آن وجود دارند. برخلاف پارامترهای پیکربندی تعبیه شده در کد منبع، متغیرهای محیطی برای تغییر مقادیر نیازی به کامپایل مجدد ندارند. این یک اصل بنیادی Twelve-Factor App است که جداسازی واضح بین کد و پیکربندی را تضمین میکند.
در توسعه موبایل، متغیرهای محیطی مشکل پیکربندیهای مختلف برای محیطها را حل میکنند: توسعهدهنده از سرور محلی، تستکننده از staging، کاربران از production استفاده میکنند. به جای ذخیره سه URL بکاند در کد با عاملگرهای شرطی if-else، توسعهدهنده یک URL را از طریق متغیر محیطی در مرحله ساخت ارسال میکند. این کار کد را ساده میکند و خطر استفاده تصادفی از سرور تولید در محیط تست را از بین میبرد.
مزیت اصلی امنیت است: دادههای حساس وارد مخزن کد نمیشوند. کلیدهای API، اسرار Firebase، توکنهای دسترسی به بکاند و گواهیها از طریق CI/CD مستقیماً به محیط ساخت بارگذاری میشوند. اگر مهاجم به مخزن کد دسترسی پیدا کند، اسرار را در آنجا پیدا نمیکند، زیرا آنها در انبارهای محافظت شده سیستم CI ذخیره شده و فقط در مرحله ساخت فایل بینری ارسال میشوند.
پروژههای موبایل حداقل سه محیط دارند: development، staging و production. هر محیط به مجموعه پیکربندی خاص خود نیاز دارد: URL سرور، نام بسته، شمای امضا و گواهیهای اعلان push. بدون متغیرهای محیطی، توسعهدهنده باید قبل از هر ساخت به صورت دستی پیکربندی را تغییر دهد که منجر به خطا میشود: کلید تولید فراموش شده در ساخت آزمایشی میتواند باعث ارسال اعلان به کاربران واقعی یا مصرف API پولی شود.
متغیرهای محیطی امکان تغییر بکاند را بدون تغییر کد فراهم میکنند: کافی است مقدار متغیر API_BASE_URL را جایگزین کنید. پرچمهای قابلیت (feature flags) از طریق متغیرهایی مانند FEATURE_CHAT_ENABLED=true مدیریت میشوند که امکان فعال کردن قابلیتهای جدید در staging بدون تأثیر بر production را فراهم میکند. برای هر محیط یک فایل .env مخصوص ایجاد میشود که در مرحله ساخت بارگذاری میگردد.
class AppConfig {
static final String apiBaseUrl =
const String.fromEnvironment('API_BASE_URL',
defaultValue: 'http://localhost:8080');
}
کلیدهای کدگذاری شده سخت — یک آسیبپذیری رایج در برنامههای موبایل است. مهاجم با استفاده از ابزارهایی مانند jadx یا Hopper APK یا IPA را دکامپایل کرده و اسرار را از فایل بینری استخراج میکند. حتی مبهمسازی نیز از رشتههای متنی محافظت نمیکند — آنها به راحتی در کد پس از دکامپایل یافت میشوند. متغیرهای محیطی این مشکل را حل میکنند، کلیدها را در مرحله ساخت از طریق CI/CD ارسال میکنند، جایی که در لاگها پوشانده میشوند.
object Config {
val apiKey: String =
System.getenv("API_KEY") ?: throw
IllegalStateException("API_KEY not set")
}
متغیرهای محیطی با پایپلاینهای ساخت یکپارچه میشوند: GitHub Actions، GitLab CI، Bitrise و CircleCI از متغیرهای مخفی پشتیبانی میکنند که در لاگها نمایش داده نمیشوند. در مرحله ساخت، CI بستگی به شاخه یا تگ، مقادیر مناسب را جایگزین میکند: برای شاخه develop از staging، برای تگ v* از production استفاده میشود. این فرآیند را خودکار کرده و عامل انسانی را حذف میکند و تضمین میکند که هر ساخت مجموعه پیکربندی صحیح را دریافت میکند.
فایل .env روش استاندارد ذخیره متغیرهای محیطی در قالب KEY=VALUE است. در مخزن قرار نمیگیرد، بلکه به جای آن فایل .env.example با الگوی همه متغیرها و مقادیر خالی به مخزن اضافه میشود. هر توسعهدهنده فایل .env خود را با تنظیمات محلی ایجاد میکند، بدون اینکه بر پیکربندی سایر اعضای تیم تأثیر بگذارد. برای محیطهای مختلف از فایلهای جداگانه استفاده میشود: .env.dev، .env.stage، .env.prod.
# .env.example — الگو برای توسعهدهندگان
API_BASE_URL=http://localhost:8080
FEATURE_CHAT_ENABLED=true
SENTRY_DSN=
برای پروژههای موبایل کتابخانههای تخصصی برای کار با فایلهای .env وجود دارند:
تنظیمات شاخه در CI/CD امکان جایگزینی فایلهای .env مختلف را فراهم میکند: .env.dev برای سرورهای تست، .env.stage برای پیش از انتشار و .env.prod برای انتشار در فروشگاههای برنامه. فایلهای حاوی اسرار از ذخیرهگاه امن (Vault، AWS Secrets Manager) بارگذاری میشوند و در مخزن ذخیره نمیشوند. این تضمین میکند که حتی در صورت به خطر افتادن سیستم کنترل نسخه، اسرار محافظت شده باقی میمانند.
اکوسیستم iOS از فایلهای xcconfig برای مدیریت متغیرها در سطح ساخت استفاده میکند. آنها به طرحهای Xcode متصل شده و امکان بازنویسی مقادیر برای پیکربندیهای Debug و Release را فراهم میکنند. فایلهای xcconfig از وراثت پشتیبانی میکنند: میتوان یک فایل پایه با تنظیمات مشترک و فایلهای مخصوص برای هر محیط ایجاد کرد.
فایلهای xcconfig متغیرها را در قالب KEY = VALUE ذخیره کرده و از طریق تنظیمات Configuration به طرح ساخت در Xcode متصل میشوند. متغیرهای xcconfig در Info.plist از طریق نحو $(VARIABLE_NAME) در دسترس هستند که امکان استفاده از شناسههای بسته و نامهای مختلف برنامه برای طرحهای مختلف را فراهم میکند. برای شناسایی سریع محیط، به نام برنامه پسوند Dev یا Staging اضافه میشود.
# Config/Dev.xcconfig — پیکربندی توسعه
API_BASE_URL = http://localhost:3000
BUNDLE_ID_SUFFIX = .dev
APP_DISPLAY_NAME = MyApp Dev
برای دسترسی به متغیرها در زمان اجرا در iOS از فایل Configuration.swift استفاده میشود که مقادیر را از Info.plist از طریق Bundle.main.object(forInfoDictionaryKey:) میخواند. این رویکرد تضمین میکند که متغیرها در مرحله ساخت تعیین شده و بلافاصله پس از راهاندازی در دسترس برنامه هستند. مقادیر یک بار در هنگام مقداردهی اولیه ماژول خوانده شده و برای دسترسی سریع در طول چرخه حیات برنامه ذخیره میشوند.
enum AppEnvironment {
static var apiBaseURL: URL {
guard let urlString = Bundle.main
.object(forInfoDictionaryKey: "API_BASE_URL"),
let url = URL(string: urlString as! String)
else { fatalError("API_BASE_URL is not configured") }
return url
}
static var isChatEnabled: Bool {
Bundle.main.object(
forInfoDictionaryKey: "FEATURE_CHAT_ENABLED"
) as? Bool ?? false
}
}
Android از متغیرهای محیطی از طریق BuildConfig — کلاس تولید شده خودکار که فیلدهای آن در فایل build.gradle ماژول تعریف میشود — پشتیبانی میکند. BuildConfig در مرحله کامپایل برای هر flavor و نوع ساخت به طور جداگانه ایجاد میشود. این امکان داشتن مقادیر مختلف برای debug و release را بدون استفاده از عاملگرهای شرطی در کد فراهم میکند که عملکرد و امنیت را افزایش میدهد.
فیلدهای BuildConfig از طریق buildConfigField در defaultConfig یا در buildTypes خاص تنظیم میشوند. برای هر محیط یک buildType یا productFlavor جداگانه ایجاد میشود. این جداسازی دقیق پیکربندیها را تضمین میکند: debug از سرور محلی، release از production استفاده میکند. فیلدهای BuildConfig از نظر نوع ایستا هستند که خطاها را هنگام ارجاع به آنها در کد از بین میبرد.
// build.gradle (Module: app)
android {
defaultConfig {
buildConfigField "String", "API_BASE_URL",
"\"http://localhost:8080\""
}
buildTypes {
debug {
buildConfigField "String", "API_BASE_URL",
"\"http://dev.api.itsectr.com\""
}
release {
buildConfigField "String", "API_BASE_URL",
"\"https://api.itsectr.com\""
}
}
}
فایل gradle.properties در ریشه پروژه متغیرهای سراسری Gradle را ذخیره میکند. آنها از طریق نحو $variableName در همه ماژولها در دسترس هستند و برای تعیین نسخه وابستگیها، پرچمهای ساخت و کلیدهای API استفاده میشوند. برخلاف BuildConfig، gradle.properties فقط در مرحله پیکربندی Gradle کار میکند، نه در زمان اجرای برنامه. بنابراین رمزهای عبور و کلیدهای API مشخص شده در gradle.properties در کد دکامپایل شده قابل مشاهده نیستند، زیرا آنها فقط برای تولید BuildConfig در مرحله کامپایل استفاده میشوند.
# gradle.properties
SENTRY_DSN=https://key@sentry.io/project
MAPS_API_KEY=AIzaSy...
برای ارسال امن اسرار در پروژههای Android توصیه میشود از local.properties (حذف شده از VCS) استفاده کنید یا مقادیر را از متغیرهای CI/CD از طریق System.getenv() به build.gradle بارگذاری کنید. این تضمین میکند که کلیدها وارد مخزن نشوند. هنگام انتشار در Google Play Console مطمئن شوید که تمام کلیدهای debug با نسخههای تولیدی از طریق buildTypes یا productFlavors مختلف با مقادیر BuildConfig مربوطه جایگزین شدهاند.
سوالات متداول
بله، Flutter از متغیرهای محیطی از طریق بسته flutter_dotenv برای دسترسی در زمان اجرا یا از طریق کانالهای بومی برای متغیرهای پلتفرمی پشتیبانی میکند. در Dart همچنین سازنده String.fromEnvironment برای ارسال مقادیر در مرحله کامپایل از طریق --dart-define در دسترس است که روش ترجیحی برای پروژههای Flutter میباشد.
BuildConfig — یک کلاس Java با فیلدهای تایپشده است که در مرحله کامپایل برای هر buildType و flavor تولید میشود. gradle.properties — یک فایل متنی با جفتهای کلید-مقدار است که برای همه ماژولهای Gradle در مرحله پیکربندی ساخت در دسترس میباشد. BuildConfig در زمان اجرای برنامه کار میکند، gradle.properties — فقط در اسکریپتهای Gradle.
.env را به فایل .gitignore مخزن خود اضافه کنید. فقط .env.example را با مقادیر خالی و توضیح هر متغیر به مخزن commit کنید. برای CI/CD از اسرار رمزگذاری شده در تنظیمات GitHub Actions، GitLab CI یا Bitrise استفاده کنید که در لاگها پوشانده شده و پس از پایان ساخت قابل خواندن نیستند.
اکثر سیستمهای CI از متغیرهای محیطی مخفی پشتیبانی میکنند. در GitHub Actions اینها Secrets، در GitLab CI — CI/CD Variables، در Bitrise — Secrets نامیده میشوند. در مرحله ساخت، آنها از طریق process.env یا System.getenv() به اسکریپت ساخت ارسال میشوند. متغیرهای مخفی در لاگهای ساخت نمایش داده نمیشوند و در فورکهای مخزن در دسترس نیستند.
Feature flags — متغیرهای بولی هستند که فعال یا غیرفعال کردن قابلیت را بدون کامپایل مجدد کد کنترل میکنند. مثال: FEATURE_NEW_PAYMENT=true سیستم پرداخت جدید را در staging برای آزمایش فعال میکند. در production همان پرچم تا استقرار کامل بکاند بر روی false تنظیم شده است. این امکان پیادهسازی ایمن تغییرات را به صورت مرحلهای و بازگشت آنها را در صورت بروز مشکل فراهم میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.