الأربعاء، 18 أكتوبر 2017

البث Broadcasts

البث Broadcasts






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

يمكن للتطبيقات التسجيل لتلقي البث المحدد. عند إرسال بث، يقوم النظام تلقائيا بتوجيه البث إلى التطبيقات التي اشتركت في تلقي هذا النوع من البث.

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


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

الرسالة الإذاعية نفسها ملفوفة في كائن Intent تحدد سلسلة الإجراءات الحدث الذي حدث (على سبيل المثال android.intent.action.AIRPLANE_MODE ). وقد تتضمن النية أيضا معلومات إضافية مجمعة في حقلها الإضافي. على سبيل المثال، يتضمن نية وضع الطائرة إضافة منطقية تشير إلى ما إذا كان وضع الطائرة قيد التشغيل أم لا.

للحصول على مزيد من المعلومات حول كيفية قراءة النوايا والحصول على سلسلة الإجراء من نية، راجع النوايا و النوايا الفلاتر .

للحصول على قائمة كاملة بإجراءات بث النظام، راجع الملف BROADCAST_ACTIONS.TXT في أندرويد سك. كل عمل بث له حقل ثابت مرتبط به. على سبيل المثال، قيمة ACTION_AIRPLANE_MODE_CHANGED ثابتة هي android.intent.action.AIRPLANE_MODE . وتوجد وثائق لكل إجراء إذاعي في المجال الثابت المرتبط به.

التغييرات في عمليات البث على النظام
الروبوت 7.0 وأعلى لم يعد يرسل البث النظام التالية. يؤثر هذا التحسين على جميع التطبيقات، وليس فقط تلك التي تستهدف أندرويد 7.0.

ACTION_NEW_PICTURE
ACTION_NEW_VIDEO
يجب على التطبيقات التي تستهدف أندرويد 7.0 (مستوى واجهة برمجة التطبيقات 24) والأعلى تسجيل عمليات البث التالية باستخدام registerReceiver(BroadcastReceiver, IntentFilter) . لا يعمل إعلان مستقبل في البيان.

CONNECTIVITY_ACTION
بدءا من أندرويد 8.0 (مستوى أبي 26)، يفرض النظام قيودا إضافية على أجهزة الاستقبال المعلنة. إذا كان تطبيقك يستهدف مستوى واجهة برمجة التطبيقات (26) أو أعلى، فلا يمكنك استخدام البيان لإعلان جهاز استقبال لمعظم عمليات البث الضمنية (عمليات البث التي لا تستهدف تطبيقك على وجه التحديد).

تلقي البث
يمكن للتطبيقات تلقي البث بطريقتين: من خلال أجهزة الاستقبال المعلنة والمذكرات المسجلة في السياق.

المستقبلات المعلنة
إذا كنت تعلن عن مستقبل البث في البيان الخاص بك، سيقوم النظام بتشغيل التطبيق الخاص بك (إذا كان التطبيق لا يعمل بالفعل) عندما يتم إرسال البث.

ملاحظة: إذا كان تطبيقك يستهدف مستوى واجهة برمجة التطبيقات (26) أو أعلى، فلا يمكنك استخدام البيان لإعلان جهاز استقبال عن عمليات البث الضمنية (عمليات البث التي لا تستهدف تطبيقك على وجه التحديد)، باستثناء بعض عمليات البث الضمنية المعفاة من هذا التقييد . في معظم الحالات، يمكنك استخدام المهام المجدولة بدلا من ذلك.
لإعلان مستقبل البث في البيان، قم بتنفيذ الخطوات التالية:

حدد عنصر <receiver> في بيان تطبيقك.
<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    </intent-filter>
</receiver>

تحدد فلاتر النوايا إجراءات البث التي يشترك فيها المستقبل.
onReceive(Context, Intent) BroadcastReceiver وتنفيذ onReceive(Context, Intent) . يسجل مستقبل البث في المثال التالي ويعرض محتويات البث:

