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