خدمات پیش زمینه

خدمات پیش زمینه عملیاتی را انجام می دهند که برای کاربر قابل توجه است.

سرویس‌های پیش‌زمینه یک اعلان نوار وضعیت را نشان می‌دهند تا کاربران آگاه شوند که برنامه شما در حال انجام یک کار در پیش‌زمینه است و منابع سیستم را مصرف می‌کند.

نمونه هایی از برنامه هایی که از خدمات پیش زمینه استفاده می کنند عبارتند از:

  • یک برنامه پخش کننده موسیقی که موسیقی را در یک سرویس پیش زمینه پخش می کند. اعلان ممکن است آهنگ فعلی در حال پخش را نشان دهد.
  • یک برنامه تناسب اندام که پس از دریافت مجوز از کاربر، دویدن کاربر را در یک سرویس پیش زمینه ثبت می کند. این اعلان ممکن است مسافتی را که کاربر در طول جلسه تناسب اندام فعلی طی کرده است را نشان دهد.

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

این سند مجوز لازم برای استفاده از خدمات پیش زمینه و نحوه راه اندازی سرویس پیش زمینه و حذف آن از پس زمینه را توضیح می دهد. همچنین نحوه مرتبط کردن موارد استفاده خاص با انواع سرویس های پیش زمینه و محدودیت های دسترسی که هنگام راه اندازی یک سرویس پیش زمینه از برنامه ای که در پس زمینه اجرا می شود اعمال می شود، توضیح می دهد.

کاربر می تواند به طور پیش فرض اعلان را رد کند

از Android 13 (سطح API 33)، کاربران می توانند به طور پیش فرض اعلان مربوط به یک سرویس پیش زمینه را رد کنند. برای انجام این کار، کاربران یک حرکت تند کشیدن روی اعلان انجام می دهند. به طور سنتی، اعلان رد نمی شود مگر اینکه سرویس پیش زمینه متوقف شود یا از پیش زمینه حذف شود.

اگر می‌خواهید اعلان توسط کاربر قابل رد نباشد، هنگام ایجاد اعلان با استفاده از Notification.Builder ، true به متد setOngoing() ارسال کنید.

خدماتی که اعلان را فورا نشان می دهند

اگر یک سرویس پیش‌زمینه حداقل یکی از ویژگی‌های زیر را داشته باشد، سیستم اعلان مربوطه را بلافاصله پس از شروع سرویس نشان می‌دهد، حتی در دستگاه‌هایی که Android 12 یا بالاتر دارند:

در Android 13 (سطح API 33) یا بالاتر، اگر کاربر مجوز اعلان را رد کند، همچنان اعلان‌های مربوط به خدمات پیش‌زمینه را در Task Manager می‌بیند اما آنها را در کشوی اعلان نمی‌بیند.

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

در مانیفست برنامه خود، هر یک از سرویس های پیش زمینه برنامه خود را با یک عنصر <service> اعلام کنید. برای هر سرویس، از ویژگی android:foregroundServiceType استفاده کنید تا مشخص کنید که سرویس چه نوع کاری را انجام می دهد.

به عنوان مثال، اگر برنامه شما یک سرویس پیش زمینه ایجاد می کند که موسیقی پخش می کند، می توانید این سرویس را به صورت زیر اعلام کنید:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
  <application ...>

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
  </application>
</manifest>

اگر چندین نوع شما برای سرویس شما اعمال می شود، آنها را با | جدا کنید اپراتور به عنوان مثال، سرویسی که از دوربین و میکروفون استفاده می کند، آن را به صورت زیر اعلام می کند:

android:foregroundServiceType="camera|microphone"

مجوزهای سرویس پیش زمینه را درخواست کنید

برنامه‌هایی که Android 9 (سطح API 28) یا بالاتر را هدف قرار می‌دهند و از خدمات پیش‌زمینه استفاده می‌کنند، باید FOREGROUND_SERVICE را در مانیفست برنامه درخواست کنند، همانطور که در قطعه کد زیر نشان داده شده است. این یک مجوز عادی است، بنابراین سیستم به طور خودکار آن را به برنامه درخواست کننده اعطا می کند.