public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        StringBuilder sb = new StringBuilder();
        sb.append("Action: " + intent.getAction() + "\n");
        sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
        String log = sb.toString();
        Log.d(TAG, log);
        Toast.makeText(context, log, Toast.LENGTH_LONG).show();
    }
}

يسجل مدير حزمة النظام جهاز الاستقبال عند تثبيت التطبيق. ثم يصبح المتلقي نقطة دخول منفصلة في التطبيق الخاص بك مما يعني أن النظام يمكن أن تبدأ التطبيق وتسليم البث إذا كان التطبيق لا يعمل حاليا.

يقوم النظام بإنشاء كائن مكون BroadcastReceiver جديد للتعامل مع كل بث يتلقى. هذا الكائن صالح فقط لمدة المكالمة إلى onReceive(Context, Intent) . بمجرد إرجاع التعليمات البرمجية من هذه الطريقة، يعتبر النظام المكون لم يعد نشطا.

أجهزة استقبال مسجلة في السياق
لتسجيل جهاز استقبال مع سياق، قم بتنفيذ الخطوات التالية:

إنشاء مثيل من BroadcastReceiver .


BroadcastReceiver br = new MyBroadcastReceiver();

إنشاء IntentFilter وتسجيل المتلقي عن طريق استدعاء registerReceiver(BroadcastReceiver, IntentFilter) :


IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);

ملاحظة: للتسجيل للبث المحلي، استدعاء LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter) بدلا من ذلك.
وتتلقى أجهزة الاستقبال المسجلة في السياق برامج البث طالما أن سياق تسجيلها صحيح. على سبيل المثال، إذا قمت بالتسجيل ضمن سياق Activity ، تتلقى البث طالما لم يتم تدمير النشاط. إذا قمت بالتسجيل مع سياق التطبيق، تتلقى البث طالما التطبيق قيد التشغيل.
لإيقاف تلقي البث، اتصل unregisterReceiver(android.content.BroadcastReceiver) . تأكد من إلغاء تسجيل جهاز الاستقبال عندما لم تعد بحاجة إليه أو لم يعد السياق صالحا.
onCreate(Bundle) في onCreate(Bundle) المكان الذي تقوم فيه بالتسجيل وعدم تسجيل جهاز الاستقبال، على سبيل المثال، إذا قمت بتسجيل جهاز استقبال في onCreate(Bundle) باستخدام سياق النشاط، يجب عليك إلغاء onDestroy() في onDestroy() لمنع تسرب جهاز الاستقبال من سياق النشاط. إذا قمت بتسجيل جهاز استقبال في onResume() ، يجب عليك إلغاء onPause() في onPause() لمنع تسجيله عدة مرات (إذا كنت لا ترغب في تلقي البث عند إيقاف مؤقت، وهذا يمكن خفض على النفقات العامة للنظام غير الضرورية). لا تقم onSaveInstanceState(Bundle) في onSaveInstanceState(Bundle) ، لأن هذا لا يسمى إذا كان المستخدم يتحرك مرة أخرى في كومة التاريخ.
تأثيرات على حالة العملية
حالة جهاز BroadcastReceiver (سواء كان يعمل أم لا) يؤثر على حالة العملية التي تحتوي عليها، والتي يمكن أن تؤثر بدورها على احتمال قتله من قبل النظام. على سبيل المثال، عندما تقوم عملية بتنفيذ جهاز استقبال (أي، حاليا تشغيل التعليمات البرمجية في طريقة onReceive() )، يعتبر عملية مقدمة. النظام يحافظ على تشغيل العملية إلا في حالات الضغط الذاكرة القصوى.

