Broadcasts

来源:互联网 发布:孩子气的战争动作数据 编辑:程序博客网 时间:2024/06/12 09:38

Broadcasts

  1. System broadcasts
    1. Changes to system broadcasts
  2. Receiving broadcasts
    1. Manifest-declared receivers
    2. Context-registered receivers
    3. Effects on process state
  3. Sending broadcasts
  4. Restricting broadcasts with permissions
    1. Sending with permissions
    2. Receiving with permissions
  5. Security considerations and best practices

Android apps can send or receive broadcast messages from the Android system and other Android apps, similar to the publish-subscribe design pattern. These broadcasts are sent when an event of interest occurs. For example, the Android system sends broadcasts when various system events occur, such as when the system boots up or the device starts charging. Apps can also send custom broadcasts, for example, to notify other apps of something that they might be interested in (for example, some new data has been downloaded).

Apps can register to receive specific broadcasts. When a broadcast is sent, the system automatically routes broadcasts to apps that have subscribed to receive that particular type of broadcast.

Generally speaking, broadcasts can be used as a messaging system across apps and outside of the normal user flow. However, you must be careful not to abuse the opportunity to respond to broadcasts and run jobs in the background that can contribute to a slow system performance, as described in the following video.

System broadcasts


The system automatically sends broadcasts when various system events occur, such as when the system switches in and out of airplane mode. System broadcasts are sent to all apps that are subscribed to receive the event.

The broadcast message itself is wrapped in an Intent object whose action string identifies the event that occurred (for exampleandroid.intent.action.AIRPLANE_MODE). The intent may also include additional information bundled into its extra field. For example, the airplane mode intent includes a boolean extra that indicates whether or not Airplane Mode is on.

For more information about how to read intents and get the action string from an intent, see Intents and Intent Filters.

For a complete list of system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the Android SDK. Each broadcast action has a constant field associated with it. For example, the value of the constant ACTION_AIRPLANE_MODE_CHANGED is android.intent.action.AIRPLANE_MODE. Documentation for each broadcast action is available in its associated constant field.

Changes to system broadcasts

Android 7.0 and higher no longer sends the following system broadcasts. This optimization affects all apps, not only those targeting Android 7.0.

  • ACTION_NEW_PICTURE
  • ACTION_NEW_VIDEO

Apps targeting Android 7.0 (API level 24) and higher must register the following broadcasts with registerReceiver(BroadcastReceiver, IntentFilter). Declaring a receiver in the manifest does not work.

  • CONNECTIVITY_ACTION

Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers. If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically).

Receiving broadcasts


Apps can receive broadcasts in two ways: through manifest-declared receivers and context-registered receivers.

Manifest-declared receivers

If you declare a broadcast receiver in your manifest, the system launches your app (if the app is not already running) when the broadcast is sent.

Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction. In most cases, you can use scheduled jobsinstead.

To declare a broadcast receiver in the manifest, perform the following steps:

  1. Specify the <receiver> element in your app's manifest.

    <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>

    The intent filters specify the broadcast actions your receiver subscribes to.

  2. Subclass BroadcastReceiver and implement onReceive(Context, Intent). The broadcast receiver in the following example logs and displays the contents of the broadcast:

    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();    }}

The system package manager registers the receiver when the app is installed. The receiver then becomes a separate entry point into your app which means that the system can start the app and deliver the broadcast if the app is not currently running.

The system creates a new BroadcastReceiver component object to handle each broadcast that it receives. This object is valid only for the duration of the call to onReceive(Context, Intent). Once your code returns from this method, the system considers the component no longer active.

Context-registered receivers