علاوه بر این، اگر برنامه سطح API 34 یا بالاتر را هدف قرار دهد، باید نوع مجوز مناسب را برای نوع کاری که سرویس پیش زمینه انجام می دهد درخواست کند. هر نوع سرویس پیش زمینه دارای یک نوع مجوز مربوطه است. برای مثال، اگر برنامه‌ای سرویس پیش‌زمینه‌ای را راه‌اندازی کند که از دوربین استفاده می‌کند، باید مجوزهای FOREGROUND_SERVICE و FOREGROUND_SERVICE_CAMERA را درخواست کنید. اینها همه مجوزهای عادی هستند، بنابراین اگر در مانیفست فهرست شده باشند، سیستم به طور خودکار آنها را اعطا می کند.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>

    <application ...>
        ...
    </application>
</manifest>

پیش نیازهای خدمات پیش زمینه

با شروع Android 14 (سطح API 34)، هنگامی که یک سرویس پیش زمینه را راه اندازی می کنید، سیستم پیش نیازهای خاصی را بر اساس نوع سرویس بررسی می کند. برای مثال، اگر می‌خواهید یک سرویس پیش‌زمینه از نوع location را راه‌اندازی کنید، سیستم بررسی می‌کند تا مطمئن شود برنامه شما قبلاً مجوز ACCESS_COARSE_LOCATION یا ACCESS_FINE_LOCATION را دارد. اگر این کار را نکرد، سیستم SecurityException را پرتاب می کند.

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

یک سرویس پیش زمینه را شروع کنید

قبل از اینکه از سیستم درخواست کنید تا یک سرویس را به عنوان سرویس پیش زمینه اجرا کند، خود سرویس را راه اندازی کنید:

کاتلین

val intent = Intent(...) // Build the intent for the service
context.startForegroundService(intent)

جاوا

Context context = getApplicationContext();
Intent intent = new Intent(...); // Build the intent for the service
context.startForegroundService(intent);

در داخل سرویس، معمولاً در onStartCommand() می توانید درخواست کنید که سرویس شما در پیش زمینه اجرا شود. برای انجام این کار، با ServiceCompat.startForeground() (موجود در androidx-core نسخه 1.12 و بالاتر) تماس بگیرید. این روش پارامترهای زیر را می گیرد:

  • سرویس
  • یک عدد صحیح مثبت که به طور منحصر به فرد اعلان را در نوار وضعیت شناسایی می کند
  • خود شیء Notification
  • انواع خدمات پیش زمینه شناسایی کار انجام شده توسط سرویس

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

برای مثال، فرض کنید یک برنامه تناسب اندام یک سرویس ردیاب در حال اجرا را اجرا می کند که همیشه به اطلاعات location نیاز دارد، اما ممکن است نیاز به پخش رسانه داشته باشد یا نداشته باشد. باید هم location و هم mediaPlayback را در مانیفست اعلام کنید. اگر کاربر یک اجرا را شروع می‌کند و فقط می‌خواهد موقعیت مکانی او ردیابی شود، برنامه شما باید startForeground() فراخوانی کند و فقط مجوز ACCESS_FINE_LOCATION پاس کند. سپس، اگر کاربر می‌خواهد پخش صدا را شروع کند، دوباره startForeground() را فراخوانی کنید و ترکیب بیتی همه انواع سرویس‌های پیش‌زمینه (در این مورد، ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK ) را ارسال کنید.

در اینجا یک مثال است که یک سرویس پیش زمینه دوربین را راه اندازی می کند:

کاتلین

class MyCameraService: Service() {

  private fun startForeground() {
    // Before starting the service as foreground check that the app has the
    // appropriate runtime permissions. In this case, verify that the user has
    // granted the CAMERA permission.
    val cameraPermission =
            PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA)
    if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) {
        // Without camera permissions the service cannot run in the foreground
        // Consider informing user or updating your app UI if visible.
        stopSelf()
        return
    }

    try {
        val notification = NotificationCompat.Builder(this, "CHANNEL_ID")
            // Create the notification to display while the service is running
            .build()
        ServiceCompat.startForeground(
            /* service = */ this,
            /* id = */ 100, // Cannot be 0
            /* notification = */ notification,
            /* foregroundServiceType = */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
            } else {
                0
            },
        )
    } catch (e: Exception) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
                && e is ForegroundServiceStartNotAllowedException) {
            // App not in a valid state to start foreground service
            // (e.g. started from bg)
        }
        // ...
    }
  }
}