ومع ذلك، وبمجرد إرجاع التعليمات البرمجية من onReceive() ، و بروادكاستريسيفر لم يعد نشطا. تصبح عملية المضيف المتلقي فقط أهمية مثل مكونات التطبيق الأخرى التي تعمل فيها. إذا كانت هذه العملية تستضيف جهاز استقبال أعلن بوضوح فقط (وهو حالة شائعة للتطبيقات التي لم يتفاعل معها المستخدم أبدا أو لم يتفاعل معها مؤخرا)، onReceive() عودته من onReceive() ، يعتبر النظام أن العملية التي يقوم بها عملية ذات أولوية منخفضة وقد وقتلها لجعل الموارد المتاحة لعمليات أخرى أكثر أهمية.

لهذا السبب، يجب عدم بدء تشغيل المواضيع الخلفية طويلة من جهاز استقبال البث. بعد onReceive() ، يمكن للنظام أن يقتل العملية في أي وقت لاستعادة الذاكرة، وعند القيام بذلك، فإنه ينهي مؤشر الترابط ولدت في العملية. لتجنب ذلك، يجب عليك إما الاتصال goAsync() (إذا كنت تريد وقتا أطول قليلا لمعالجة البث في سلسلة ترابط الخلفية) أو جدولة JobService من المتلقي باستخدام JobScheduler ، لذلك يعرف النظام أن العملية لا تزال تؤدي نشطة عمل. لمزيد من المعلومات، راجع العمليات ودورة حياة التطبيق .

يعرض المقتطف التالي BroadcastReceiver يستخدم goAsync() للعلم أنه يحتاج إلى مزيد من الوقت لإنهاء بعد onReceive() كاملة. هذا مفيد بشكل خاص إذا كان العمل الذي تريد إكماله في onReceive() طويل بما فيه الكفاية لتسبب مؤشر ترابط واجهة المستخدم لتفويت إطار (> 16ms)، مما يجعلها أكثر ملاءمة لخيط الترابط الخلفية.


ublic class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";

    @Override
    public void onReceive(final Context context, final Intent intent) {
        final PendingResult pendingResult = goAsync();
        AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
            @Override
            protected String doInBackground(String... params) {
                StringBuilder sb = new StringBuilder();
                sb.append("Action: " + intent.getAction() + "\n");
                sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
                Log.d(TAG, log);
                // Must call finish() so the BroadcastReceiver can be recycled.
                pendingResult.finish();
                return data;
            }
        };
        asyncTask.execute();
    }
}

إرسال البث
يوفر أندرويد ثلاث طرق للتطبيقات لإرسال البث:

طريقة sendOrderedBroadcast(Intent, String) يرسل البث إلى جهاز استقبال واحد في وقت واحد. كما ينفذ كل مستقبل بدوره، فإنه يمكن نشر نتيجة إلى المستقبل المقبل، أو أنه يمكن إحباط تماما البث بحيث لن يتم تمريرها إلى مستقبلات أخرى. مستقبلات النظام تشغيل في يمكن السيطرة عليها مع الروبوت: سمة الأولوية من مطابقة نية تصفية. سيتم تشغيل أجهزة الاستقبال ذات الأولوية نفسها في ترتيب تعسفي.
وترسل طريقة sendBroadcast(Intent) البث إلى جميع المستقبلات بترتيب غير محدد. وهذا ما يسمى البث العادي. وهذا أكثر كفاءة، ولكنه يعني أن المستقبلات لا تستطيع قراءة النتائج من المستقبلات الأخرى، أو نشر البيانات الواردة من البث، أو إبطال البث.
طريقة LocalBroadcastManager.sendBroadcast يرسل البث إلى أجهزة الاستقبال التي هي في نفس التطبيق مثل المرسل. إذا لم تكن بحاجة إلى إرسال بث عبر التطبيقات، فاستخدم عمليات البث المحلية. تنفيذ هو أكثر كفاءة بكثير (أي الاتصالات إنتيربروسيس اللازمة) وكنت لا داعي للقلق حول أي قضايا أمنية تتعلق تطبيقات أخرى تكون قادرة على تلقي أو إرسال البث الخاص بك.
يوضح مقتطف الشفرة التالي كيفية إرسال بث عن طريق إنشاء نية والدعوة sendBroadcast(Intent) .

 Intent intent = new Intent(); intent.setAction("com.example.broadcast.MY_NOTIFICATION"); intent.putExtra("data","Notice me senpai!"); sendBroadcast(intent); 