To register a receiver with a context, perform the following steps:

  1. Create an instance of BroadcastReceiver.

    BroadcastReceiver br = new MyBroadcastReceiver();

  2. Create an IntentFilter and register the receiver by calling registerReceiver(BroadcastReceiver, IntentFilter):

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

    Note: To register for local broadcasts, call LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter) instead.

    Context-registered receivers receive broadcasts as long as their registering context is valid. For an example, if you register within an Activitycontext, you receive broadcasts as long as the activity is not destroyed. If you register with the Application context, you receive broadcasts as long as the app is running.

  3. To stop receiving broadcasts, call unregisterReceiver(android.content.BroadcastReceiver). Be sure to unregister the receiver when you no longer need it or the context is no longer valid.

    Be mindful of where you register and unregister the receiver, for example, if you register a receiver in onCreate(Bundle) using the activity's context, you should unregister it in onDestroy() to prevent leaking the receiver out of the activity context. If you register a receiver in onResume(), you should unregister it in onPause() to prevent registering it multiple times (If you don't want to receive broadcasts when paused, and this can cut down on unnecessary system overhead). Do not unregister in onSaveInstanceState(Bundle), because this isn't called if the user moves back in the history stack.

Effects on process state

The state of your BroadcastReceiver (whether it is running or not) affects the state of its containing process, which can in turn affect its likelihood of being killed by the system. For example, when a process executes a receiver (that is, currently running the code in its onReceive() method), it is considered to be a foreground process. The system keeps the process running except under cases of extreme memory pressure.

However, once your code returns from onReceive(), the BroadcastReceiver is no longer active. The receiver's host process becomes only as important as the other app components that are running in it. If that process hosts only a manifest-declared receiver (a common case for apps that the user has never or not recently interacted with), then upon returning from onReceive(), the system considers its process to be a low-priority process and may kill it to make resources available for other more important processes.

For this reason, you should not start long running background threads from a broadcast receiver. After onReceive(), the system can kill the process at any time to reclaim memory, and in doing so, it terminates the spawned thread running in the process. To avoid this, you should either call goAsync() (if you want a little more time to process the broadcast in a background thread) or schedule a JobService from the receiver using the JobScheduler, so the system knows that the process continues to perform active work. For more information, see Processes and Application Life Cycle.

The following snippet shows a BroadcastReceiver that uses goAsync() to flag that it needs more time to finish after onReceive() is complete. This is especially useful if the work you want to complete in your onReceive() is long enough to cause the UI thread to miss a frame (>16ms), making it better suited for a background thread.

public 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();    }}

Sending broadcasts


Android provides three ways for apps to send broadcast:

  • The sendOrderedBroadcast(Intent, String) method sends broadcasts to one receiver at a time. As each receiver executes in turn, it can propagate a result to the next receiver, or it can completely abort the broadcast so that it won't be passed to other receivers. The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter; receivers with the same priority will be run in an arbitrary order.
  • The sendBroadcast(Intent) method sends broadcasts to all receivers in an undefined order. This is called a Normal Broadcast. This is more efficient, but means that receivers cannot read results from other receivers, propagate data received from the broadcast, or abort the broadcast.
  • The LocalBroadcastManager.sendBroadcast method sends broadcasts to receivers that are in the same app as the sender. If you don't need to send broadcasts across apps, use local broadcasts. The implementation is much more efficient (no interprocess communication needed) and you don't need to worry about any security issues related to other apps being able to receive or send your broadcasts.

The following code snippet demonstrates how to send a broadcast by creating an Intent and calling sendBroadcast(Intent).

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

The broadcast message is wrapped in an Intent object. The intent's action string must provide the app's Java package name syntax and uniquely identify the broadcast event. You can attach additional information to the intent with putExtra(String, Bundle). You can also limit a broadcast to a set of apps in the same organization by calling setPackage(String) on the intent.

Note: Although intents are used for both sending broadcasts and starting activities with startActivity(Intent), these actions are completely unrelated. Broadcast receivers can't see or capture intents used to start an activity; likewise, when you broadcast an intent, you can't find or start an activity.

Restricting broadcasts with permissions


Permissions allow you to restrict broadcasts to the set of apps that hold certain permissions. You can enforce restrictions on either the sender or receiver of a broadcast.