جاوا

public class MyCameraService extends Service {

    private void startForeground() {
        // Before starting the service as foreground check that the app has the
        // appropriate runtime permissions. In this case, verify that the user
        // has granted the CAMERA permission.
        int cameraPermission =
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (cameraPermission == PackageManager.PERMISSION_DENIED) {
            // Without camera permissions the service cannot run in the
            // foreground. Consider informing user or updating your app UI if
            // visible.
            stopSelf();
            return;
        }

        try {
            Notification notification =
                new NotificationCompat.Builder(this, "CHANNEL_ID")
                    // Create the notification to display while the service
                    // is running
                    .build();
            int type = 0;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
            }
            ServiceCompat.startForeground(
                    /* service = */ this,
                    /* id = */ 100, // Cannot be 0
                    /* notification = */ notification,
                    /* foregroundServiceType = */ type
            );
        } catch (Exception e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
                    e instanceof ForegroundServiceStartNotAllowedException
            ) {
                // App not in a valid state to start foreground service
                // (e.g started from bg)
            }
            // ...
        }
    }

    //...
}

یک سرویس را از پیش زمینه حذف کنید

برای حذف سرویس از پیش زمینه، stopForeground() فراخوانی کنید. این روش یک بولی می گیرد که نشان می دهد اعلان نوار وضعیت نیز حذف شود. توجه داشته باشید که سرویس به کار خود ادامه می دهد.

اگر سرویس را در حالی که در پیش زمینه اجرا می شود متوقف کنید، اعلان آن حذف می شود.

توقف برنامه‌هایی را که خدمات پیش‌زمینه اجرا می‌کنند توسط کاربر مدیریت کنید

در پایین کشوی اعلان ها دکمه ای وجود دارد که تعداد برنامه هایی را که در حال حاضر در پس زمینه در حال اجرا هستند را نشان می دهد. هنگامی که این دکمه را فشار می دهید، یک گفتگو ظاهر می شود که نام برنامه های مختلف را لیست می کند. دکمه Stop در سمت راست هر برنامه قرار دارد
شکل 1. گردش کار Task Manager در دستگاه هایی که اندروید 13 یا بالاتر را اجرا می کنند.

با شروع Android 13 (سطح API 33)، کاربران می‌توانند یک گردش کار را از کشوی اعلان‌ها تکمیل کنند تا برنامه‌ای را که سرویس‌های پیش‌زمینه در حال انجام دارد، بدون توجه به نسخه SDK هدف آن برنامه، متوقف کنند. این توانایی که Task Manager نامیده می شود، لیستی از برنامه هایی را نشان می دهد که در حال حاضر یک سرویس پیش زمینه را اجرا می کنند.

این لیست دارای برچسب برنامه های فعال است. در کنار هر برنامه یک دکمه توقف وجود دارد. شکل 1 گردش کار Task Manager را در دستگاهی که اندروید 13 را اجرا می کند، نشان می دهد.

هنگامی که کاربر دکمه Stop را در کنار برنامه شما در Task Manager فشار می دهد، اقدامات زیر انجام می شود:

  • سیستم برنامه شما را از حافظه حذف می کند. بنابراین، کل برنامه شما متوقف می شود ، نه فقط سرویس پیش زمینه در حال اجرا.
  • سیستم پشته فعالیت برنامه شما را حذف می کند.
  • هر پخش رسانه ای متوقف می شود.
  • اعلان مربوط به سرویس پیش زمینه حذف می شود.
  • برنامه شما در تاریخ باقی می ماند.
  • کارهای برنامه ریزی شده در زمان برنامه ریزی شده خود اجرا می شوند.
  • هشدارها در زمان یا پنجره زمانی برنامه ریزی شده خود خاموش می شوند.

برای آزمایش اینکه برنامه شما همانطور که انتظار می رود در زمانی که کاربر برنامه شما را متوقف می کند و پس از آن عمل می کند، دستور ADB زیر را در پنجره ترمینال اجرا کنید:

