آموزش کامل broadcastreceiver در اندروید

broadcastreceiver در اندروید

برنامه های اندروید می توانند پیام های broadcastreceiver را از سیستم اندرویدی و سایر برنامه های اندروید مانند الگوی طراحی انتشار و اشتراک (publish-subscribe) ارسال یا دریافت کنند. این رویدادها هنگام ارسال یک رویداد مورد علاقه فرستاده می شوند. سیستم اندروید هنگامی که رویدادهای مختلف سیستم رخ می دهد برنامه های پخش را می فرستد، مانند زمانی که سیستم دستگاه boot می شود یا شروع به شارژ می کند.

برنامه ها همچنین می توانند broadcast های سفارشی ارسال کنند، برای مثال، برای اطلاع رسانی برنامه های دیگری که مورد علاقه شما باشند. (برای مثال برخی از داده های جدید که دانلود شده است).

برنامه ها می توانند برای broadcastreceiver های مخصوص، ثبت نام کنند. وقتی broadcast ارسال می شود، یک سیستم بطور خودکار مسیرهای broadcastها را به برنامه که برای دریافت نوع خاصی از broadcast مشترک شده اند، میفرستد.

به طور کلی، broadcast  می تواند به عنوان یک سیستم پیام رسان در سراسر برنامه ها و خارج از روند نرمال کاربر استفاده شود. با این حال، شما باید مراقب باشید که از فرصت برای پاسخگویی به broadcasts و اجرای مشاغل در پس زمینه سو استفاده نکنید، که می تواند باعث کندی عملکرد سیستم شود.

broadcast های سیستم

این سیستم زمانی که رویدادهای مختلف سیستم رخ می دهد به طور خودکار broadcast ها را می فرستد، مانند زمانی که سیستم به حالت پرواز (airplane) می رود و خارج می شود. broadcast های سیستم به تمام برنامه هایی که برای دریافت رویداد مشترک شده اند ارسال می شود.

پیام broadcast  خود را در یک شی intent که رشته عملیات رویداد را نشان می دهد، می پیچد (به عنوان مثال android.intent.action.AIRPLANE_MODE). این intent  ممکن است شامل اطلاعات اضافی همراه با فیلد اضافی نیز باشد. به عنوان مثال، intent حالت پرواز پرواز (airplane) حاوی اطلاعات اضافیست که نشان می دهد آیا حالت پرواز (airplane) روشن است یا خیر.

مطلب مرتبط: آموزش کامل استفاده از intent در اندروید

برای اطلاعات بیشتر در مورد چگونگی خواندن intent و دریافت رشته عملیاتی از یک intent، به Intents and Intent Filters در سایت گوگل یا ساخت intent و کار با آن نگاه کنید.

برای لیست کامل broadcast های عملیاتی سیستم ، فایل BROADCAST_ACTIONS.TXT را در Android SDK مشاهده کنید. هر broadcast  عملیاتی دارای یک فیلد ثابت همراه است. به عنوان مثال، مقدار  ACTION_AIRPLANE_MODE_CHANGED ثابت android.intent.action.AIRPLANE_MODE است. مستندات برای هر broadcast  عملیاتی همراه با فیلد ثابت آن موجود است.

تغییرات در broadcast های سیستم

Android 7.0 و بالاتر، دیگر سیستم های broadcasts زیر را نمی فرستند. این بهینه سازی بر همه برنامه ها تاثیر می گذارد، نه تنها آنهایی که با Android 7.0 کار می کنند.

برنامه هایی که با Android 7.0 (API level 24) و بالاتر کار می کنند باید برنامه های زیر را با registerReceiver(BroadcastReceiver, IntentFilter) ثبت کنند. اعلام یک دریافت کننده در مانیفست (manifest) کار نمی کند.

CONNECTIVITY_ACTION

با Android 8.0 (سطح API 26)، سیستم محدودیت های بیشتری را بر روی گیرنده های اعلام شده، اعمال می کند. اگر برنامه شما API سطح 26 یا بالاتر باشد، نمی توانید برای اکثر برنامه های ضمنی، از مانیفست برای اعلام گیرنده استفاده کنید(broadcast ها که به طور مشخص برنامه شما را هدف قرار نمی دهند).

broadcastreceiver

برنامه ها می توانند broadcast ها را به دو طریق دریافت کنند: از طریق گیرنده های اعلام شده در مانیفست (manifest) و گیرنده های ثبت شده با context.

