الخدمات التي تعمل في المقدّمة

تُنفِّذ الخدمات التي تعمل في المقدّمة عمليات يلاحظها المستخدم.

تعرِض الخدمات التي تعمل في المقدّمة إشعارًا في شريط الحالة لإعلام المستخدمين بأنّ تطبيقك ينفِّذ مهمة في المقدّمة ويستهلك موارد النظام.

تشمل أمثلة التطبيقات التي تستخدم الخدمات التي تعمل في المقدّمة ما يلي:

  • تطبيق مشغّل موسيقى يشغّل الموسيقى في خدمة تعمل في المقدّمة قد يعرض الإشعار الأغنية الحالية التي يتم تشغيلها.
  • يشير ذلك المصطلح إلى تطبيق للّياقة البدنية يسجّل ما ينفّذه المستخدم في خدمة تعمل في المقدّمة، بعد تلقّي الإذن من المستخدم. قد يعرض الإشعار المسافة التي قطعها المستخدم خلال جلسة اللياقة البدنية الحالية.

لا تستخدِم خدمة تعمل في المقدّمة إلا عندما يحتاج تطبيقك إلى تنفيذ مهمة يلاحظها المستخدم، حتى عندما لا يتفاعل مباشرةً مع التطبيق. إذا كان الإجراء منخفض الأهمية لدرجة أنّك تريد استخدام إشعار بأولوية منخفضة، أنشئ مهمة تعمل في الخلفية بدلاً من ذلك.

يوضّح هذا المستند الإذن المطلوب لاستخدام الخدمات التي تعمل في المقدّمة، وكيفية بدء خدمة تعمل في المقدّمة وإزالتها من الخلفية. وتوضّح أيضًا كيفية ربط حالات استخدام معيّنة بأنواع الخدمات التي تعمل في المقدّمة، وقيود الوصول التي تسري عند بدء تشغيل خدمة تعمل في المقدّمة من تطبيق يعمل في الخلفية.

يمكن للمستخدم إغلاق الإشعار تلقائيًا.

اعتبارًا من الإصدار 13 من نظام التشغيل Android (المستوى 33 من واجهة برمجة التطبيقات)، يمكن للمستخدمين إغلاق الإشعار المرتبط بخدمة تعمل في المقدّمة تلقائيًا. لإجراء ذلك، ينفّذ المستخدمون إيماءة التمرير سريعًا على الإشعار. في العادة، لا يتم إغلاق الإشعار ما لم يتم إيقاف الخدمة التي تعمل في المقدّمة أو إزالتها من المقدّمة.

إذا كنت تريد أن لا يتمكّن المستخدم من إغلاق الإشعار، نقْلtrue إلى طريقة setOngoing() عند إنشاء الإشعار باستخدام Notification.Builder.

الخدمات التي تعرِض إشعارًا على الفور

إذا كانت الخدمة التي تعمل في المقدّمة تتضمّن واحدة على الأقل من السمات التالية، يعرض النظام الإشعار المرتبط بها مباشرةً بعد بدء الخدمة، حتى على الأجهزة التي تعمل بنظام التشغيل Android 12 أو إصدار أحدث:

في الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، إذا رفض المستخدم إذن الإشعارات، سيظل بإمكانه الاطّلاع على الإشعارات المتعلّقة بالخدمات التي تعمل في المقدّمة في مدير المهام ولكن لن تظهر له في مربّع الإشعارات.

تقديم بيان عن الخدمات التي تعمل في المقدّمة في ملف البيان