يتم لف رسالة البث في كائن Intent . يجب أن توفر سلسلة إجراءات النية بنية اسم حزمة جافا في التطبيق وتعرف حدث البث بشكل فريد. يمكنك إرفاق معلومات إضافية إلى نية مع putExtra(String, Bundle) . يمكنك أيضا الحد من البث إلى مجموعة من التطبيقات في نفس المؤسسة عن طريق استدعاء setPackage(String) على القصد.

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

إرسال الأذونات
عند استدعاء sendBroadcast(Intent, String) أو sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) ، يمكنك تحديد معلمة إذن. فقط أجهزة الاستقبال الذين طلبوا الإذن مع في بيانهم (وبعد ذلك تم منح الإذن إذا كان خطرا) يمكن الحصول على البث. على سبيل المثال، ترسل التعليمات البرمجية التالية بث:

 sendBroadcast(new Intent("com.example.NOTIFY"), Manifest.permission.SEND_SMS); 
لتلقي البث، يجب أن يطلب التطبيق المستلم الإذن كما هو موضح أدناه:

 <uses-permission android:name="android.permission.SEND_SMS"/> 
يمكنك تحديد إما إذن نظام حالي مثل SEND_SMS أو تحديد إذن مخصص باستخدام العنصر <permission> SEND_SMS <permission> . للحصول على معلومات حول الأذونات والأمان بشكل عام، راجع أذونات النظام .

ملاحظة: يتم تسجيل الأذونات المخصصة عند تثبيت التطبيق. يجب تثبيت التطبيق الذي يحدد إذن مخصص قبل التطبيق الذي يستخدمه.
تلقي الأذونات
إذا قمت بتحديد معلمة إذن عند تسجيل جهاز استقبال البث (إما مع registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) أو في <receiver> علامة في البيان الخاص بك)، ثم المذيعين فقط الذين طلبوا الإذن مع <uses-permission> registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) <uses-permission> في بيانهم (وبعد ذلك تم منح الإذن إذا كان خطرا) يمكن إرسال نية إلى المتلقي.

على سبيل المثال، افترض أن تطبيق الاستلام يحتوي على مستقبل إعلان معلن كما هو موضح أدناه:





 <receiver android:name=".MyBroadcastReceiver" android:permission="android.permission.SEND_SMS"> <intent-filter> <action android:name="android.intent.action.AIRPLANE_MODE"/> </intent-filter> </receiver> 
أو يتلقى التطبيق الخاص بك استقبال مسجل السياق كما هو مبين أدناه:
 IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null ); 
ثم، لتكون قادرة على إرسال البث إلى تلك المستقبلات، يجب على التطبيق إرسال طلب الإذن كما هو مبين أدناه:
 <uses-permission android:name="android.permission.SEND_SMS"/> 

الاعتبارات الأمنية وأفضل الممارسات


في ما يلي بعض الاعتبارات الأمنية وأفضل الممارسات لإرسال البث واستلامه:

إذا كنت لا تحتاج إلى إرسال البث إلى مكونات خارج التطبيق الخاص بك، ثم إرسال واستقبال البث المحلية مع LocalBroadcastManager الذي يتوفر في مكتبة الدعم . و LocalBroadcastManager هو أكثر كفاءة (لا الاتصالات إنتيربروسيس اللازمة) ويسمح لك لتجنب التفكير في أي قضايا أمنية تتعلق تطبيقات أخرى تكون قادرة على تلقي أو إرسال البث الخاص بك. يمكن استخدام الإذاعات المحلية كحافلة للأحداث العامة / الباصات الفرعية في تطبيقك بدون أي نفقات عامة على البث على نطاق النظام.
إذا سجلت العديد من التطبيقات لتلقي نفس البث في بيانها، فإنه يمكن أن يسبب النظام لإطلاق الكثير من التطبيقات، مما تسبب في تأثير كبير على كل من أداء الجهاز وتجربة المستخدم. لتجنب ذلك، تفضل استخدام تسجيل السياق على بيان البيان. في بعض الأحيان، فإن نظام أندرويد نفسه يفرض استخدام أجهزة الاستقبال المسجلة في السياق. على سبيل المثال، يتم تسليم البث CONNECTIVITY_ACTION فقط إلى أجهزة الاستقبال المسجلة في السياق.
لا تبث معلومات حساسة باستخدام نية ضمنية. يمكن قراءة المعلومات من قبل أي التطبيق الذي يسجل لتلقي البث. هناك ثلاث طرق للتحكم في من يمكنه تلقي البث:
يمكنك تحديد إذن عند إرسال بث.
في الروبوت 4.0 وأعلى، يمكنك تحديد حزمة مع setPackage(String) عند إرسال البث. يقيد النظام البث إلى مجموعة التطبيقات التي تطابق الحزمة.
يمكنك إرسال البث المحلي مع LocalBroadcastManager .
عند تسجيل جهاز استقبال، يمكن لأي التطبيق إرسال البث الخبيثة المحتملة لمتلقي التطبيق الخاص بك. هناك ثلاث طرق للحد من عمليات البث التي يتلقاها تطبيقك:
يمكنك تحديد إذن عند تسجيل جهاز استقبال البث.
بالنسبة إلى المستقبلات المعلنة، يمكنك تعيين السمة التي تم تصديرها إلى أندرويد إلى "فالس" في البيان. لا يتلقى المتلقي البث من مصادر خارج التطبيق.
يمكنك تقييد نفسك للبث المحلي فقط مع LocalBroadcastManager .
مساحة الاسم لإجراءات البث عالمية. تأكد من كتابة أسماء الإجراءات والسلاسل الأخرى في مساحة اسم تملكها، وإلا قد تتعارض بشكل غير مقصود مع تطبيقات أخرى.
لأن طريقة onReceive(Context, Intent) المتلقي يعمل على الموضوع الرئيسي، فإنه يجب تنفيذ والعودة بسرعة. إذا كنت بحاجة إلى تنفيذ العمل على المدى الطويل، كن حذرا حول المواضيع onReceive() أو بدء خدمات الخلفية لأن النظام يمكن أن تقتل العملية برمتها بعد onReceive() إرجاع. لمزيد من المعلومات، راجع التأثير على حالة العملية لتنفيذ العمل الطويل، نوصي بما يلي:
استدعاء goAsync() في goAsync() الخاص بك) المتلقي وتمرير BroadcastReceiver.PendingResult إلى مؤشر ترابط الخلفية. هذا يبقي البث نشط بعد عودته من onReceive() . ومع ذلك، حتى مع هذا النهج النظام يتوقع منك الانتهاء مع البث بسرعة كبيرة (أقل من 10 ثانية). أنها تسمح لك لنقل العمل إلى مؤشر ترابط آخر لتجنب خلل الموضوع الرئيسي.
جدولة وظيفة مع JobScheduler . لمزيد من المعلومات، راجع جدولة الوظيفة الذكية .
لا تبدأ الأنشطة من أجهزة استقبال البث لأن تجربة المستخدم هو التنافر؛ خاصة إذا كان هناك أكثر من جهاز استقبال واحد. بدلا من ذلك، فكر في عرض إشعار .





ليست هناك تعليقات:

إرسال تعليق

للوضع الليلي في التطبيق DayNight

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