گیرنده های اعلام شده در مانیفست (manifest)

اگر یک broadcastreceiver را در مانیفست خود اعلام کنید، سیستم هنگامی که broadcast ارسال می شود، برنامه شما را اجرا می کند (اگر برنامه در حال اجرا نباشد).

توجه: اگر برنامه شما API سطح 26 یا بالاتر باشد، شما نمی توانید از مانیفست برای اعلام broadcastreceiver های ضمنی استفاده کنید (broadcast هایی که به طور خاص برنامه خود را هدف قرار نمی دهند)، به جز چند broadcast ضمنی که از این محدودیت معاف (exempted from that restriction) هستند. در اغلب موارد، شما می توانید از کارهای برنامه ریزی شده (scheduled jobs) استفاده کنید.

برای اعلام broadcastreceiver در مانیفست، مراحل زیر را انجام دهید:

1- عنصر <receiver> را در manifest  برنامه خود مشخص کنید.

intent  فیلترهای ذکر شده در عملیات broadcast  را که گیرنده شما به آن موافقت می کند را مشخص می کند.

2- زیر کلاس BroadcastReceiver و پیاده سازی onReceive(Context, Intent) . گیرنده broadcast  در مثال زیر وقایع و محتویات broadcast را نشان می دهد:

سیستم مدیر بسته گیرنده را ، وقتی که برنامه نصب شد، ثبت می کند. گیرنده به یک نقطه ورود جداگانه به برنامه شما تبدیل می شود، بدین معنی که سیستم می تواند برنامه را اجرا و broadcast را در صورتی که برنامه در حال اجرا نیست، دریافت کند.

این سیستم یک شی BroadcastReceiver ترکیبی جدید برای رسیدگی به هر broadcast  دریافت می کند. این شیء فقط برای مدت زمان فراخوانی onReceive(Context, Intent) معتبر است. هنگامی که کد شما از این روش باز می گردد، سیستم مولفه دیگر را فعال می کند.

گیرنده های ثبت شده با Context (Context-registered receivers)

برای ثبت گیرنده با context ، مراحل زیر را انجام دهید:

1- یک نمونه از BroadcastReceiver ایجاد کنید.

BroadcastReceiver br = new MyBroadcastReceiver();

2- یک IntentFilter ایجاد کنید و گیرنده را بوسیله فراخوانی registerReceiver(BroadcastReceiver, IntentFilter) ثبت کنید:

توجه: برای ثبت broadcast های محلی،  LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter) را فراخوانی کنید.

گیرنده های ثبت شده با Context تا زمانی که Context ثبت نام آنها معتبر است، broadcast می شوند. برای مثال، اگر شما در یک اکتیویتی context ثبت کنید، تا زمانی که اکتیویتی از بین نرود، broadcast دریافت می کنید. اگر در context برنامه ثبت نام کنید، تا زمانی که برنامه در حال اجرا است، برنامه های broadcast را دریافت می کنید .

3- برای جلوگیری از دریافت broadcast ، unregisterReceiver(android.content.BroadcastReceiver) را فراخوانی کنید. مطمئن شوید که گیرنده زمانی که دیگر به آن نیاز ندارید یا context  دیگر معتبر نیست، لغو شود.این برای سرعت برنامه شما بسیار مهم است

برای مثال، اگر گیرنده را در onCreate(Bundle) با استفاده از اکتیویتی context ثبت نام کنید، شما باید آن را در onDestroy() لغو کنید تا مانع نفوذ گیرنده از محیط اکتیویتی شوید. اگر یک گیرنده را در onResume() ثبت کنید، باید آن را از onPause() لغو کنید تا از ثبت چندین بار آن جلوگیری شود (اگر نمی خواهید در هنگام مکث(pause)، broadcast دریافت کنید ، و این می تواند هزینه های سیستم غیر ضروری را کاهش دهد).  در onSaveInstanceState(Bundle) ثبت نام نکنید، زیرا اگر کاربر در بازگشت به پشته تاریخچه (history) حرکت کند، این فراخوانی نمی شود.

نتایج بر روی حالت فرایند