في ملف بيان تطبيقك، يُرجى تحديد كل خدمة من الخدمات التي تعمل في المقدّمة في تطبيقك باستخدام عنصر <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 (المستوى 28 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث وتستخدم خدمات تعمل في المقدّمة طلب عرض السمة FOREGROUND_SERVICE في بيان التطبيق كما هو موضّح في مقتطف الرمز التالي. هذا إذن عادي، لذا يمنحه النظام تلقائيًا للتطبيق الذي يطلبه.

بالإضافة إلى ذلك، إذا كان التطبيق يستهدف المستوى 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 (المستوى 34 لواجهة برمجة التطبيقات)، عند تشغيل خدمة تعمل في المقدّمة، يبحث النظام عن متطلبات أساسية معيّنة استنادًا إلى نوع الخدمة. على سبيل المثال، إذا حاولت تشغيل خدمة تعمل في المقدّمة من النوع location، يتحقق النظام للتأكّد من أنّ تطبيقك لديه إذن ACCESS_COARSE_LOCATION أو ACCESS_FINE_LOCATION. وإذا لم يحدث ذلك، يعرض النظام SecurityException.

لهذا السبب، عليك التأكّد من استيفاء المتطلبات الأساسية المطلوبة قبل بدء استخدام خدمة تعمل في المقدّمة. تسرد مستندات نوع الخدمة التي تعمل في المقدّمة المتطلبات الأساسية المطلوبة لكل نوع من أنواع الخدمات التي تعمل في المقدّمة.

بدء خدمة تعمل في المقدّمة

قبل أن تطلب من النظام تشغيل خدمة كخدمة تعمل في المقدّمة، ابدأ الخدمة نفسها:

Kotlin

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

Java

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

داخل الخدمة، يمكنك عادةً في onStartCommand()طلب تشغيل خدمتك في المقدّمة. لإجراء ذلك، يمكنك الاتصال بـ ServiceCompat.startForeground() (متاح في androidx-core 1.12 والإصدارات الأحدث). تأخذ هذه الطريقة المَعلمات التالية:

قد تكون هذه الأنواع مجموعة فرعية من الأنواع المُعلَن عنها في البيان، استنادًا إلى حالة الاستخدام المحدّدة. بعد ذلك، إذا كنت بحاجة إلى إضافة المزيد من أنواع الخدمات، يمكنك الاتصال برقم startForeground() مرة أخرى.

على سبيل المثال، لنفترض أنّ تطبيق لياقة بدنية يشغّل خدمة تتبُّع الركض التي تحتاج دائمًا إلى معلومات location، ولكن قد تحتاج أو لا تحتاج إلى تشغيل الوسائط. عليك الإفصاح عن كل من location وmediaPlayback في البيان. إذا بدأ أحد المستخدمين جولة ركض وأردت تتبُّع موقعه الجغرافي فقط، يجب أن يتصل تطبيقك بواجهة برمجة التطبيقات startForeground() ويرسل الإذن ACCESS_FINE_LOCATION فقط. بعد ذلك، إذا أراد المستخدم بدء تشغيل الصوت، يُرجى الاتصال بالرقم startForeground() مرة أخرى وإرسال مجموعة الأعداد الثنائية لجميع أنواع الخدمات التي تعمل في المقدّمة (في هذه الحالة، ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).

في ما يلي مثال لبدء خدمة تعمل في المقدّمة للكاميرا:

Kotlin

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)
        }
        // ...
    }
  }
}

Java

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(). تأخذ هذه الطريقة قيمة منطقية تشير إلى ما إذا كان سيتم أيضًا إزالة الإشعار من شريط الحالة. يُرجى العلم أنّ الخدمة ستبقى مفعّلة.

في حال إيقاف الخدمة أثناء تشغيلها في المقدّمة، تتم إزالة إشعارها.

التعامل مع عمليات إيقاف التطبيقات التي تعمل بخدمات تعمل في المقدّمة والتي بدأها المستخدم

ويظهر زر أسفل درج الإشعارات يشير إلى عدد التطبيقات التي تعمل في الخلفية حاليًا. عند الضغط على
    هذا الزر، يظهر مربّع حوار يسرد أسماء التطبيقات المختلفة. يظهر
    زر &quot;إيقاف&quot; على يسار كل تطبيق
الشكل 1. سير عمل "مدير المهام" على الأجهزة التي تعمل بالإصدار 13 من نظام التشغيل Android أو إصدار أحدث

