ترسل تطبيقات Android الرسائل المتعددة البث وتتلقّاها من نظام Android ومن تطبيقات Android الأخرى، على غرار نمط التصميم للنشر والاشتراك. يرسل النظام والتطبيقات عادةً عمليات بث عند وقوع أحداث معيّنة. على سبيل المثال، يرسل نظام Android عمليات بث عند وقوع أحداث مختلفة في النظام، مثل بدء تشغيل النظام أو شحن الجهاز. ترسل التطبيقات أيضًا عمليات بث مخصّصة، مثلاً لإعلام التطبيقات الأخرى بشيء قد يهمّها (مثل تنزيل بيانات جديدة).
يمكن للتطبيقات التسجيل لتلقّي إشعارات بث محدّدة. عند إرسال بث، يوجّه النظام البث تلقائيًا إلى التطبيقات التي اشتركت لتلقّي هذا النوع من البث.
بشكل عام، يمكن استخدام عمليات البث كنظام مراسلة على مستوى التطبيقات وخارج مسار المستخدم العادي. ومع ذلك، يجب توخّي الحذر وعدم إساءة استخدام فرصة الرد على عمليات البث وتشغيل المهام في الخلفية التي يمكن أن تساهم في بطء أداء النظام.
لمحة عن رسائل البث من النظام
يرسل النظام تلقائيًا عمليات بث عند حدوث أحداث مختلفة في النظام، مثل عندما ينتقل النظام إلى "وضع الطائرة" أو يخرج منه. تتلقّى جميع التطبيقات المشترَكة عمليات البث هذه.
يغلّف العنصر Intent الإعلان على جميع الأجهزة. تحدّد السلسلة action الحدث الذي وقع، مثل android.intent.action.AIRPLANE_MODE. قد يتضمّن الغرض أيضًا معلومات إضافية مجمّعة في حقل البيانات الإضافية.
على سبيل المثال، يتضمّن الغرض من "وضع الطائرة" قيمة منطقية إضافية تشير إلى ما إذا كان "وضع الطائرة" مفعّلاً أم لا.
لمزيد من المعلومات حول كيفية قراءة الأهداف والحصول على سلسلة الإجراءات من هدف، راجِع الأهداف وفلاتر الأهداف.
إجراءات البث في النظام
للاطّلاع على قائمة كاملة بإجراءات رسائل البث من النظام، راجِع ملف BROADCAST_ACTIONS.TXT في حزمة تطوير البرامج (SDK) لنظام التشغيل Android. يتضمّن كل إجراء بث حقلًا ثابتًا مرتبطًا به. على سبيل المثال، قيمة الثابت
ACTION_AIRPLANE_MODE_CHANGED هي android.intent.action.AIRPLANE_MODE.
تتوفّر مستندات لكل إجراء بث في الحقل الثابت المرتبط به.
التغييرات التي تطرأ على عمليات البث في النظام
مع تطوّر نظام Android الأساسي، يتم بشكل دوري تغيير طريقة عمل عمليات البث على مستوى النظام. يجب مراعاة التغييرات التالية لتوفير الدعم لجميع إصدارات Android.
Android 16
في Android 16، لن نضمن ترتيب تسليم عمليات البث باستخدام السمة android:priority أو IntentFilter.setPriority() في العمليات المختلفة. يتم الالتزام بأولويات البث
ضمن عملية التطبيق نفسها فقط، وليس على مستوى جميع العمليات.
بالإضافة إلى ذلك، يتم تلقائيًا حصر أولويات البث في النطاق
(SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1).
يُسمح لمكوّنات النظام فقط بضبط SYSTEM_LOW_PRIORITY,
SYSTEM_HIGH_PRIORITY كأولوية البث.
Android 14
عندما تكون التطبيقات في حالة التخزين المؤقت، يحسِّن النظام عملية بث البيانات
للحفاظ على سلامة النظام. على سبيل المثال، يؤجّل النظام عمليات البث الأقل أهمية، مثل ACTION_SCREEN_ON، عندما يكون التطبيق في حالة التخزين المؤقت.
بعد أن ينتقل التطبيق من حالة التخزين المؤقت إلى دورة حياة نشطة للعملية، يسلّم النظام أي عمليات بث مؤجّلة.
عمليات البث المهمة التي يتم الإعلان عنها في ملف البيان تؤدي إلى إزالة التطبيقات مؤقتًا من حالة التخزين المؤقت لتسليمها.
Android 9
بدءًا من Android 9 (مستوى واجهة برمجة التطبيقات 28)، لا يتلقّى البث NETWORK_STATE_CHANGED_ACTION معلومات حول الموقع الجغرافي للمستخدم أو البيانات التي تكشف الهوية الشخصية.
إذا تم تثبيت تطبيقك على جهاز يعمل بالإصدار 9.0 من نظام التشغيل Android (المستوى 28 من واجهة برمجة التطبيقات) أو إصدار أحدث، لن يتضمّن النظام معرّفات SSID أو BSSID أو معلومات الاتصال أو نتائج البحث في عمليات بث شبكة Wi-Fi. للحصول على هذه المعلومات، يُرجى الاتصال بالرقم
getConnectionInfo() بدلاً من ذلك.
Android 8.0
بدءًا من الإصدار 8.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 26)، يفرض النظام قيودًا إضافية على أدوات الاستقبال المعرَّفة في ملف البيان.
إذا كان تطبيقك يستهدف الإصدار 8.0 من نظام التشغيل Android أو الإصدارات الأحدث، لا يمكنك استخدام البيان لتحديد مستقبل لمعظم عمليات البث الضمنية (عمليات البث التي لا تستهدف تطبيقك تحديدًا). سيظل بإمكانك استخدام مستقبِل مسجَّل في السياق عندما يستخدم المستخدم تطبيقك بشكل نشط.
Android 7.0
لا يرسل الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث عمليات البث التالية على مستوى النظام:
بالإضافة إلى ذلك، يجب أن تسجّل التطبيقات التي تستهدف الإصدار 7.0 من نظام التشغيل Android والإصدارات الأحدث عملية البث CONNECTIVITY_ACTION باستخدام registerReceiver(BroadcastReceiver, IntentFilter). لا يمكن تعريف أداة استقبال في ملف البيان.
تلقّي عمليات البث
يمكن للتطبيقات تلقّي عمليات البث بطريقتَين: من خلال أجهزة الاستقبال المسجَّلة في السياق وأجهزة الاستقبال المحدَّدة في ملف البيان.
المستقبِلات المسجَّلة في السياق
تتلقّى أجهزة الاستقبال المسجّلة في السياق عمليات البث طالما أنّ سياق التسجيل صالح. ويكون ذلك عادةً بين طلبَي registerReceiver وunregisterReceiver. يصبح سياق التسجيل غير صالح أيضًا عندما يدمر النظام السياق المقابل. على سبيل المثال، إذا سجّلت الدخول ضمن سياق Activity، ستتلقّى عمليات بث ما دام النشاط نشطًا. إذا سجّلت باستخدام سياق التطبيق، ستتلقّى عمليات البث ما دام التطبيق قيد التشغيل.
لتسجيل مستلِم مع سياق، اتّبِع الخطوات التالية:
في ملف الإصدار على مستوى الوحدة في تطبيقك، أدرِج الإصدار 1.9.0 أو إصدارًا أحدث من مكتبة AndroidX الأساسية:
Groovy
dependencies { def core_version = "1.19.0" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.1.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0" }
Kotlin
dependencies { val core_version = "1.19.0" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.1.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0") }
أنشئ مثيلاً من
BroadcastReceiver:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();أنشئ مثيلاً من
IntentFilter:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");اختَر ما إذا كان يجب تصدير أداة استقبال البث وجعلها مرئية للتطبيقات الأخرى على الجهاز. إذا كان هذا المستقبل يستمع إلى عمليات بث مرسَلة من النظام أو من تطبيقات أخرى، حتى التطبيقات الأخرى التي تملكها، استخدِم العلامة
RECEIVER_EXPORTED. إذا كان هذا المستقبل يستمع فقط إلى عمليات البث التي يرسلها تطبيقك، استخدِم العلامةRECEIVER_NOT_EXPORTED.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }Java
boolean listenToBroadcastsFromOtherApps = false; int receiverFlags = listenToBroadcastsFromOtherApps ? ContextCompat.RECEIVER_EXPORTED : ContextCompat.RECEIVER_NOT_EXPORTED;سجِّل جهاز الاستقبال من خلال الاتصال بالرقم
registerReceiver():Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);لإيقاف تلقّي الرسائل الإذاعية، اتّصِل بالرقم
unregisterReceiver(android.content.BroadcastReceiver). تأكد من إلغاء تسجيل جهاز الاستقبال عندما لا تعود بحاجة إليه أو عندما يصبح السياق غير صالح.
إلغاء تسجيل مستقبِل البث
أثناء تسجيل أداة استقبال البث، تحتفظ الأداة بمرجع إلى Context الذي تم التسجيل من خلاله. قد يؤدي ذلك إلى حدوث تسرّبات إذا كان النطاق المسجّل للمستلِم يتجاوز نطاق عمر دورة Context. على سبيل المثال، يمكن أن يحدث ذلك عند تسجيل جهاز استقبال في نطاق نشاط، ولكنك تنسى إلغاء تسجيله عندما يدمر النظام النشاط. لذلك، عليك دائمًا إلغاء تسجيل مستقبِل البث.
Kotlin
class MyActivity : ComponentActivity() {
private val myBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
setContent { MyApp() }
}
override fun onDestroy() {
super.onDestroy()
// When you forget to unregister your receiver here, you're causing a leak!
this.unregisterReceiver(myBroadcastReceiver)
}
}
Java
class MyActivity extends ComponentActivity {
MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
// Set content
}
}
تسجيل أدوات الاستقبال في أصغر نطاق
يجب ألا يتم تسجيل أداة استقبال البث إلا عندما تكون مهتمًا بالنتيجة. اختَر أصغر نطاق ممكن للمستلِم:
LifecycleResumeEffectأو طرق دورة حياة النشاطonResume/onPause: لا يتلقّى مستقبِل البث تحديثات إلا عندما يكون التطبيق في حالة الاستئناف.LifecycleStartEffectأو طرق دورة حياة النشاطonStart/onStop: لا يتلقّى مستقبِل البث تحديثات إلا عندما يكون التطبيق في حالة الاستئناف.-
DisposableEffect: لا يتلقّى مستقبِل البث التحديثات إلا عندما تكون الدالة المركّبة في شجرة التكوين. لم يتم ربط هذا النطاق بنطاق مراحل النشاط. ننصحك بتسجيل المستلِم في سياق التطبيق. والسبب في ذلك هو أنّ الدالة المركّبة يمكن نظريًا أن تستمر بعد انتهاء نطاق مراحل النشاط وأن يؤدي إلى تسرُّب النشاط. - النشاط
onCreate/onDestroy: يتلقّى برنامج استقبال البث تحديثات أثناء وجود النشاط في حالة الإنشاء. احرص على إلغاء التسجيل فيonDestroy()وليس فيonSaveInstanceState(Bundle)لأنّه قد لا يتم استدعاء هذا الإجراء. - نطاق مخصّص: على سبيل المثال، يمكنك تسجيل أداة استقبال في
ViewModelالنطاق، ما يتيح لها البقاء بعد إعادة إنشاء النشاط. احرص على استخدام سياق التطبيق لتسجيل أداة الاستقبال، لأنّ أداة الاستقبال يمكن أن تستمر بعد انتهاء نطاق مراحل نشاط التطبيق، ما يؤدي إلى تسرُّب النشاط.
إنشاء دوال برمجية قابلة للإنشاء مع حفظ الحالة وبدون حفظ الحالة
يحتوي Compose على دوال برمجية قابلة للإنشاء مع الاحتفاظ بالحالة ودوال برمجية قابلة للإنشاء بدون الاحتفاظ بالحالة. يؤدي تسجيل أو إلغاء تسجيل مستقبِل البث داخل دالة مركّبة إلى جعلها تتضمّن حالة. الدالة المركّبة ليست دالة خوارزمية حتمية تعرض المحتوى نفسه عند ضبط المَعلمات نفسها. يمكن أن تتغيّر الحالة الداخلية استنادًا إلى طلبات تم إرسالها إلى أداة استقبال البث المسجّلة.
كإحدى أفضل الممارسات في Compose، ننصحك بتقسيم العناصر القابلة للإنشاء إلى إصدارات تتضمّن حالة وأخرى لا تتضمّن حالة. لذلك، ننصحك بنقل عملية إنشاء أداة استقبال البث خارج Composable لجعلها بلا حالة:
@Composable
fun MyStatefulScreen() {
val myBroadcastReceiver = remember { MyBroadcastReceiver() }
val context = LocalContext.current
LifecycleStartEffect(true) {
// ...
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
}
MyStatelessScreen()
}
@Composable
fun MyStatelessScreen() {
// Implement your screen
}
مستقبِلات محدَّدة في البيان
إذا أعلنت عن أداة استقبال البث في ملف البيان، سيطلق النظام تطبيقك عند إرسال البث. إذا لم يكن التطبيق قيد التشغيل، سيطلقه النظام.
لتعريف أداة استقبال البث في ملف البيان، اتّبِع الخطوات التالية:
حدِّد العنصر
<receiver>في ملف البيان الخاص بتطبيقك.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.example.snippets.ACTION_UPDATE_DATA" /> </intent-filter> </receiver>تحدّد فلاتر الأهداف إجراءات البث التي يشترك فيها المستقبِل.
أنشئ فئة فرعية
BroadcastReceiverونفِّذonReceive(Context, Intent). يسجّل جهاز استقبال البث في المثال التالي محتوى البث ويعرضه:Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var dataRepository: DataRepository override fun onReceive(context: Context, intent: Intent) { if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") { val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data" // Do something with the data, for example send it to a data repository: dataRepository.updateData(data) } } }Java
public static class MyBroadcastReceiver extends BroadcastReceiver { @Inject DataRepository dataRepository; @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) { String data = intent.getStringExtra("com.example.snippets.DATA"); // Do something with the data, for example send it to a data repository: if (data != null) { dataRepository.updateData(data); } } } }
يسجّل مدير حِزم النظام أداة الاستقبال عند تثبيت التطبيق. يصبح المستلِم بعد ذلك نقطة دخول منفصلة إلى تطبيقك، ما يعني أنّه يمكن للنظام بدء تشغيل التطبيق وتسليم البث إذا لم يكن التطبيق قيد التشغيل.
ينشئ النظام عنصر BroadcastReceiver جديدًا للتعامل مع كل عملية بث يتلقّاها. يكون هذا العنصر صالحًا فقط خلال مدة استدعاء الدالة onReceive(Context, Intent). بعد أن تعرض الشفرة النتيجة من هذه الطريقة، يعتبر النظام أنّ المكوّن لم يعُد نشطًا.
التأثيرات في حالة العملية
يؤثر ما إذا كان BroadcastReceiver يعمل أم لا في العملية المضمّنة، ما قد يغيّر من احتمالية إيقاف النظام. تنفِّذ عملية تعمل في المقدّمة طريقة onReceive() الخاصة بجهاز استقبال. ينفّذ النظام العملية
إلا في حال تعرّضه لضغط شديد في الذاكرة.
يوقف النظام ميزة BroadcastReceiver بعد onReceive().
تعتمد أهمية عملية المضيف الخاصة بالمستلِم على مكوّنات التطبيق. إذا كانت هذه العملية تستضيف
مستقبِلًا تم تعريفه في ملف البيان فقط، قد يوقفها النظام بعد onReceive()
لإتاحة الموارد لعمليات أخرى أكثر أهمية. ويحدث ذلك عادةً مع التطبيقات التي لم يتفاعل معها المستخدم مطلقًا أو لم يتفاعل معها مؤخرًا.
وبالتالي، يجب ألا تبدأ أدوات معالجة البث سلاسل طويلة الأمد في الخلفية.
يمكن للنظام إيقاف العملية في أي لحظة بعد onReceive() لاستعادة الذاكرة، ما يؤدي إلى إنهاء سلسلة المحادثات التي تم إنشاؤها. لإبقاء العملية نشطة، عليك جدولة
JobService من جهاز الاستقبال باستخدام JobScheduler لكي يعرف
النظام أنّ العملية لا تزال تعمل. تقدّم مقالة نظرة عامة على العمل في الخلفية مزيدًا من التفاصيل.
إرسال رسائل بث
يوفّر نظام التشغيل Android طريقتَين للتطبيقات لإرسال عمليات البث:
- تُرسِل طريقة
sendOrderedBroadcast(Intent, String)عمليات البث إلى جهاز استقبال واحد في كل مرة. وبما أنّ كل مستلِم ينفّذ العملية بالتسلسل، يمكنه نقل النتيجة إلى المستلِم التالي. يمكنه أيضًا إيقاف البث نهائيًا كي لا يصل إلى أجهزة استقبال أخرى. يمكنك التحكّم في ترتيب تشغيل أدوات الاستقبال ضمن عملية التطبيق نفسها. لإجراء ذلك، استخدِم السمةandroid:priorityالخاصة بفلتر الأهداف المطابق. يتم تنفيذ عمليات الاستقبال التي لها الأولوية نفسها بترتيب عشوائي. - ترسل طريقة
sendBroadcast(Intent)عمليات البث إلى جميع أجهزة الاستقبال بترتيب غير محدّد. يُطلق على هذا النوع اسم "بث عادي". هذه الطريقة أكثر فعالية، ولكنّها تعني أنّ أجهزة الاستقبال لا يمكنها قراءة النتائج من أجهزة استقبال أخرى أو نشر البيانات المستلَمة من البث أو إيقاف البث.
يوضّح مقتطف الرمز التالي كيفية إرسال بث من خلال إنشاء Intent واستدعاء sendBroadcast(Intent).
Kotlin
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", newData)
setPackage("com.example.snippets")
}
context.sendBroadcast(intent)
Java
Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);
يتم تضمين الإعلان على جميع الأجهزة في عنصر Intent. يجب أن يوفّر السلسلة action الخاصة بالغرض بنية اسم حزمة Java للتطبيق وأن يحدّد حدث البث بشكل فريد. يمكنك إرفاق معلومات إضافية بالنية باستخدام putExtra(String, Bundle). يمكنك أيضًا حصر البث على مجموعة من التطبيقات في المؤسسة نفسها من خلال استدعاء setPackage(String) في الغرض.
تقييد عمليات البث باستخدام الأذونات
تتيح لك الأذونات حصر عمليات البث على مجموعة التطبيقات التي لديها أذونات معيّنة. يمكنك فرض قيود على المُرسِل أو المتلقّي للبث.
إرسال رسائل بث مع أذونات
عند الاتصال بالرقم sendBroadcast(Intent, String) أو
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
، يمكنك تحديد مَعلمة إذن. ولا يمكن أن يتلقّى البث سوى أجهزة الاستقبال التي طلبت هذا الإذن باستخدام العلامة <uses-permission> في ملف البيان. إذا كان الإذن خطيرًا، يجب منحه قبل أن يتمكّن جهاز الاستقبال من تلقّي البث. على سبيل المثال، يرسل الرمز البرمجي التالي بثًا مع إذن:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
لتلقّي البث، يجب أن يطلب التطبيق المتلقّي الإذن على النحو التالي:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
يمكنك تحديد إذن نظام حالي، مثل
BLUETOOTH_CONNECT، أو تحديد إذن مخصّص باستخدام العنصر
<permission>. للحصول على معلومات حول الأذونات والأمان بشكل عام، يُرجى الاطّلاع على أذونات النظام.
تلقّي عمليات البث مع الأذونات
إذا حدّدت مَعلمة إذن عند تسجيل أداة استقبال البث (إما باستخدام registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) أو في العلامة <receiver> في ملف البيان)، لن يتمكّن من إرسال Intent إلى أداة الاستقبال إلا أدوات البث التي طلبت الإذن باستخدام العلامة <uses-permission> في ملف البيان. إذا كان الإذن خطيرًا،
يجب أيضًا منح الباث الإذن.
على سبيل المثال، لنفترض أنّ تطبيق الاستقبال يتضمّن أداة استقبال تم تعريفها في البيان على النحو التالي:
<!-- If this receiver listens for broadcasts sent from the system or from
other apps, even other apps that you own, set android:exported to "true". -->
<receiver
android:name=".MyBroadcastReceiverWithPermission"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
</intent-filter>
</receiver>
أو يحتوي تطبيق الاستلام على مستقبِل مسجَّل في السياق على النحو التالي:
Kotlin
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
)
Java
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
);
بعد ذلك، لكي يتمكّن تطبيق الإرسال من إرسال عمليات بث إلى أجهزة الاستقبال هذه، يجب أن يطلب الإذن على النحو التالي:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
تجنُّب عمليات البث ضمن العملية نفسها
تم تصميم عمليات البث كآلية للتواصل بين العمليات (IPC) بهدف إرسال الرسائل بين التطبيقات المختلفة أو بين النظام والتطبيقات. يُعد إرسال بث من عملية إلى جهاز استقبال يعمل ضمن العملية نفسها أمرًا غير فعّال للغاية، ويؤدي إلى زيادة غير ضرورية في تكاليف النظام، لذا ننصح بشدة بعدم إجراء ذلك.
في ما يلي سيناريوهان شائعان ترسل فيهما التطبيقات عمليات بث إلى نفسها:
التواصل بين المكوّنات في العملية نفسها: على سبيل المثال، تمرير الأحداث أو البيانات بين الأنشطة أو الأجزاء أو الخدمات أو سلاسل الخلفية بدلاً من إرسال عمليات بث، استخدِم آليات التواصل العادية أثناء المعالجة، مثل نمط المراقب أو عمليات البث التفاعلية:
- مسارات Kotlin (
SharedFlowوStateFlow): حلّ حديث ومناسب في Kotlin لإصدار ومراقبة عمليات بث الأحداث أو تحديثات الحالة في جميع الكوروتينات والمكوّنات في تطبيقك. - Shared
ViewModel: تسهّل مشاركة البيانات والأحداث بين مكوّنات مختلفة في واجهة المستخدم (مثل الأجزاء أو العناصر القابلة للإنشاء) ضمن النشاط نفسه. - عمليات رد الاتصال ومعالجات الأحداث: عمليات رد الاتصال أو مراجع الدوال الخاصة بالواجهة العادية التي يتم تمريرها مباشرةً بين المكوّنات أو تسجيلها في مستودع أو وحدة تحكّم مركزية
- مسارات Kotlin (
التعامل مع أحداث النظام أو المهام أو المنبّهات: على سبيل المثال، تلقّي مهمة مجدوَلة أو منبّه أو ردّ اتصال من النظام، ثم إرسال بث لتنفيذ العمل الفعلي بدلاً من إرسال بث، أكمل العمل مباشرةً ضمن تلك المهمة (مثل
JobServiceأو عامل WorkManager) أو معالج التنبيه أو مكوّن معاودة الاتصال بالنظام، أو فوِّض العمل مباشرةً إلى فئات منطق النشاط التجاري في تطبيقك.
إذا رصد النظام بثًا ذاتيًا، قد يحاول تحسين العرض من خلال إعادة توجيهه أثناء العملية. ومع ذلك، يظل هذا الخيار أقل كفاءة من بدائل التواصل أثناء المعالجة الموضّحة سابقًا، ويجب استخدام تلك البدائل بدلاً منه.
لمزيد من المعلومات حول تصميم التواصل بين مكوّنات التطبيق، يُرجى الاطّلاع على دليل تصميم بنية التطبيق.
الاعتبارات الأمنية
في ما يلي بعض اعتبارات الأمان عند إرسال واستلام عمليات البث:
إذا سجّلت العديد من التطبيقات لتلقّي البث نفسه في ملف البيان، قد يؤدي ذلك إلى أن يطلق النظام الكثير من التطبيقات، ما يؤثر بشكل كبير في أداء الجهاز وتجربة المستخدم. ولتجنُّب ذلك، ننصحك باستخدام تسجيل السياق بدلاً من بيان ملف البيان. في بعض الأحيان، يفرض نظام Android نفسه استخدام مستقبِلات مسجّلة في السياق. على سبيل المثال، لا يتم تسليم البث
CONNECTIVITY_ACTIONإلا إلى أجهزة الاستقبال المسجّلة في السياق.لا تبث معلومات حساسة باستخدام نية ضمنية. يمكن لأي تطبيق قراءة المعلومات إذا سجّل لتلقّي البث. هناك ثلاث طرق للتحكّم في مَن يمكنه تلقّي رسائل البث:
- يمكنك تحديد إذن عند إرسال رسالة بث.
- في الإصدار 4.0 من نظام التشغيل Android (المستوى 14 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك تحديد حزمة باستخدام
setPackage(String)عند إرسال بث. يقيّد النظام البث على مجموعة التطبيقات التي تتطابق مع الحزمة.
عند تسجيل أداة استقبال، يمكن لأي تطبيق إرسال عمليات بث يُحتمل أن تكون ضارة إلى أداة استقبال تطبيقك. هناك عدة طرق للحدّ من عمليات البث التي يتلقّاها تطبيقك:
- يمكنك تحديد إذن عند تسجيل أداة استقبال البث.
- بالنسبة إلى أدوات الاستقبال المحدّدة في البيان، يمكنك ضبط السمة android:exported على "false" في البيان. لا يتلقّى المستلِم عمليات البث من مصادر خارج التطبيق.
مساحة الاسم الخاصة بإجراءات البث عامة. تأكَّد من كتابة أسماء الإجراءات والسلاسل الأخرى في مساحة اسم تملكها. وإلا، قد يحدث تعارض غير مقصود مع تطبيقات أخرى.
بما أنّ طريقة
onReceive(Context, Intent)الخاصة بالمستلِم يتم تنفيذها في سلسلة التعليمات الرئيسية، يجب أن يتم تنفيذها وإرجاعها بسرعة. إذا كنت بحاجة إلى تنفيذ عمل يستغرق وقتًا طويلاً، عليك توخّي الحذر بشأن إنشاء سلاسل أو بدء خدمات تعمل في الخلفية لأنّ النظام يمكنه إيقاف العملية بأكملها بعد أن تعرض الدالةonReceive()القيمة. لمزيد من المعلومات، راجِع التأثير على حالة العملية. لتنفيذ مهام تستغرق وقتًا طويلاً، ننصحك بما يلي:- استدعاء
goAsync()في طريقةonReceive()الخاصة بالمستلِم وتمريرBroadcastReceiver.PendingResultإلى سلسلة خلفية يؤدي ذلك إلى إبقاء البث نشطًا بعد الرجوع منonReceive(). ومع ذلك، حتى مع هذا النهج، يتوقّع النظام أن تنتهي من البث بسرعة كبيرة (في أقل من 10 ثوانٍ). ويتيح لك نقل العمل إلى سلسلة تعليمات أخرى لتجنُّب حدوث خلل في سلسلة التعليمات الرئيسية. - جدولة مهمة باستخدام
JobSchedulerلمزيد من المعلومات، اطّلِع على الجدولة الذكية للوظائف.
- استدعاء
لا تبدأ الأنشطة من أدوات استقبال البث لأنّ تجربة المستخدم ستكون غير سلسة، خاصةً إذا كان هناك أكثر من أداة استقبال واحدة. ننصحك بدلاً من ذلك بعرض إشعار.