Sending with permissions

When you call sendBroadcast(Intent, String) or sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), you can specify a permission parameter. Only receivers who have requested that permission with the tag in their manifest (and subsequently been granted the permission if it is dangerous) can receive the broadcast. For example, the following code sends a broadcast:

sendBroadcast(new Intent("com.example.NOTIFY"),              Manifest.permission.SEND_SMS);

To receive the broadcast, the receiving app must request the permission as shown below:

<uses-permission android:name="android.permission.SEND_SMS"/>

You can specify either an existing system permission like SEND_SMS or define a custom permission with the <permission> element. For information on permissions and security in general, see the System Permissions.

Note: Custom permissions are registered when the app is installed. The app that defines the custom permission must be installed before the app that uses it.

Receiving with permissions

If you specify a permission parameter when registering a broadcast receiver (either with registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) or in <receiver> tag in your manifest), then only broadcasters who have requested the permission with the <uses-permission> tag in their manifest (and subsequently been granted the permission if it is dangerous) can send an Intent to the receiver.

For example, assume your receiving app has a manifest-declared receiver as shown below:

<receiver android:name=".MyBroadcastReceiver"          android:permission="android.permission.SEND_SMS">    <intent-filter>        <action android:name="android.intent.action.AIRPLANE_MODE"/>    </intent-filter></receiver>

Or your receiving app has a context-registered receiver as shown below:

IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );

Then, to be able to send broadcasts to those receivers, the sending app must request the permission as shown below:

<uses-permission android:name="android.permission.SEND_SMS"/>

Security considerations and best practices


Here are some security considerations and best practices for sending and receiving broadcasts:

  • If you don't need to send broadcasts to components outside of your app, then send and receive local broadcasts with the LocalBroadcastManagerwhich is available in the Support Library. The LocalBroadcastManager is much more efficient (no interprocess communication needed) and allows you to avoid thinking about any security issues related to other apps being able to receive or send your broadcasts. Local Broadcasts can be used as a general purpose pub/sub event bus in your app without any overheads of system wide broadcasts.

  • If many apps have registered to receive the same broadcast in their manifest, it can cause the system to launch a lot of apps, causing a substantial impact on both device performance and user experience. To avoid this, prefer using context registration over manifest declaration. Sometimes, the Android system itself enforces the use of context-registered receivers. For example, the CONNECTIVITY_ACTION broadcast is delivered only to context-registered receivers.

  • Do not broadcast sensitive information using an implicit intent. The information can be read by any app that registers to receive the broadcast. There are three ways to control who can receive your broadcasts:

    • You can specify a permission when sending a broadcast.
    • In Android 4.0 and higher, you can specify a package with setPackage(String) when sending a broadcast. The system restricts the broadcast to the set of apps that match the package.
    • You can send local broadcasts with LocalBroadcastManager.
  • When you register a receiver, any app can send potentially malicious broadcasts to your app's receiver. There are three ways to limit the broadcasts that your app receives:

    • You can specify a permission when registering a broadcast receiver.
    • For manifest-declared receivers, you can set the android:exported attribute to "false" in the manifest. The receiver does not receive broadcasts from sources outside of the app.
    • You can limit yourself to only local broadcasts with LocalBroadcastManager.
  • The namespace for broadcast actions is global. Make sure that action names and other strings are written in a namespace you own, or else you may inadvertently conflict with other apps.

  • Because a receiver's onReceive(Context, Intent) method runs on the main thread, it should execute and return quickly. If you need to perform long running work, be careful about spawning threads or starting background services because the system can kill the entire process after onReceive()returns. For more information, see Effect on process state To perform long running work, we recommend:

    • Calling goAsync() in your receiver's onReceive() method and passing the BroadcastReceiver.PendingResult to a background thread. This keeps the broadcast active after returning from onReceive(). However, even with this approach the system expects you to finish with the broadcast very quickly (under 10 seconds). It does allow you to move work to another thread to avoid glitching the main thread.
    • Scheduling a job with the JobScheduler. For more information, see Intelligent Job Scheduling.
  • Do not start activities from broadcast receivers because the user experience is jarring; especially if there is more than one receiver. Instead, consider displaying a notification.

译文:

广播

  1. 系统广播
    1. 系统广播的变化
  2. 接收广播
    1. 清单声明的接收者
    2. 上下文注册的接收器
    3. 对进程状态的影响
  3. 发送广播
  4. 用权限限制广播
    1. 发送权限
    2. 接收权限
  5. 安全考虑和最佳实践

Android应用程序可以发送或接收来自Android系统和其他Android应用程序的广播消息,类似于发布 - 订阅 设计模式。这些广播是在感兴趣的事件发生时发送的。例如,Android系统在发生各种系统事件时发送广播,例如当系统启动或设备开始充电时。应用程序也可以发送自定义广播,例如,通知其他应用程序他们可能感兴趣的东西(例如,一些新的数据已被下载)。

应用程序可以注册以接收特定的广播。当广播被发送时,系统自动将广播路由到已经预订接收该特定类型的广播的应用。

一般来说,广播可以用作应用程序之间和正常用户流程之外的消息传递系统。但是,您必须小心,不要滥用机会回应广播并在后台运行作业,这可能会导致系统性能降低,如以下视频中所述。

系统广播


当各种系统事件发生时,系统自动发送广播,例如当系统切换进入飞行模式时。系统广播被发送到订阅接收事件的所有应用程序。

广播消息本身包装在一个Intent 对象中,对象的操作字符串标识发生的事件(例如 android.intent.action.AIRPLANE_MODE)。意图还可能包括额外的信息绑定到其额外的领域。例如,飞行模式意图包括一个布尔额外的指示飞行模式是否开启。

有关如何读取意图并从意图获取操作字符串的更多信息,请参阅意向和意图过滤器

有关系统广播操作的完整列表,请参阅BROADCAST_ACTIONS.TXTAndroid SDK中的 文件。每个广播动作都有一个与之相关的常量字段。例如,常量的值ACTION_AIRPLANE_MODE_CHANGED是 android.intent.action.AIRPLANE_MODE每个广播操作的文档可以在其相关的常量字段中找到。

系统广播的变化

Android 7.0及更高版本不再发送以下系统广播。此优化会影响所有应用,而不仅仅是针对Android 7.0的应用。

  • ACTION_NEW_PICTURE
  • ACTION_NEW_VIDEO

定位到Android 7.0(API级别24)及更高版本的应用必须使用以下广播注册registerReceiver(BroadcastReceiver, IntentFilter)在清单中声明接收者不起作用。

  • CONNECTIVITY_ACTION

从Android 8.0(API级别26)开始,系统对清单声明的接收方施加额外的限制。如果您的应用定位到API级别26或更高,则无法使用清单来声明大多数隐式广播的接收方(专门不针对您的应用的广播)。

接收广播


应用程序可以通过两种方式接收广播:通过清单声明的接收器和上下文注册的接收器。

清单声明的接收者

如果您在清单中声明广播接收器,系统会在广播发送时启动您的应用程序(如果应用程序尚未运行)。

注意:如果您的应用程序的目标是API级别26或更高,则不能使用清单来声明隐式广播的接收方(专门不针对您的应用程序的广播),除非少数隐式广播免于该限制在大多数情况下,您可以使用计划作业

要在清单中声明广播接收器,请执行以下步骤:

  1. <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>                              

    意图过滤器指定您的接收器订阅的广播操作。

  2. 子类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 附加“行动:” + 意图的getAction ()+ “\ n”个);                                             sb 附加“URI:” + 意图toUri 意向URI_INTENT_SCHEME )。的toString ()+ “\ n”个); 字符串日志= sb toString (); 日志d TAG log ); 吐司makeText 背景下日志吐司LENGTH_LONG )。show (); } }                                