adb shell cmd activity stop-app PACKAGE_NAME

معافیت ها

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

معافیت ها برای هر برنامه است، نه برای هر فرآیند. اگر سیستم یک فرآیند را در یک برنامه مستثنی کند، همه فرآیندهای دیگر در آن برنامه نیز معاف هستند.

معافیت از ظاهر شدن در Task Manager اصلا

برنامه های زیر می توانند یک سرویس پیش زمینه را اجرا کنند و اصلاً در Task Manager ظاهر نشوند:

  • برنامه های سطح سیستم
  • برنامه های ایمنی؛ یعنی برنامه هایی که نقش ROLE_EMERGENCY را دارند
  • دستگاه هایی که در حالت نمایشی هستند

معافیت های قابل توقف توسط کاربران

هنگامی که انواع برنامه‌های زیر یک سرویس پیش‌زمینه را اجرا می‌کنند، در Task Manager ظاهر می‌شوند، اما دکمه Stop در کنار نام برنامه وجود ندارد تا کاربر روی آن ضربه بزند:

به جای سرویس های پیش زمینه، از API های ساخته شده با هدف استفاده کنید

برای بسیاری از موارد استفاده، پلتفرم یا API های Jetpack وجود دارد که می توانید از آنها برای انجام کارهایی استفاده کنید که در غیر این صورت ممکن است از یک سرویس پیش زمینه استفاده کنید. اگر یک API مناسب برای هدف وجود دارد، تقریباً همیشه باید به جای استفاده از سرویس پیش زمینه از آن استفاده کنید. APIهای ساخته شده با هدف اغلب قابلیت‌های خاص مورد استفاده اضافی را ارائه می‌دهند که در غیر این صورت مجبور خواهید بود خودتان آن را بسازید. برای مثال، Bubbles API منطق پیچیده رابط کاربری را برای برنامه‌های پیام‌رسانی که نیاز به اجرای ویژگی‌های حباب چت دارند، مدیریت می‌کند.

اسناد مربوط به انواع سرویس های پیش زمینه، جایگزین های خوبی را برای استفاده به جای خدمات پیش زمینه فهرست می کند.

محدودیت در راه اندازی یک سرویس پیش زمینه از پس زمینه

برنامه‌هایی که Android 12 یا بالاتر را هدف قرار می‌دهند، نمی‌توانند سرویس‌های پیش‌زمینه را در حالی که برنامه در پس‌زمینه اجرا می‌شود راه‌اندازی کنند، به جز چند مورد خاص . اگر برنامه ای سعی کند یک سرویس پیش زمینه را در حالی که برنامه در پس زمینه اجرا می شود راه اندازی کند و سرویس پیش زمینه یکی از موارد استثنایی را برآورده نکند، سیستم یک ForegroundServiceStartNotAllowedException را پرتاب می کند.

به‌علاوه، اگر برنامه‌ای بخواهد سرویس پیش‌زمینه‌ای را راه‌اندازی کند که به مجوزهای حین استفاده نیاز دارد (مثلاً مجوزهای حسگر بدن، دوربین، میکروفون یا موقعیت مکانی)، نمی‌تواند در حالی که برنامه در پس‌زمینه است، سرویس را ایجاد کند ، حتی اگر برنامه در یکی از معافیت‌های محدودیت‌های شروع پس‌زمینه قرار گیرد. دلیل این امر در بخش محدودیت‌های شروع سرویس‌های پیش‌زمینه که به مجوزهای حین استفاده نیاز دارند توضیح داده شده است.

معافیت از محدودیت های شروع پس زمینه

در شرایط زیر، برنامه شما می‌تواند خدمات پیش‌زمینه را حتی زمانی که برنامه شما در پس‌زمینه اجرا می‌شود راه‌اندازی کند:

محدودیت‌هایی در راه‌اندازی سرویس‌های پیش‌زمینه که به مجوزهای حین استفاده نیاز دارند

در Android 14 (سطح API 34) یا بالاتر، اگر در حال راه‌اندازی یک سرویس پیش‌زمینه هستید که به مجوزهای حین استفاده نیاز دارد، شرایط خاصی وجود دارد که باید از آنها آگاه باشید.

اگر برنامه شما اندروید 14 یا بالاتر را هدف قرار می‌دهد، سیستم عامل زمانی که یک سرویس پیش‌زمینه ایجاد می‌کنید، بررسی می‌کند تا مطمئن شود برنامه شما همه مجوزهای مناسب برای آن نوع سرویس را دارد. به عنوان مثال، هنگامی که یک سرویس پیش زمینه از نوع میکروفون ایجاد می کنید، سیستم عامل تأیید می کند که برنامه شما در حال حاضر مجوز RECORD_AUDIO را دارد. اگر آن مجوز را نداشته باشید، سیستم یک SecurityException می اندازد.

برای مجوزهای حین استفاده، این باعث یک مشکل بالقوه می شود. اگر برنامه شما دارای مجوز حین استفاده است، تنها زمانی که در پیش زمینه است این مجوز را دارد. این بدان معناست که اگر برنامه شما در پس‌زمینه است و سعی می‌کند یک سرویس پیش‌زمینه از نوع دوربین، مکان یا میکروفون ایجاد کند، سیستم می‌بیند که برنامه شما در حال حاضر مجوزهای لازم را ندارد و یک SecurityException می‌زند.

به طور مشابه، اگر برنامه شما در پس‌زمینه باشد و یک سرویس بهداشتی ایجاد کند که به مجوز BODY_SENSORS نیاز دارد، برنامه در حال حاضر این مجوز را ندارد و سیستم یک استثنا ایجاد می‌کند. (اگر این یک سرویس بهداشتی باشد که به مجوزهای مختلفی نیاز دارد، مانند ACTIVITY_RECOGNITION این مورد اعمال نمی شود.) فراخوانی PermissionChecker.checkSelfPermission() از این مشکل جلوگیری نمی کند. اگر برنامه شما مجوز while-in-use داشته باشد، و checkSelfPermission() را فراخوانی کند تا بررسی کند که آیا این مجوز را دارد، روش PERMISSION_GRANTED را برمی گرداند حتی اگر برنامه در پس زمینه باشد. وقتی روش PERMISSION_GRANTED را برمی گرداند، می گوید "برنامه شما این مجوز را در زمانی که برنامه در حال استفاده است دارد."

به همین دلیل، اگر سرویس پیش‌زمینه شما به مجوز استفاده در حین استفاده نیاز دارد، باید Context.startForegroundService() یا Context.bindService() در حالی که برنامه شما دارای فعالیت قابل مشاهده است، فراخوانی کنید، مگر اینکه سرویس در یکی از معافیت‌های تعریف شده قرار گیرد.

معافیت از محدودیت در مجوزهای در حین استفاده

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

در همین شرایط، اگر سرویس یک نوع location سرویس پیش‌زمینه را اعلام کند و توسط برنامه‌ای راه‌اندازی شود که دارای مجوز ACCESS_BACKGROUND_LOCATION است، این سرویس می‌تواند همیشه به اطلاعات مکان دسترسی داشته باشد، حتی زمانی که برنامه در پس‌زمینه اجرا می‌شود.

لیست زیر شامل این موقعیت ها است:

  • یک جزء سیستم سرویس را شروع می کند.
  • این سرویس با تعامل با ویجت های برنامه شروع می شود.
  • این سرویس با تعامل با یک اعلان شروع می شود.
  • این سرویس به عنوان یک PendingIntent شروع می شود که از یک برنامه قابل مشاهده و متفاوت ارسال می شود.
  • این سرویس توسط برنامه ای شروع می شود که یک کنترل کننده خط مشی دستگاه است که در حالت مالک دستگاه اجرا می شود.
  • این سرویس توسط برنامه‌ای شروع می‌شود که VoiceInteractionService را ارائه می‌کند.
  • این سرویس توسط برنامه‌ای شروع می‌شود که دارای مجوز ممتاز START_ACTIVITIES_FROM_BACKGROUND است.
تعیین کنید کدام سرویس ها در برنامه شما تحت تأثیر قرار می گیرند

هنگام آزمایش برنامه خود، خدمات پیش زمینه آن را شروع کنید. اگر سرویس شروع شده دسترسی به مکان، میکروفون و دوربین را محدود کرده باشد، پیام زیر در Logcat ظاهر می شود:

Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME