متغیرهای محیطی: چیست، استفاده و پیکربندی در پروژه‌های موبایل

نویسنده: IT Sectr منتشر شده: 2026-05-31 زمان مطالعه: 8 دقیقه

متغیرهای محیطی — مقادیر پویایی هستند که در مرحله راه‌اندازی به برنامه ارسال می‌شوند تا رفتار آن را بدون تغییر کد پیکربندی کنند. آنها امکان جداسازی پیکربندی‌های توسعه، تست و تولید را فراهم می‌کنند. به گفته Twelve-Factor App, 2025، پیکربندی باید در متغیرهای محیطی ذخیره شود، نه در کد. متغیرهای محیطی مدیریت امن کلیدهای API، URL بک‌اند و پرچم‌های قابلیت را تضمین می‌کنند.

نکات اصلی

  • متغیرهای محیطی پیکربندی برنامه را از کد منبع برای محیط‌های مختلف اجرا جدا می‌کنند
  • فایل‌های .env متغیرها را در قالب KEY=VALUE ذخیره می‌کنند و از طریق .gitignore از مخزن حذف می‌شوند
  • iOS از xcconfig و Build Settings برای ارسال متغیرها در مرحله کامپایل استفاده می‌کند
  • Android از BuildConfig و gradle.properties برای تولید فیلدهای پیکربندی استفاده می‌کند
  • امنیت: کلیدها و توکن‌ها باید از طریق CI/CD بارگذاری شوند، نه در کد یا مخزن ذخیره شوند

متغیرهای محیطی چیست

متغیرهای محیطی یک جفت کلید-مقدار هستند که از طریق 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 مخصوص ایجاد می‌شود که در مرحله ساخت بارگذاری می‌گردد.

dart
class AppConfig {
  static final String apiBaseUrl =
    const String.fromEnvironment('API_BASE_URL',
      defaultValue: 'http://localhost:8080');
}

امنیت کلیدها

کلیدهای کدگذاری شده سخت — یک آسیب‌پذیری رایج در برنامه‌های موبایل است. مهاجم با استفاده از ابزارهایی مانند jadx یا Hopper APK یا IPA را دکامپایل کرده و اسرار را از فایل بینری استخراج می‌کند. حتی مبهم‌سازی نیز از رشته‌های متنی محافظت نمی‌کند — آنها به راحتی در کد پس از دکامپایل یافت می‌شوند. متغیرهای محیطی این مشکل را حل می‌کنند، کلیدها را در مرحله ساخت از طریق CI/CD ارسال می‌کنند، جایی که در لاگ‌ها پوشانده می‌شوند.

kotlin
object Config {
    val apiKey: String =
        System.getenv("API_KEY") ?: throw
            IllegalStateException("API_KEY not set")
}

یکپارچه‌سازی CI/CD

متغیرهای محیطی با پایپ‌لاین‌های ساخت یکپارچه می‌شوند: GitHub Actions، GitLab CI، Bitrise و CircleCI از متغیرهای مخفی پشتیبانی می‌کنند که در لاگ‌ها نمایش داده نمی‌شوند. در مرحله ساخت، CI بستگی به شاخه یا تگ، مقادیر مناسب را جایگزین می‌کند: برای شاخه develop از staging، برای تگ v* از production استفاده می‌شود. این فرآیند را خودکار کرده و عامل انسانی را حذف می‌کند و تضمین می‌کند که هر ساخت مجموعه پیکربندی صحیح را دریافت می‌کند.

فایل‌های .env و کتابخانه‌های مدیریت

فایل .env روش استاندارد ذخیره متغیرهای محیطی در قالب KEY=VALUE است. در مخزن قرار نمی‌گیرد، بلکه به جای آن فایل .env.example با الگوی همه متغیرها و مقادیر خالی به مخزن اضافه می‌شود. هر توسعه‌دهنده فایل .env خود را با تنظیمات محلی ایجاد می‌کند، بدون اینکه بر پیکربندی سایر اعضای تیم تأثیر بگذارد. برای محیط‌های مختلف از فایل‌های جداگانه استفاده می‌شود: .env.dev، .env.stage، .env.prod.

bash
# .env.example — الگو برای توسعه‌دهندگان
API_BASE_URL=http://localhost:8080
FEATURE_CHAT_ENABLED=true
SENTRY_DSN=

