ترسل تطبيقات 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
بدءًا من الإصدار 9 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 28)، لا يتلقّى البث NETWORK_STATE_CHANGED_ACTION معلومات حول الموقع الجغرافي للمستخدم أو البيانات التي تكشف الهوية الشخصية.
إذا تم تثبيت تطبيقك على جهاز يعمل بالإصدار 9.0 من نظام التشغيل Android (المستوى 28 من واجهة برمجة التطبيقات) أو إصدار أحدث، لن يتضمّن النظام معرّفات SSID أو BSSID أو معلومات الاتصال أو نتائج البحث في عمليات بث شبكة Wi-Fi. للحصول على هذه المعلومات، يُرجى الاتصال بالرقم
getConnectionInfo() بدلاً من ذلك.
Android 8.0
بدءًا من نظام التشغيل Android 8.0 (مستوى واجهة برمجة التطبيقات 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.1" // 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.1" // 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. على سبيل المثال، يمكن أن يحدث ذلك عند تسجيل أداة استقبال في نطاق Activity، ولكنك تنسى إلغاء تسجيلها عندما يتلف النظام Activity. لذلك، عليك دائمًا إلغاء تسجيل مستقبِل البث.
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 لإصدار ومراقبة عمليات بث الأحداث أو تعديلات الحالة في جميع أنحاء الروتينات الفرعية والمكوّنات في تطبيقك. - المشاركة
ViewModel: تسهّل مشاركة البيانات والأحداث بين مكوّنات مختلفة في واجهة المستخدم (مثل الأجزاء أو العناصر القابلة للإنشاء) ضمن النشاط نفسه. - عمليات رد الاتصال ومعالجات الأحداث: عمليات رد الاتصال أو مراجع الدوال الخاصة بالواجهة العادية التي يتم تمريرها مباشرةً بين المكوّنات أو تسجيلها في مستودع أو وحدة تحكّم مركزية
- مسارات Kotlin (
التعامل مع أحداث النظام أو المهام أو المنبّهات: على سبيل المثال، تلقّي مهمة مجدوَلة أو منبّه أو ردّ اتصال من النظام، ثم إرسال بث لتنفيذ العمل الفعلي بدلاً من إرسال بث، أكمل العمل مباشرةً ضمن تلك المهمة (مثل
JobServiceأو منفِّذ WorkManager) أو معالج التنبيه أو مكوّن معاودة الاتصال بالنظام، أو فوِّض العمل مباشرةً إلى فئات منطق النشاط التجاري في تطبيقك.
على الأجهزة التي تعمل بالإصدار Android 17 QPR2 أو إصدار أحدث، يقدّم النظام عمليات البث الذاتي بكفاءة أكبر من خلال إعادة عمليات البث إلى عملية الإرسال، ما يؤدي إلى إرسالها إلى أجهزة الاستقبال الخاصة بها على سلسلة التعليمات الرئيسية. لا يؤدي إرسال بث ذاتي إلى زيادة أهمية العملية، ولا يمنع تجميد عملية مخزّنة مؤقتًا، لذا لا تعتمد على عمليات البث الذاتي لإبقاء تطبيقك قيد التشغيل أو لتنفيذ مهام في الخلفية. وحتى مع هذا التحسين، تكون عمليات البث الذاتي أقل كفاءة من آليات التواصل أثناء المعالجة، لذا استخدِم البدائل بدلاً من ذلك.
لمزيد من المعلومات حول تصميم التواصل بين مكوّنات التطبيق، يُرجى الاطّلاع على دليل تصميم بنية التطبيق.
الاعتبارات الأمنية
في ما يلي بعض اعتبارات الأمان المتعلقة بإرسال الرسائل الجماعية وتلقّيها:
إذا سجّلت العديد من التطبيقات لتلقّي البث نفسه في ملف البيان، قد يؤدي ذلك إلى أن يطلق النظام الكثير من التطبيقات، ما يؤثر بشكل كبير في أداء الجهاز وتجربة المستخدم. لتجنُّب ذلك، ننصحك باستخدام تسجيل السياق بدلاً من بيان البيان. في بعض الأحيان، يفرض نظام Android نفسه استخدام مستقبِلات مسجّلة في السياق. على سبيل المثال، يتم تسليم البث
CONNECTIVITY_ACTIONإلى أجهزة الاستقبال المسجّلة في السياق فقط.لا تبث معلومات حساسة باستخدام نية ضمنية. يمكن لأي تطبيق قراءة المعلومات إذا سجّل لتلقّي البث. هناك ثلاث طرق للتحكّم في مَن يمكنه تلقّي رسائل البث:
- يمكنك تحديد إذن عند إرسال رسالة بث.
- في الإصدار 4.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 14) والإصدارات الأحدث، يمكنك تحديد حزمة باستخدام
setPackage(String)عند إرسال بث. يقتصر البث على مجموعة التطبيقات التي تتطابق مع الحزمة.
عند تسجيل أداة استقبال، يمكن لأي تطبيق إرسال عمليات بث يُحتمل أن تكون ضارة إلى أداة استقبال تطبيقك. هناك عدة طرق للحدّ من عمليات البث التي يتلقّاها تطبيقك:
- يمكنك تحديد إذن عند تسجيل أداة استقبال البث.
- بالنسبة إلى أدوات الاستقبال المحدّدة في البيان، يمكنك ضبط السمة android:exported على "false" في البيان. لا يتلقّى جهاز الاستقبال عمليات البث من مصادر خارج التطبيق.
مساحة الاسم الخاصة بإجراءات البث عامة. تأكَّد من كتابة أسماء الإجراءات والسلاسل الأخرى في مساحة اسم تملكها. وإلا، قد يحدث تعارض غير مقصود مع تطبيقات أخرى.
بما أنّ طريقة
onReceive(Context, Intent)الخاصة بالمستلِم يتم تنفيذها على سلسلة التعليمات الرئيسية، يجب أن يتم تنفيذها وإرجاعها بسرعة. إذا كنت بحاجة إلى تنفيذ عمل يستغرق وقتًا طويلاً، عليك توخّي الحذر بشأن إنشاء سلاسل أو بدء خدمات تعمل في الخلفية لأنّ النظام يمكنه إيقاف العملية بأكملها بعد أن تعرض الدالةonReceive(). لمزيد من المعلومات، راجِع التأثير في حالة العملية. لتنفيذ مهام تستغرق وقتًا طويلاً، ننصحك بما يلي:- استدعاء
goAsync()في طريقةonReceive()الخاصة بالمستلِم وتمريرBroadcastReceiver.PendingResultإلى سلسلة خلفية يؤدي ذلك إلى إبقاء البث نشطًا بعد الرجوع منonReceive(). ومع ذلك، حتى مع اتّباع هذا النهج، يتوقّع النظام أن تنتهي عملية البث بسرعة كبيرة (في أقل من 10 ثوانٍ). ولكنّه يتيح لك نقل العمل إلى سلسلة تعليمات أخرى لتجنُّب حدوث خلل في سلسلة التعليمات الرئيسية. - جدولة مهمة باستخدام
JobSchedulerلمزيد من المعلومات، يُرجى الاطّلاع على الجدولة الذكية للمهام.
- استدعاء
لا تبدأ الأنشطة من أدوات استقبال البث لأنّ تجربة المستخدم ستكون سيئة، خاصةً إذا كان هناك أكثر من أداة استقبال واحدة. ننصحك بدلاً من ذلك بعرض إشعار.