系统包管理器在安装应用程序时注册接收器。接收器然后成为一个单独的入口点到您的应用程序,这意味着系统可以启动应用程序,并提供广播,如果该应用程序当前不在运行。

系统创建一个新的BroadcastReceiver组件对象来处理它接收到的每个广播。此对象仅在调用期间有效onReceive(Context, Intent)一旦你的代码从这个方法返回,系统就认为这个组件不再处于活动状态。

上下文注册的接收器

要使用上下文注册接收者,请执行以下步骤:

  1. 创建一个实例BroadcastReceiver

    BroadcastReceiver br = new MyBroadcastReceiver ();  

  2. 通过以下方式创建IntentFilter并注册接收者registerReceiver(BroadcastReceiver, IntentFilter)

    IntentFilter的过滤器= 的IntentFilter ConnectivityManager CONNECTIVITY_ACTION ); intentFilter 的addAction 意图ACTION_AIRPLANE_MODE_CHANGED ); 这个registerReceiver br filter );  

    注意:要注册本地广播,请调用LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter)

    只要注册上下文有效,上下文注册的接收器就会接收广播。例如,如果您在Activity上下文中注册 ,只要活动未被破坏,您就会收到广播。如果您注册了应用程序上下文,只要应用程序正在运行,您就会收到广播。

  3. 要停止接收广播,请致电unregisterReceiver(android.content.BroadcastReceiver)当您不再需要接收器或上下文不再有效时,请务必注销接收器。

    注意你注册和注销接收者的位置,例如,如果你注册一个接收者onCreate(Bundle)使用活动的上下文,你应该取消注册,onDestroy()以防止接收者从活动上下文中泄漏。如果你注册了一个接收器onResume(),你应该取消注册,onPause()以防止多次注册(如果你不想在暂停时收到广播,这可以减少不必要的系统开销)。不要取消注册onSaveInstanceState(Bundle),因为如果用户移回到历史堆栈,则不会调用该注册

对进程状态的影响

你的状态BroadcastReceiver(无论是否在运行)影响其包含过程的状态,这反过来可能影响系统被杀的可能性。例如,当一个进程执行一个接收者(也就是说,当前在其onReceive() 方法中运行该代码)时,它被认为是一个前台进程。系统保持进程运行,除非存在极大的内存压力。

但是,一旦您的代码返回onReceive(),BroadcastReceiver不再处于活动状态。接收者的主机进程变得和在其中运行的其他应用程序组件一样重要。如果该进程仅托管清单声明的接收方(对于用户从来没有或最近没有进行过交互的应用程序的常见情况),则在返回时onReceive(),系统将其进程视为低优先级进程,并可能将其终止为其他更重要的流程提供资源。

因此,您不应该从广播接收器开始长时间运行后台线程。之后onReceive(),系统可以随时终止进程来回收内存,这样做会终止在进程中运行的衍生线程。为了避免这种情况,您应该调用goAsync()(如果您希望有更多时间在后台线程中处理广播),或者JobService使用接收者从接收者调度a JobScheduler,那么系统知道该进程继续执行主动工作。有关更多信息,请参阅进程和应用程序生命周期

下面的代码片段显示了一个BroadcastReceiver使用goAsync()到它需要更多的时间来完成后旗onReceive()完成。如果你想在你完成的工作onReceive()足够长,导致UI线程错过一个帧(> 16ms),这使得它更适合后台线程,这是特别有用的

public 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 附加“行动:” + 意图的getAction ()+ “\ n”个);                 sb 追加“URI:” + 意图toUri                                                    意图URI_INTENT_SCHEME )。toString ()+ “\ n” ); 日志d TAG log ); //必须调用finish()以便BroadcastReceiver可以被回收。                pendingResult 完成(); 返回数据; } };         asyncTask execute (); } }                                                                          

发送广播


Android为应用程序提供了三种发送广播的方式:

  • sendOrderedBroadcast(Intent, String) 方法一次向一个接收机发送广播。由于每个接收器依次执行,它可以将结果传播到下一个接收器,或者它可以完全中止广播,使其不会传递给其他接收器。运行的订单接收者可以用匹配意图过滤器的android:priority属性来控制; 具有相同优先级的接收器将以任意顺序运行。
  • sendBroadcast(Intent)方法以未定义的顺序向所有接收机发送广播。这被称为普通广播。这样更有效率,但意味着接收者不能从其他接收者读取结果,传播从广播接收到的数据,或者中止广播。
  • LocalBroadcastManager.sendBroadcast方法发送广播到发件人在同一个应用程序的接收器。如果您不需要跨应用程序发送广播,请使用本地广播。实现效率更高(不需要进程间通信),您不必担心与其他应用程序能够接收或发送广播相关的任何安全问题。

以下代码片段演示了如何通过创建一个Intent并调用来发送广播sendBroadcast(Intent)

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

广播消息被包装在一个Intent对象中。意图的动作字符串必须提供应用程序的Java包名称语法,并唯一标识广播事件。您可以附加附加信息的意图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>元素定义自定义权限 有关一般权限和安全性的信息,请参阅系统权限

注意:自定义权限是在安装应用程序时注册的。定义自定义权限的应用程序必须安装在使用它的应用程序之前。

接收权限

如果您在注册广播接收机时指定一个权限参数(无论是在清单registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)中的<receiver>标签还是在 标签中),那么只有在清单中请求带有<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效率要高得多(不需要进程间通信),并可以让你避免考虑与其他应用程序能够接收或发送你的广播任何安全问题。本地广播可以在您的应用程序中用作通用的发布/订阅事件总线,而无需系统广播的任何开销。

  • 如果很多应用程序已经注册在清单中接收到相同的广播,则可能会导致系统启动大量应用程序,从而对设备性能和用户体验产生重大影响。为了避免这种情况,更喜欢使用清单声明上的注册。有时,Android系统本身强制使用上下文注册的接收器。例如,CONNECTIVITY_ACTION广播只传送给上下文注册的接收者。

  • 不要使用隐含的意图来传播敏感信息。这些信息可以被任何注册接收广播的应用读取。有三种方法可以控制谁可以接收您的广播:

    • 您可以在发送广播时指定权限。
    • 在Android 4.0及更高版本,可以指定一个 与 setPackage(String)发送广播时。系统将广播限制为与包匹配的一组应用程序。
    • 您可以发送本地广播LocalBroadcastManager
  • 当您注册接收器时,任何应用程序都可能将恶意广播发送到应用程序的接收器。有三种方法可以限制您的应用收到的广播:

    • 您可以在注册广播接收机时指定权限。
    • 对于清单声明的接收者,可以在清单中将 android:exported 属性设置为“false”。接收器不接收来自应用程序之外的来源的广播。
    • 你可以限制自己只有本地广播LocalBroadcastManager
  • 广播操作的命名空间是全局的。确保动作名称和其他字符串是在您拥有的名称空间中编写的,否则您可能会无意中与其他应用程序发生冲突。

  • 因为接收者的onReceive(Context, Intent)方法在主线程上运行,所以应该快速执行并返回。如果您需要执行长时间运行的工作,请注意产生线程或启动后台服务,因为系统可能会在onReceive()返回终止整个进程 有关更多信息,请参阅对进程状态的影响要执行长时间运行的工作,我们建议:

    • 调用goAsync()接收者的onReceive()方法并将其传递BroadcastReceiver.PendingResult给后台线程。这从广播返回后保持广播活动onReceive()但是,即使采用这种方法,系统也会很快(10秒以内)完成广播。它允许您将工作移动到另一个线程,以避免干扰主线程。
    • JobScheduler安排工作有关更多信息,请参阅智能作业计划
  • 不要从广播接收机开始活动,因为用户体验震撼; 特别是如果有多个接收器的话。相反,请考虑显示通知


原创粉丝点击