برای پروژه‌های موبایل کتابخانه‌های تخصصی برای کار با فایل‌های .env وجود دارند:

  • flutter_dotenv (Flutter) — متغیرها را از .env در زمان اجرا از طریق dotenv.load() بارگذاری می‌کند
  • BuildConfig (Android) — فیلدهای تایپ‌شده را از مقادیر build.gradle تولید می‌کند
  • xcconfig (iOS) — فایل‌های پیکربندی را به طرح‌های مختلف ساخت Xcode متصل می‌کند
  • react-native-config (React Native) — مدیریت متغیرها از طریق فایل‌های .env

تنظیمات شاخه در CI/CD امکان جایگزینی فایل‌های .env مختلف را فراهم می‌کند: .env.dev برای سرورهای تست، .env.stage برای پیش از انتشار و .env.prod برای انتشار در فروشگاه‌های برنامه. فایل‌های حاوی اسرار از ذخیره‌گاه امن (Vault، AWS Secrets Manager) بارگذاری می‌شوند و در مخزن ذخیره نمی‌شوند. این تضمین می‌کند که حتی در صورت به خطر افتادن سیستم کنترل نسخه، اسرار محافظت شده باقی می‌مانند.

متغیرهای محیطی در پروژه‌های iOS

اکوسیستم iOS از فایل‌های xcconfig برای مدیریت متغیرها در سطح ساخت استفاده می‌کند. آنها به طرح‌های Xcode متصل شده و امکان بازنویسی مقادیر برای پیکربندی‌های Debug و Release را فراهم می‌کنند. فایل‌های xcconfig از وراثت پشتیبانی می‌کنند: می‌توان یک فایل پایه با تنظیمات مشترک و فایل‌های مخصوص برای هر محیط ایجاد کرد.

پیکربندی فایل‌های xcconfig

فایل‌های xcconfig متغیرها را در قالب KEY = VALUE ذخیره کرده و از طریق تنظیمات Configuration به طرح ساخت در Xcode متصل می‌شوند. متغیرهای xcconfig در Info.plist از طریق نحو $(VARIABLE_NAME) در دسترس هستند که امکان استفاده از شناسه‌های بسته و نام‌های مختلف برنامه برای طرح‌های مختلف را فراهم می‌کند. برای شناسایی سریع محیط، به نام برنامه پسوند Dev یا Staging اضافه می‌شود.

bash
# Config/Dev.xcconfig — پیکربندی توسعه
API_BASE_URL = http://localhost:3000
BUNDLE_ID_SUFFIX = .dev
APP_DISPLAY_NAME = MyApp Dev

کد Swift برای خواندن متغیرها

برای دسترسی به متغیرها در زمان اجرا در iOS از فایل Configuration.swift استفاده می‌شود که مقادیر را از Info.plist از طریق Bundle.main.object(forInfoDictionaryKey:) می‌خواند. این رویکرد تضمین می‌کند که متغیرها در مرحله ساخت تعیین شده و بلافاصله پس از راه‌اندازی در دسترس برنامه هستند. مقادیر یک بار در هنگام مقداردهی اولیه ماژول خوانده شده و برای دسترسی سریع در طول چرخه حیات برنامه ذخیره می‌شوند.

swift
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

Android از متغیرهای محیطی از طریق BuildConfig — کلاس تولید شده خودکار که فیلدهای آن در فایل build.gradle ماژول تعریف می‌شود — پشتیبانی می‌کند. BuildConfig در مرحله کامپایل برای هر flavor و نوع ساخت به طور جداگانه ایجاد می‌شود. این امکان داشتن مقادیر مختلف برای debug و release را بدون استفاده از عاملگرهای شرطی در کد فراهم می‌کند که عملکرد و امنیت را افزایش می‌دهد.

پیکربندی فیلدهای BuildConfig

فیلدهای BuildConfig از طریق buildConfigField در defaultConfig یا در buildTypes خاص تنظیم می‌شوند. برای هر محیط یک buildType یا productFlavor جداگانه ایجاد می‌شود. این جداسازی دقیق پیکربندی‌ها را تضمین می‌کند: debug از سرور محلی، release از production استفاده می‌کند. فیلدهای BuildConfig از نظر نوع ایستا هستند که خطاها را هنگام ارجاع به آنها در کد از بین می‌برد.

groovy
// 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.properties در ریشه پروژه متغیرهای سراسری Gradle را ذخیره می‌کند. آنها از طریق نحو $variableName در همه ماژول‌ها در دسترس هستند و برای تعیین نسخه وابستگی‌ها، پرچم‌های ساخت و کلیدهای API استفاده می‌شوند. برخلاف BuildConfig، gradle.properties فقط در مرحله پیکربندی Gradle کار می‌کند، نه در زمان اجرای برنامه. بنابراین رمزهای عبور و کلیدهای API مشخص شده در gradle.properties در کد دکامپایل شده قابل مشاهده نیستند، زیرا آنها فقط برای تولید BuildConfig در مرحله کامپایل استفاده می‌شوند.

groovy
# 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 از متغیرهای محیطی از طریق بسته flutter_dotenv برای دسترسی در زمان اجرا یا از طریق کانال‌های بومی برای متغیرهای پلتفرمی پشتیبانی می‌کند. در Dart همچنین سازنده String.fromEnvironment برای ارسال مقادیر در مرحله کامپایل از طریق --dart-define در دسترس است که روش ترجیحی برای پروژه‌های Flutter می‌باشد.

تفاوت بین BuildConfig و gradle.properties چیست؟

BuildConfig — یک کلاس Java با فیلدهای تایپ‌شده است که در مرحله کامپایل برای هر buildType و flavor تولید می‌شود. gradle.properties — یک فایل متنی با جفت‌های کلید-مقدار است که برای همه ماژول‌های Gradle در مرحله پیکربندی ساخت در دسترس می‌باشد. BuildConfig در زمان اجرای برنامه کار می‌کند، gradle.properties — فقط در اسکریپت‌های Gradle.

چگونه از نشت فایل .env به مخزن جلوگیری کنیم؟

.env را به فایل .gitignore مخزن خود اضافه کنید. فقط .env.example را با مقادیر خالی و توضیح هر متغیر به مخزن commit کنید. برای CI/CD از اسرار رمزگذاری شده در تنظیمات GitHub Actions، GitLab CI یا Bitrise استفاده کنید که در لاگ‌ها پوشانده شده و پس از پایان ساخت قابل خواندن نیستند.

چگونه متغیرهای محیطی را از طریق CI/CD ارسال کنیم؟

اکثر سیستم‌های CI از متغیرهای محیطی مخفی پشتیبانی می‌کنند. در GitHub Actions اینها Secrets، در GitLab CI — CI/CD Variables، در Bitrise — Secrets نامیده می‌شوند. در مرحله ساخت، آنها از طریق process.env یا System.getenv() به اسکریپت ساخت ارسال می‌شوند. متغیرهای مخفی در لاگ‌های ساخت نمایش داده نمی‌شوند و در فورک‌های مخزن در دسترس نیستند.

feature flags از طریق متغیرهای محیطی چیست؟

Feature flags — متغیرهای بولی هستند که فعال یا غیرفعال کردن قابلیت را بدون کامپایل مجدد کد کنترل می‌کنند. مثال: FEATURE_NEW_PAYMENT=true سیستم پرداخت جدید را در staging برای آزمایش فعال می‌کند. در production همان پرچم تا استقرار کامل بک‌اند بر روی false تنظیم شده است. این امکان پیاده‌سازی ایمن تغییرات را به صورت مرحله‌ای و بازگشت آنها را در صورت بروز مشکل فراهم می‌کند.

خلاصه

  • متغیرهای محیطی پیکربندی را از کد منبع برای محیط‌های مختلف توسعه جدا می‌کنند
  • فایل‌های .env با الگوی .env.example — استاندارد مدیریت متغیرها در تیم‌ها با تفکیک محیط‌ها
  • iOS xcconfig فایل‌های پیکربندی را با پشتیبانی از وراثت و یکپارچه‌سازی Info.plist به طرح‌های Xcode متصل می‌کند
  • Android BuildConfig فیلدهای تایپ‌شده را از build.gradle برای هر buildType به طور جداگانه تولید می‌کند
  • اسرار CI/CD داده‌های حساس را بدون ذخیره در مخزن در مرحله ساخت ارسال می‌کنند
  • Feature flags از طریق متغیرها امکان فعال کردن قابلیت در محیط خاص را بدون کامپایل مجدد فراهم می‌کنند
  • امنیت: کلیدها در CI رمزگذاری شده و وارد فایل بینری قابل دکامپایل برنامه نمی‌شوند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید