美文网首页
Android中的广播

Android中的广播

作者: sunhaiyu | 来源:发表于2017-05-11 21:59 被阅读548次

    Android中的广播

    广播接受器,可以比喻成收音机。而广播则可以看成电台。

    Android系统内部相当于已经有一个电台 定义了好多的广播事件,比如外拨电话 短信到来 sd卡状态 电池电量变化...

    广播的两种注册方式

    静态注册

    静态注册写在AndroidManifest.xml,即使没有进入应用(没有写在onCreate里面),也可以接收到。如接收开机广播。

    监听外拨电话

    写个拨打电话,自动加区号的功能。区号可以自定义,每次填了区号后,会存到偏好文件中。若不改区号,每次默认打电话都会加这个区号。(这个程序实在没什么意义)

    可直接在Android Studio中File -> New -> Other -> Broadcast Receiver。需要重写OnReceive方法,这个方法在广播接受器接收到广播的时候被调用。

    AndroidManifest.xml下注册

    <receiver
        android:name=".TelReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter >
            <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
        </intent-filter>
    </receiver>
    

    其中android:enabled="true"表示启用这个广播,默认为trueandroid:enabled="true"表示这个广播接收器可以接收本程序以外的广播。其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。一般就上面默认生成的写法就好了,显式指定为true更直观不是吗。

    同时申请权限<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>,记住一定要申请运行时权限啊,我傻傻的调试了半天......

    主界面一个输入框用来自定义默认区号,和一个按钮保存到偏好文件。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.telbroadcastreceivertest.MainActivity">
    
        <EditText
            android:id="@+id/et_area_code"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <Button
            android:id="@+id/bt_save"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="保存区号"/>
    
    </LinearLayout>
    
    

    MainActivity

    package com.example.telbroadcastreceivertest;
    
    import android.Manifest;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.pm.PackageManager;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private EditText editText;
        private Context mContext;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mContext = this;
            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS}, 1);
            }
    
            editText = (EditText) findViewById(R.id.et_area_code);
            Button button = (Button) findViewById(R.id.bt_save);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String areaCode = editText.getText().toString().trim();
                    SharedPreferences spf = getSharedPreferences("code", MODE_PRIVATE);
                    // 保存区号到偏好文件,下次拨打电话默认加这个前缀
                    spf.edit().putString("code", areaCode).apply();
                    Toast.makeText(mContext, "区号保存成功", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    
    

    广播接收器,可以拦截外拨电话的有序广播

    package com.example.telbroadcastreceivertest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    
    public class TelReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            SharedPreferences spf = context.getSharedPreferences("code", Context.MODE_PRIVATE);
            String areaCode = spf.getString("code", "");
    
            // 接收前一个广播接收者的所设定的数据,这里是拨号器的广播接收者,数据是电话号码
            String phoneNumber = getResultData();
            // 区号一般以0开头,若号码不以0开头,就加上区号
            if (!phoneNumber.startsWith("0")) {
                setResultData(areaCode + phoneNumber);
            }
        }
    }
    
    

    向外拨打电话时系统会发出一个有序广播,android.intent.action.NEW_OUTGOING_CALL,虽然该广播最终会被拔号器里的广播接收者所接收并实现电话拔打,但我们可以在广播传递给拔号广播接收者之前先得到该广播,并添加了区号后再拨打出去。

    填写默认的区号。

    由于使用真机,拨号使用了一个空号。

    看图,确实是添加了区号再拨打出去的

    测试成功后,赶紧给卸载了,这会影响电话拨打功能的。

    动态注册

    监听SD卡的挂载/未挂载

    注意:这里所说的SD卡是真实的外置SD卡

    之前使用真机,还有模拟器,SD卡的选择是internal storage而非protable storage。这样就不带外置SD卡,所以一直接收不到广播,折腾了半天。引以为戒!

    AndroidManifest.xml里面

    <receiver android:name=".SDReceiver"
         android:enabled="true"
         android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED"/>
        <action android:name="android.intent.action.MEDIA_REMOVED"/>
        <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
        <!-- 一定要指定下面这个scheme为"file",否则无法接收到广播 -->
        <data android:scheme="file"/>
      </intent-filter>
    </receiver>
    

    上面的写法是静态注册,用动态注册的方式如下,也一定要加上scheme。注意动态注册只能当前Activity能接收到广播,因为是写在onCreate方法里的嘛。

    // onCreate方法内
    IntentFilter intentFilter = new IntentFilter();
    // 同时加了三个action,可以接收到这三种系统广播
    intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
    intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
    intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
    // scheme必须加
    intentFilter.addDataScheme("file");
    // 实例化广播接收者
    SDReceiver sdReceiver = new SDReceiver();
    // 注册广播接收器,接收一个实例和intentFilter。匹配action和data
    registerReceiver(sdReceiver , intentFilter);
    
    // !!! 注册了还必须注销,在onDestroy方法内
     @Override
        protected void onDestroy() {
            unregisterReceiver(telReceiver);
            super.onDestroy();
        }
    

    动态注册,必须注销。而静态注册,无需操心注销的事。

    动态注册的优先级是要高于静态注册优先级的

    然后新建一个Broadcast Receiver重写receive方法,判断状态

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.MEDIA_MOUNTED".equals(action)) {
          Log.d("SD卡", "外置SD卡存在,且已挂载mounted");
        } else if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
          Log.d("SD卡", "外置SD卡存在,但未挂载unmounted");
        } else if (Intent.ACTION_MEDIA_EJECT.equals(action)) {
          Log.d("SD卡", "外置SD卡卸载ejected");
        } else if (Intent.ACTION_MEDIA_REMOVED.equals(action)) {
          Log.d("SD卡", "外置SD卡移除removed");
        }
    

    当挂载了外置SD卡时候,就会打印外置SD卡存在,且已挂载mounted,正常卸载时候打印外置SD卡存在,但未挂载外置SD卡卸载ejected。当拔出了SD卡的情况,不仅打印上面两个,还会打印外置SD卡移除removed

    拓展

    现在的手机一般很少插入了真实的外置SD卡,我们之前所说的SD卡指的是虚拟的内置SD卡,又叫做internal storage,路径是/mnt/sdcard或者/storage/emulated/0又或者/sdcard,这三个路径指向同一个地方。

    Environment.getExternalStorageDirectory().getPath(); // 这里小米真机打印/storage/emulated/0
    

    从Androidkk4.4开始,第三方应用程序是无法访问(读/写)外置SD卡的;仅仅只有系统级别的并且使用系统签名的APP可以访问外置SD卡。但就我测试环境(API25)来看,是并不影响监听外置SD卡状态的。

    还可以判断内置SD卡的状态,使用如下方法。当然外置SD的拔插,都不影响内置SD卡。都会打印mounted

    Log.d("SDcard", Environment.getExternalStorageState()); // 打印mounted
    Log.d("SDcard", Environment.getExternalStorageDirectory().getPath()); // 打印 /storage/emulated/0
    

    接收(拦截)短信

    注册

    <!-- 申请接收短信的权限 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <!-- 省略部分代码 -->
    <receiver
        android:name=".SmsReceiver"
        android:enabled="true"
        android:exported="true">
      <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
      </intent-filter>
    </receiver>
    

    申请的权限记得要动态申请。

    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECEIVE_SMS}, 1);
    }
    

    广播接收器

    package com.example.telbroadcastreceivertest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.telephony.SmsMessage;
    import android.util.Log;
    
    public class SmsReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 每一个object为一条短信,实际返回的是byte[][],一个pdu对应byte[]
            Object[] smss = (Object[]) intent.getExtras().get("pdus");
            Log.d("sms", String.valueOf(smss.length));
            for (Object sms : smss) {
                // API23后,必须加入format参数
                String format = intent.getStringExtra("format"); // 模拟器,打印3gpp
                Log.d("sms", format);
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                    SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms, format);
                    // 获取发送短信的内容
                    // 功能更强大,如果有,可以得到email message body和address
                    String dispalyBody = smsMessage.getDisplayMessageBody();
                    String displayAddr = smsMessage.getDisplayOriginatingAddress();
    
                    // 纯文本的消息体
                    String body = smsMessage.getMessageBody();
                    // 获取发送者号码
                    String address = smsMessage.getOriginatingAddress();
                    Log.d("sms", "disBody:"+dispalyBody); // 由于发送的就是一般的文本短信,打印内容和下面一样
                    Log.d("sms", "body:"+body);
                    Log.d("sms", "disAddr:"+displayAddr); // 打印内容和下面一样
                    Log.d("sms", "addr:"+address);
                }
    
            }
        }
    }
    
    

    API23开始,SmsMessage.createFromPdu(byte[] sms);被弃用。使用SmsMessage.createFromPdu((byte[]) sms, format);format可以用String format = intent.getStringExtra("format");获取。

    这个例子在真机上(可恶的小米5S)测试又失败了。估计有啥流氓软件给先拦截了。不过,在模拟器上测试成功。

    监听应用的安装、更新、卸载

    注册

    <receiver android:name=".APPReceiver">
      <intent-filter>
        <!-- 安装应用 -->
        <action android:name="android.intent.action.PACKAGE_ADDED" />
        <!-- 更新已有应用 -->
        <action android:name="android.intent.action.PACKAGE_REPLACED" />
        <!-- 卸载应用 -->
        <action android:name="android.intent.action.PACKAGE_REMOVED" />
        <!-- 携带包名,这个必须要加上 -->
        <data android:scheme="package" />
      </intent-filter>
    </receiver>
    

    不需要申请啥权限

    广播接收器

    package com.example.telbroadcastreceivertest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.util.Log;
    
    
    public class APPReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 判断广播类型
            String action = intent.getAction();
            //获取包名
            // intent.getData().toString
            String appName = intent.getDataString();
    
            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                Log.i("APPReceiver", "ADD" + appName);
            } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                Log.i("APPReceiver", "REPLACED" + appName);
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                Log.i("APPReceiver", "REMOVE" + appName);
            }
        }
    }
    

    应用在更新时,会先REMOVED,然后在REPLACED。在本例中,自己本身被安装和卸载,接收不到ADDED和REMOVED广播。

    应用未启动过,接收不到广播

    资料来自张明云的知识共享

    从Android3.1开始,新安装的程序会被置于”stopped”状态,并且只有在至少手动启动这个程序一次后该程序才会改变状态,能够正常接收到指定的广播消息。Android这样做的目的是防止广播无意或者不必要地开启未启动的APP后台服务。也就是说在Android3.1及以上的版本,在未启动的情况下通过应用自身完成一些操作是不可能的,但Android提供了一种借助其它应用发送指定Flag广播的方式,达到应用在未启动的情况下仍然能够收到消息的效果。

    从Android 3.1开始,系统给Intent定义了两个新的Flag,分别为FLAG_INCLUDE_STOPPED_PACKAGES(表示包含未启动的App)和FLAG_EXCLUDE_STOPPED_PACKAGES(表示不包含未启动的App),用来控制Intent是否要对处于停止状态的App起作用,具体的操作方式如下

    Intent intent = new Intent();
    intent.setAction("com.xxx.xxx.ACTION_XXXX");
    // 这句是关键
    intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
    sendBroadcast(intent);
    

    监听开机广播

    注册

    <receiver
        android:name=".BootCompleteReceiver"
        android:enabled="true"
        android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
      </intent-filter>
    </receiver>
    

    申请权限

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

    广播接收器

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();
    }
    

    一些特殊的广播

    比如操作特别频繁的广播事件,屏幕的关闭和打开 ,电量的变化等广播接收器静态注册无效

    android.intent.action.SCREEN_ON
    android.intent.action.SCREEN_OFF
    android.intent.action.BATTERY_CHANGED
    android.intent.action.CONFIGURATION_CHANGED
    android.intent.action.TIME_TICK
    

    因为这些事android的基本事件,如果大多数程序都监听,会大大的拖慢整个系统(占用内存等),所以android不鼓励我们在程序退出的情况下监听这些事件。不过还是可以通过在service里面注册广播接受器...来解决。

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
    intentFilter.addAction(Intent.ACTION_SCREEN_ON);
    screenReceiver = new ScreenReceiver();
    registerReceiver(screenReceiver, intentFilter);
    

    别忘了注销

    @Override
    protected void onDestroy() {
        unregisterReceiver(screenReceiver);
        super.onDestroy();
    }
    

    监听网络状态变化

    可以静态注册,但是已经被弃用。最好动态注册。

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
    networkReceiver = new NetworkReceiver();
    registerReceiver(networkReceiver, intentFilter);
    

    取消注册

    @Override
    protected void onDestroy() {
        unregisterReceiver(screenReceiver);
        super.onDestroy();
    }
    
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        // 获得正在使用的网络,若无网络连接返回null,所以需要判断
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    
        if (networkInfo != null && networkInfo.isAvailable()) {
          String typeName = networkInfo.getTypeName(); // 返回MOBILE或WIFI
          Toast.makeText(context, typeName + " network is available", Toast.LENGTH_LONG).show();
        } else {
          Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
        }
    }
    

    记得申请权限 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    自定义广播

    标准广播和有序广播

    • 标准广播:异步执行,广播发出后,所有广播接收器几乎同时接收到这条广播。无顺序可言,效率高但是无法被截获,也无法修改数据。可想象成开会时,听领导讲话
    • 有序广播:同步执行,广播发出后,同一时刻只有一个广播接收器能收到。当这个广播接收器处理完成之后,可修改数据后传给下一个接收器,也可以选择截获(不继续往下传递),显然这是有顺序的。可想象成一个人给另外一个人传话,我可以不告诉你呀

    发送标准广播

    定义了两个广播接受器,接收同一个自定义广播com.example.broadcasttest.MY_BROADCAST

    <receiver
        android:name=".MyBroadcastReceiver"
        android:enabled="true"
        android:exported="true">
      <intent-filter>
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
      </intent-filter>
    </receiver>
    
    <receiver
        android:name=".AnotherReceiver"
        android:enabled="true"
        android:exported="true" >
      <intent-filter>
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
      </intent-filter>
    </receiver>
    

    然后在某个活动中,匹配了action在发送广播就行了。

    Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
    sendBroadcast(intent);
    

    两个广播接收器

    public class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "Received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
        }
    }
    
    // 另外一个文件
    public class AnotherReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "Received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
        }
    }
    

    上面的两个接收器都会接收到这个广播。在无序广播中,abortBroadcast()是无效的,而且会在logcat发出警告。

    发送有序广播

    还是上面的两个接收器,不同的是给AnotherReceiver设置了优先级。priority可在[-1000,1000]之间设置,默认为0,值越大优先级越高。

    <receiver
        android:name=".AnotherReceiver"
        android:enabled="true"
        android:exported="true" >
      <intent-filter android:priority="1000">
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
      </intent-filter>
    </receiver>
    

    且在AnotherReceiver中阻断了传播

    public class AnotherReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "Received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
            // 截获后阻断传播
            abortBroadcast();
        }
    }
    

    这样只有AnotherReceiver能接收打广播了,由于在此阻断了传播,所以 MyBroadcastReceiver接收不到。

    不过如果这样发送MyBroadcastReceiver就又可以接收到了

    sendOrderedBroadcast(intent, null, new MyBroadcastReceiver(), null, RESULT_OK, null, null);
    
    

    注意第三个参数,是最终接收器,不管有没有被截获,最后都会传到这个接收器。所以,上面的截获对于MyBroadcastReceiver是无意义的,因为在发送有序广播时指定了这个接收器为最终接收器。而且最终的Receiver无需注册。把上面的MyBroadcastReceiver注册代码删掉,也能接收到。

    本地广播

    前面发送和接收的都是全局广播,发出的广播可以被任何应用程序接收到;而且也可以接收来自其他任何应用程序的广播。这样容易引起安全问题。如发送一些敏感数据,如果被其他软件截获,又或者其他程序不停向我们发送广播。

    使用本地广播,使得广播只能在应用程序内部传递。广播接收器也只能接收来自本应用程序的广播。这样安全性就得到保障。

    本地广播无法通过静态注册来接收。因为静态就是让程序在未启动的情况下也能收到广播。但是在发送本地广播的时候,我们的程序肯定是在运行的。因此完全不需要使用静态注册.

    需要使用到LocalBroadcastManager

    mContext = this;
    // 先注册
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.example.action.LOCAL_BROADCAST");
    localReceiver = new LocalReceiver();
    // 获得实例
    localBroadcastManager = LocalBroadcastManager.getInstance(mContext);
    // 使用localBroadcastManager的注册方法
    localBroadcastManager.registerReceiver(localReceiver, intentFilter);
    // 再发送广播
    Intent intent = new Intent("com.example.action.LOCAL_BROADCAST");
    localBroadcastManager.sendBroadcast(intent);
    // 省略了部分代码
    @Override
    protected void onDestroy() {
      // 取消注册也要是要localBroadcastManager的方法
      localBroadcastManager.unregisterReceiver(localReceiver);
      super.onDestroy();
    }
    

    LocalReceiver

    package com.example.administrator.broadcasttest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.widget.Toast;
    
    public class LocalReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "LocalReceiver", Toast.LENGTH_SHORT).show();
        }
    }
    

    这样,这个广播接收器只能接受来自本应用的广播,而且其他程序也不会接收到这个广播了。

    自定义带权限的广播

    详见WJ_S的CSDN

    谁可以接收我发出的广播?

    假设appA发出了带有权限的广播,那么appB中的广播接收器想要接收到,必须申请appA定义的权限。

    appA中自定义权限

    <permission
        android:name="com.example.broadcasttest.RECEICVE_ABC"
        android:protectionLevel="normal"/>
    

    其中protectionLevel有如下几种比较常见

    normal:默认的,普通权限。应用安装前,用户可以看到相应的权限,但无需用户主动授权。
    dangerous:危险权限,需要动态申请。Android会弹出对话框要求用户进行授权。常见的如:网络使用权限,发送短信权限、联系人信息使用权限等。
    signature:只有和该apk(定义了这个权限的apk)用相同的签名的应用才可以申请该权限。
    

    appA发送带有权限的广播

    Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
    sendBroadcast(intent, "com.example.broadcasttest.RECEICVE_ABC");
    

    appB中的广播接收器若想接收这个广播,必须申请权限<uses-permission android:name="com.example.broadcasttest.RECEICVE_ABC"/>,没有申请权限的一概收不到。

    谁有权发送广播给我?

    比如appB想发送广播给appA,而appA带有权限。

    Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
    sendBroadcast(intent);
    

    appA中自定义的权限

    <permission
        android:name="com.example.broadcasttest.SEND_ABC"
        android:protectionLevel="normal"/>
    

    且appA的接收器加上权限

    <receiver
        android:name=".MyBroadcastReceiver"
        android:enabled="true"
        android:exported="true"
        android:permission="com.example.broadcasttest.SEND_ABC" >
      <intent-filter>
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
      </intent-filter>
    </receiver>
    

    这样appB发送的广播,想让appA也收到。则必须申请appA定义的权限。appB中

    <uses-permission android:name="com.example.broadcasttest.SEND_ABC" />
    

    注意:onReceive方法不要进行耗时操作,当该方法运行时间过长还没结束,程序就会报错。


    by @sunhaiyu

    2017.5.11

    相关文章

      网友评论

          本文标题:Android中的广播

          本文链接:https://www.haomeiwen.com/subject/udeatxtx.html