بدءًا من الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات)، يمكن للمستخدمين إكمال سير عمل من درج الإشعارات لإيقاف تطبيق يشغّل خدمات تعمل في المقدّمة، بغض النظر عن إصدار حِزمة تطوير البرامج (SDK) المستهدَف لهذا التطبيق. وتعرض هذه الميزة، التي يُطلق عليها إدارة المهام، قائمة بالتطبيقات التي تشغِّل حاليًا خدمة تعمل في المقدّمة.

تظهر هذه القائمة بعنوان التطبيقات النشطة. بجانب كل تطبيق، يظهر زر إيقاف. يوضِّح الشكل 1 سير عمل "مدير المهام" على جهاز يعمل بنظام التشغيل Android 13.

عندما يضغط المستخدم على الزر إيقاف بجانب تطبيقك في مدير المهام، تحدث الإجراءات التالية:

  • يزيل النظام تطبيقك من الذاكرة. لذلك، يتوقف تطبيقك بالكامل، وليس الخدمة التي تعمل في المقدّمة فقط.
  • يزيل النظام حزمة نشاط تطبيقك الخلفية.
  • يتم إيقاف تشغيل أي وسائط.
  • تتم إزالة الإشعار المرتبط بالخدمة التي تعمل في المقدّمة.
  • سيظلّ تطبيقك مُدرَجًا في السجلّ.
  • يتم تنفيذ المهام المُجدوَلة في الوقت المحدّد.
  • يتم تشغيل المنبّهات في الوقت أو الفترة الزمنية المحدّدة.

لاختبار أنّ تطبيقك يعمل على النحو المتوقّع أثناء إيقاف أحد المستخدمين لتطبيقك وبعد إيقافه، شغِّل الأمر ADB التالي في نافذة طرفية:

adb shell cmd activity stop-app PACKAGE_NAME

الإعفاءات

يوفر النظام مستويات متعددة من الإعفاءات لأنواع معيّنة من التطبيقات، وتصفها الأقسام التالية.

تُمنح الإعفاءات لكل تطبيق على حدة، وليس لكل عملية. إذا أعفى النظام عملية واحدة في أحد التطبيقات، سيتم أيضًا إعفاء جميع العمليات الأخرى في ذلك التطبيق.

حالات الإعفاء من الظهور في "مدير المهام" على الإطلاق

يمكن للتطبيقات التالية تشغيل خدمة تعمل في المقدّمة ولا تظهر في مدير المهام على الإطلاق:

  • التطبيقات على مستوى النظام
  • تطبيقات السلامة، أي التطبيقات التي لها دور ROLE_EMERGENCY
  • الأجهزة التي تكون في الوضع التجريبي

حالات الإعفاء من إمكانية إيقافها من قِبل المستخدمين

عندما تعمل الأنواع التالية من التطبيقات على خدمة تعمل في المقدّمة، تظهر في مدير المهام، ولكن لا يتوفّر زر إيقاف بجانب اسم التطبيق لينقره المستخدم:

استخدام واجهات برمجة تطبيقات مخصّصة بدلاً من الخدمات التي تعمل في المقدّمة

في العديد من حالات الاستخدام، تتوفّر واجهات برمجة تطبيقات لمنصّة Android أو Jetpack يمكنك استخدامها لتنفيذ مهام قد تستخدمها في حال عدم توفّر خدمة تعمل في المقدّمة. إذا كانت هناك واجهة برمجة تطبيقات مناسبة مصمّمة لهذا الغرض، يجب استخدامها في معظم الأحيان بدلاً من استخدام خدمة تعمل في المقدّمة. غالبًا ما توفّر واجهات برمجة التطبيقات المخصّصة لأغراض معيّنة ميزات إضافية تتعلّق بحالة الاستخدام التي يتعذّر عليك إنشاؤها بنفسك. على سبيل المثال، تعالج Bubbles API منطق واجهة المستخدم المعقّد لتطبيقات المراسلة التي تحتاج إلى تنفيذ ميزات فقاعات المحادثات.

تسرد مستندات أنواع الخدمات التي تعمل في المقدّمة بدائل جيدة لاستخدامها بدلاً من الخدمات التي تعمل في المقدّمة.