حالت BroadcastReceiver (آیا در حال اجرا است یا خیر) بر حالت فرایند حاوی آن تأثیر می گذارد، که می تواند بر روی احتمال کشته شدن سیستم تاثیر بگذارد. برای مثال، هنگامی که فرایند یک گیرنده را اجرا می کند (یعنی، در حال حاضر کد را در متد onReceive() اجرا می کند)، این یک فرایند پیش زمینه است. این سیستم فرایند اجرا را، به جز در موارد فشار شدید حافظه، نگه می دارد.

با این حال، هنگامی که کد شما از onReceive() برمی گردد، BroadcastReceiver  دیگر فعال نیست. فرایند میزبان گیرنده تنها به عنوان اجزای برنامه دیگر که در آن اجرا می شود، مهم است. اگر این فرایند تنها یک گیرنده اعلام شده در manifest باشد (یک مورد معمول برای برنامه هایی است که کاربر هرگز یا اخیراً با آن ارتباط برقرار نکرده) ، پس از بازگشت از onReceive()،سیستم فرایند آن را یک فرایند با اولویت کم در نظر می گیرد و ممکن است آن را برای ایجاد منابع در دسترس برای سایر فرایندهای مهم تر بُکشد.

به همین دلیل، شما نباید از یک گیرنده broadcast  ، threadهای پس زمینه ای طولانی اجرا  کنید. پس از onReceive()، سیستم می تواند فرآیند را در هر زمان برای بازگرداندن حافظه از بین ببرد، و در انجام این کار، thread  ایجاد شده ی در حال اجرا، پایان می پذیرد. برای جلوگیری از این، شما باید یا goAsync() را فراخوانی کنید (اگر شما زمان بیشتری را برای پردازش یک broadcast  در پس زمینه بخواهید) یا برنامه JobService را از گیرنده با استفاده از JobScheduler برنامه ریزی کنید، بنابراین سیستم می داند که این روند همچنان به انجام کار فعال ادامه می دهد. برای اطلاعات بیشتر، مراحل پردازش و چرخه زندگی برنامه(Processes and Application Life Cycle) را ببینید.

قطعه زیر یک BroadcastReceiver را نشان می دهد که از goAsync() برای flag آن استفاده می کند که به زمان بیشتری برای تکمیل شدن بعد از onReceive() نیاز دارد. این کار بسیار مفید است اگر کارهایی که می خواهید در onReceive()انجام دهید، به اندازه کافی بلند باشد باعث می شود thread ، UI فریم (>16ms) را از دست بدهد، و از  آن یک thread پس زمینه مناسب می سازد.

ارسال broadcast ها

آندروید سه راه برای برنامه های ارسال broadcast فراهم می کند:

– متد sendOrderedBroadcast(Intent, String) یک broadcast را در یک زمان به یک گیرنده می فرستد. همانطور که هر گیرنده به نوبت اجرا می کند، می تواند یک نتیجه را به گیرنده بعدی broadcast  کند، یا می تواند broadcast را به طور کامل قطع کند به طوری که دیگر به گیرنده ها منتقل نشود. گیرنده سفارش که در آن اجرا می شود می تواند با ویژگی android:priority مطابق فیلتر intent کنترل شود ؛ گیرنده هایی با همان اولویت در یک دستور اختیاری اجرا می شوند.

– متد sendBroadcast(Intent)، broadcast را به همه گیرنده ها در یک سفارش نامشخص ارسال می کند. این یک broadcast معمولی است. این کارآمدتر است، اما به این معنی است که گیرنده ها نمی توانند نتایج را از گیرنده های دیگر بخوانند، داده های دریافت شده از broadcast را منتشر یا broadcast را قطع کنند.

– متد LocalBroadcastManager.sendBroadcast broadcast ارسال شده را به گیرنده ها می فرستد که در همان برنامه به عنوان فرستنده هستند. اگر شما نیازی به ارسال broadcast در اپلیکیشن ندارید ، از broadcast محلی استفاده کنید. پیاده سازی بسیار کارآمدتر است (هیچ ارتباطی بین پردازش مورد نیاز نیست) و شما لازم نیست نگرانی در مورد مسائل امنیتی مربوط به برنامه های دیگر که قادر به دریافت یا ارسال broadcast هستند، باشید.

قطعه کد زیر نشان می دهد که چگونه یک broadcast  با ایجاد یک Intent و sendBroadcast(Intent) فراخوانی می شود.

