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

هناك خطوتان لبدء خدمة تعمل في المقدّمة من تطبيقك. أولاً، يجب بدء الخدمة من خلال استدعاء context.startForegroundService(). بعد ذلك، اطلب من الخدمة الاتصال ServiceCompat.startForeground() لتعزيز نفسها إلى خدمة تعمل في المقدّمة.

المتطلّبات الأساسية

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

  • لا يُسمح للتطبيقات التي تستهدف الإصدار 12 من نظام Android (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث ببدء خدمة تعمل في المقدّمة عندما يكون التطبيق في الخلفية، باستثناء بعض الاستثناءات المحدّدة. لمزيد من المعلومات ومعلومات عن استثناءات هذه القاعدة، يُرجى الاطّلاع على القيود المفروضة على بدء خدمة تعمل في المقدّمة من الخلفية.

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

بدء خدمة

لبدء خدمة تعمل في المقدّمة، يجب أولاً إطلاقها كخدمة عادية (غير تعمل في المقدّمة):

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);

النقاط الرئيسية حول الرمز

  • يشغِّل مقتطف الرمز خدمة. ومع ذلك، لا يتم تشغيل الخدمة في المقدّمة بعد. داخل الخدمة نفسها، عليك الاتصال ServiceCompat.startForeground() لتعزيز الخدمة إلى خدمة في المقدّمة.

ترقية خدمة إلى المقدّمة

بعد تشغيل الخدمة، عليك الاتصال بالرمز البرمجي ServiceCompat.startForeground() لطلب تنفيذ الخدمة في المقدّمة. عادةً ما يتم استدعاء هذه الطريقة في الطريقة onStartCommand() للخدمة.

تأخذ الدالة ServiceCompat.startForeground() المَعلمات التالية:

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

    //...
}

النقاط الرئيسية حول الرمز

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