القيود المفروضة على بدء خدمة تعمل في المقدّمة من الخلفية

لا يمكن للتطبيقات التي تستهدف الإصدار 12 من Android أو الإصدارات الأحدث بدء خدمات تعمل في المقدّمة أثناء تشغيل التطبيق في الخلفية، باستثناء بعض الحالات الخاصة. إذا حاول أحد التطبيقات بدء خدمة تعمل في المقدّمة أثناء تشغيل التطبيق في الخلفية، ولم تستوفِ الخدمة التي تعمل في المقدّمة أحد الحالات الاستثنائية، يُرسِل النظام ForegroundServiceStartNotAllowedException.

بالإضافة إلى ذلك، إذا أراد أحد التطبيقات إطلاق خدمة تعمل في المقدّمة تحتاج إلى أذونات قيد الاستخدام (مثل أذونات أداة استشعار الجسم أو الكاميرا أو الميكروفون أو أذونات تحديد الموقع الجغرافي)، لن يتمكّن من إنشاء الخدمة أثناء تشغيل التطبيق في الخلفية، حتى إذا كان يندرج ضمن أحد الاستثناءات المرتبطة بقيود البدء في الخلفية. ويتم توضيح سبب ذلك في قسم القيود المفروضة على بدء تشغيل الخدمات التي تعمل في المقدّمة والتي تحتاج إلى أذونات أثناء الاستخدام.

الاستثناءات من القيود المفروضة على بدء الخدمات عندما تكون التطبيقات قيد التشغيل في الخلفية

في الحالات التالية، يمكن لتطبيقك بدء الخدمات التي تعمل في المقدّمة حتى أثناء تشغيل تطبيقك في الخلفية:

القيود المفروضة على بدء الخدمات التي تعمل في المقدّمة التي تحتاج إلى أذونات أثناء الاستخدام

في نظام التشغيل Android 14 (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، هناك مواقف خاصة يجب الانتباه إليها إذا كنت تبدأ خدمة تعمل في المقدّمة تحتاج إلى أذونات أثناء الاستخدام.

إذا كان تطبيقك يستهدف Android 14 أو إصدارًا أحدث، يتحقّق نظام التشغيل من إنشاء خدمة تعمل في المقدّمة للتأكّد من أنّ تطبيقك يتضمّن جميع الأذونات المناسبة لنوع الخدمة هذا. على سبيل المثال، عند إنشاء خدمة تعمل في المقدّمة من النوع الميكروفون، يتحقق نظام التشغيل من أنّ تطبيقك يمتلك حاليًا الإذن RECORD_AUDIO. إذا لم يكن لديك هذا الإذن، سيُرسِل النظام خطأ SecurityException.

بالنسبة إلى الأذونات التي يتم استخدامها أثناء التشغيل، قد يؤدي ذلك إلى حدوث مشكلة محتملة. إذا كان تطبيقك يمتلك إذنًا أثناء الاستخدام، لن يحصل على هذا الإذن إلا أثناء كونه في المقدّمة. وهذا يعني أنّه إذا كان تطبيقك قيد التشغيل في الخلفية وحاول إنشاء خدمة تعمل في المقدّمة من النوع "الكاميرا" أو "الموقع الجغرافي" أو "الميكروفون"، سيلاحظ النظام أنّ تطبيقك لا يملك حاليًا الأذونات المطلوبة، وسيُرسِل SecurityException.

وبالمثل، إذا كان تطبيقك يعمل في الخلفية وينشئ خدمة صحية تحتاج إلى إذن BODY_SENSORS، يعني ذلك أنّ التطبيق لا يملك حاليًا هذا الإذن، ويطرح النظام استثناءً. (لا ينطبق ذلك إذا كانت الخدمة صحية وتحتاج إلى أذونات مختلفة، مثل ACTIVITY_RECOGNITION.) لا يؤدي الاتصال برقم PermissionChecker.checkSelfPermission() إلى منع حدوث هذه المشكلة. إذا كان تطبيقك يمتلك إذنًا أثناء الاستخدام، ويشغّل 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