پیام broadcast  در یک شی intent  قرار می گیرد. رشته عملیات intent  باید دستور نحوی(syntax) نام بسته ی برنامه جاوا را ارائه کند و رویداد broadcast  را منحصر به فرد شناسایی کند. با putExtra(String, Bundle) می توانید اطلاعات اضافی را به intent اضافه کنید. شما همچنین می توانید یک broadcast  را به مجموعه ای از برنامه ها در همان سازمان و با فراخوانی setPackage(String) در intent  محدود کنید.

نکته: اگرچه intentها برای فرستادن broadcast ها و شروع اکتیویتی  با startActivity(Intent) مورد استفاده قرار می گیرند، این اقدامات کاملا ًغیر مستقیم هستند. گیرنده های Broadcast  نمی توانند نکات مورد استفاده برای شروع اکتیویتی را ببینند و یا ضبط کنند. به همین ترتیب، هنگامی که یک intent را broadcast می کنید، نمی توانید اکتیویتی را پیدا یا شروع کنید.

محدود کردن broadcast ها با مجوز(permission)

مجوز ها به شما اجازه می دهد تا broadcastها را به مجموعه ای از برنامه ها، که دارای مجوز های خاص هستند، محدود کنید . شما می توانید محدودیت ها را بر روی فرستنده یا گیرنده یک broadcast اعمال کنید.

ارسال با مجوز

وقتی می خواهید sendBroadcast(Intent, String) یا sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) را فراخوانی کنید، می توانید پارامتر permission  را مشخص کنید. فقط گیرندگان که مجوز را با تگ در مانیفست(manifest) خود درخواست کرده اند (و اگر بعد از آن خطرناک باشد مجوز آن را متعاقباً صادر می کند) می توانند این broadcast را دریافت کنند. به عنوان مثال، کد زیر یک broadcast را می فرستد:

برای دریافت broadcast ، برنامه پذیرنده باید مجوز را درخواست کند، همانطور که در زیر نشان داده شده است:

شما می توانید یک مجوز سیستمی موجود مانند SEND_SMS یا یک مجوز سفارشی را با عنصر <permission> مشخص کنید. برای اطلاعات در مورد مجوزها و به طور کلی امنیت، مجوزهای سیستم (System Permissions) را مطالعه کنید.

توجه: مجوز های سفارشی هنگامی که برنامه نصب می شود ثبت می شوند. برنامه که مجوز سفارشی را مشخص می کند باید قبل از برنامه ای که از آن استفاده می شود نصب شود.

دریافت با مجوز

پارامتر مجوز را در هنگام ثبت یک گیرنده broadcast  مشخص می کنید (یا با registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) یا در تگ <receiver> در مانیفست) و سپس تنها پخش کننده ها (broadcasters) که مجوز درخواست را با تگ <uses-permission> در مانیفست دارند (و اگر بعد از آن خطرناک باشد مجوز آن را متعاقباً صادر می کند) می توانید یک intent را به گیرنده ارسال کنید.

به عنوان مثال فرض کنید که برنامه دریافتی شما یک گیرنده اعلام شده در مانیفست باشد مانند آنچه در زیر نشان داده شده است:

سپس، برای ارسال broadcast ها به آن گیرندگان، برنامه در حال ارسال باید مجوز را درخواست کند، همانطور که در زیر نشان داده شده است:

ملاحظات امنیتی و بهترین شیوه ها

در اینجا برخی از ملاحظات امنیتی و بهترین شیوه های ارسال و دریافت broadcast ها آمده است:

– اگر شما نیازی به ارسال broadcast ها به اجزای خارج از برنامه خود ندارید، پس با LocalBroadcastManager که در کتابخانه پشتیبانی(Support Library) موجود است، broadcast های محلی را ارسال و دریافت کنید. LocalBroadcastManager  بسیار کارآمدتر است (هیچ ارتباطی بین پردازش مورد نیاز نیست) و به شما اجازه می دهد از فکر کردن در مورد هر گونه مسائل امنیتی مربوط به برنامه های دیگر که قادر به دریافت یا ارسال broadcast های خود هستند اجتناب کنید. broadcast های محلی را می توان مانند یک منظور عمومی pub/sub  رویداد خطی در برنامه خود بدون هیچ سرباری از broadcast های گسترده ، استفاده کرد.

– اگر بسیاری از برنامه ها برای دریافت broadcast مشابه در مانیفست ثبت شوند، می تواند باعث شود سیستم بسیاری از برنامه ها را راه اندازی کند و تاثیر قابل توجهی بر عملکرد دستگاه و تجربه کاربر داشته باشد. برای اجتناب از این، ترجیح می دهد از context  برای ثبت اعلانات در مانیفست استفاده شود. گاهی اوقات، سیستم اندرویدی خود را برای استفاده از گیرنده های ثبت شده با context اجرا می کند. به عنوان مثال، broadcast  CONNECTIVITY_ACTION فقط به گیرنده های ثبت شده context تحویل داده می شود.

– اطلاعات حساس را با استفاده از intent ضمنی broadcast  نکنید. اطلاعات ممکن است توسط هر برنامه ای که برای دریافت broadcast  ثبت می شود، خوانده شود. سه راه برای کنترل افرادی که می توانند broadcast های شما را دریافت کنند وجود دارد:

– شما می توانید یک مجوز را هنگام ارسال broadcast مشخص کنید.

– در Android 4.0 و بالاتر می توانید هنگام ارسال یک broadcast یک بسته (package) را با setPackage(String) مشخص کنید. این سیستم broadcast  را به مجموعه ای از برنامه هایی که با بسته همخوانی دارند، محدود می کند.

– شما می توانید broadcast های محلی را با LocalBroadcastManager ارسال کنید.

– هنگامی که یک گیرنده را ثبت می کنید، هر برنامه می تواند broadcast های بالقوه مخرب را به گیرنده برنامه شما ارسال کند. سه راه برای محدود کردن broadcast های دریافتی برنامه وجود دارد:

– شما می توانید هنگام ثبت گیرنده broadcast مجوز  را مشخص کنید.

– برای اعلام گیرنده ها در مانیفست، شما می توانید ویژگی android:exported را در مانیفست به “false” تنظیم کنید. broadcast receiver های خارج از منابع برنامه دریافت نمی کند.

– شما می توانید خود را تنها با broadcastهای محلی با  LocalBroadcastManager محدود کنید.

– namespace  برای اعمال broadcast جهانی است. اطمینان حاصل کنید که نام های عملی و دیگر رشته ها در یک namespace  که مالک آن هستید نوشته شده است یا سهواً با برنامه های دیگر ناسازگار است.

– از آنجا که متد گیرنده onReceive(Context, Intent) بر روی thread اصلی اجرا می شود، آن باید اجرا شود و به سرعت برگردد. اگر شما نیاز به انجام کار طولانی مدت دارید، مراقب باشید در مورد spawning threads یا شروع خدمات پس زمینه، زیرا سیستم می تواند بعد از برگشت onReceive() کل فرایند را از بین ببرد. برای اطلاعات بیشتر، برای انجام کار طولانی مدت به نتایج بر روی حالت فرایند(Effect on process state) نگاه کنید، توصیه می کنیم:

– فراخوانی goAsync() در متد onReceive() دریافت کننده و انتقال BroadcastReceiver.PendingResult به یک thread پس زمینه. این broadcast فعال را بعد از onReceive() برگشت نگه می دارد. با این حال، حتی با این رویکرد سیستم انتظار دارد که شما با broadcast  بسیار سریع به پایان برسید (کمتر از 10 ثانیه). این کار به شما امکان می دهد که کار را به یک thread  دیگر منتقل کنید تا مانع حرکت thread  اصلی نشود.

– برنامه ریزی کار با JobScheduler. برای اطلاعات بیشتر، برنامه ریزی هوشمندانه شغل(Intelligent Job Scheduling) را ببینید.

– اکتیویتی ها را از broadcast receiver شروع نکنید زیرا تجربه کاربر نامطلوب (jarring ) است. به ویژه اگر بیش از یک گیرنده وجود داشته باشد. در عوض، نمایش یک اعلان (notification) را در نظر بگیرید.

منبع: https://developer.android.com/guide/components/broadcasts.html#security_considerations_and_best_practices

توجه توجه: اگر توسعه دهنده اندروید هستی و می خوای کسب درآمد کنی می تونی سورس هاتو اینجا بفروشی. اگر هم نیاز به دانلود سورس داری می تونی یه عالمه سورس رایگان و پولی از اینجا دانلود کنی.

درباره ShopDroid

فروشگاه توسعه دهندگان موبایل شاپ دروید با بیش از 7 سال سابقه مفتخر است که اولین و بهترین فروشگاه سورس می باشد

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *