• Android广播机制(2)


    发送自定义广播

    发送标准广播

    步骤

    1.定义一个广播接收器来接收此广播,新建MyBroadcastReceiver,代码如下:

    //当MyBroadcastReceiver收到自定义的广播时,就会弹出"received in MyBroadcastReceiver"的提示
    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
        }
    }
    

    2.注册广播,在AndroidManifest.xml中对这个广播接收器进行修改:

    //让MyBroadcastReceiver接收一条值为com.example.broadcasttest.MY_BROADCAST的广播,所以一会我们发送的广播就是这样一条广播
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.broadcasttest">
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
          ...
          <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
          </application>
    </manifest>
    

    3.定义一个按钮作为广播的触发点,修改MainActivity的代码:

    public class MainActivity extends AppCompatActivity {
          ...
          @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button= (Button) findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent("com.example.a51104.broadcasttest.MY_BROADCAST");
                    sendBroadcast(intent,null);//发送标准广播,这样所有监听这条广播的广播接收器都可以接收到信息
                }
            });
          ...
        }
     ...
    }
    

    广播是通过Intent传递的,所以也可以携带其他数据

    跨进程广播

    广播是一种可以跨进程的通信方式。因此在我们应用程序内发出的广播,其他的应用程序应该也是可以收到的。
    新建项目BroadcastTest2

    步骤

    1.创建广播接收器

    public class AnotherBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received in AnotherBroadcastReceiver",Toast.LENGTH_SHORT).show();
        }
    }
    

    2.修改AndroidManifest.xml

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.broadcasttest2">
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
          ...
           <receiver
                android:name=".AnotherBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.a51104.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
          </application>
    </manifest>
    

    可以看到AnotherBroadcastReceiver同样接收的是com.example.a51104.broadcasttest.MY_BROADCAST这条广播(但是这是两个程序)
    3.回到BroadcastTest中点击触发广播的按钮,发现两次广播都被接收了。
    疑问:这里创建的都是静态注册的广播,如果是动态的呢?

    发送有序广播

    回到BroadcastTest项目

    1.修改MainActivity中代码:

    public class MainActivity extends AppCompatActivity {
          ...
          @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button= (Button) findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent("com.example.a51104.broadcasttest.MY_BROADCAST");
                     sendOrderedBroadcast(intent,null);//发送有序广播,这样所有监听这条广播的广播接收器都可以接收到信息
                }
            });
          ...
        }
     ...
    }
    

    2.设置广播接收器的先后顺序,保证MyBroadcastReceiver一定比AnotherBroadcastReceiver先收到广播,修改AndroidManifest.xml:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.broadcasttest2">
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
          ...
            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter android:priority="100">
                    <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
          </application>
    </manifest>
    

    我们通过android:priority设置了优先级,优先级越高的广播接收器就更先接收到广播。

    3.为了显示有序广播的特点,我们在MyBroadcastReceiver中截断广播的传播,使得AnotherBroadcastReceiver接收不到广播,修改MyBroadcastReceiver代码:

    //在MyBroadcastReceiver onReceive中添加abortBroadcast()表示将这条广播截断
    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
            abortBroadcast();
        }
    }
    

    使用本地广播

    前面我们发送和接收的广播权全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到儿,并且我们也可以接受来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播很有可能被其他的应用程序截获,或者其他的程序不停地向我们广播接收器发送各种垃圾广播。
    为了能够简单的解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制,发车广播只能够在应用程序内部进行传递,并且广播接收器只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
    本地广播的用法并不复杂,主要是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。

    实例

    修改MainActivity中的代码:

    public class MainActivity extends AppCompatActivity {
        private IntentFilter intentFilter;
        private LocalReceiver localReceiver;
        private LocalBroadcastManager localBroadcastManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取实例
            Button button= (Button) findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent("com.example.a51104.broadcasttest.LOCAL_BROADCAST");
                    localBroadcastManager.sendBroadcast(intent);//发送本地广播
                }
            });
            intentFilter=new IntentFilter();
            intentFilter.addAction("com.example.a51104.broadcasttest.LOCAL_BROADCAST");
            localReceiver=new LocalReceiver();
            localBroadcastManager.registerReceiver(localReceiver,intentFilter);//注册本地广播监听器
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            localBroadcastManager.unregisterReceiver(localReceiver);
        }
        class LocalReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
        }
    }
    }
    

    其实大部分代码都和动态注册广播接收器以及发送广播的代码是一样的,但是注册、发送广播和取消注册都是通过本地广播管理器控制的。本地广播管理通过LocalBroadcastManager.getInstance(this)获取实例。这时这条广播只会在这个应用程序内部传递。
    注:本地广播是无法通过静态注册的方式来接收的。因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,我们的程序是肯定已经启动了,因此也完全不需要使用静态注册的功能。我的理解是因为需要创建本地广播管理者,这个只能在程序中动态创建,所以广播是通过动态注册。

    本地广播的优势

    • 可以明确地知道正在发送的广播不会离开我们的程序,因此不必需要担心机密数据的泄露。
    • 其他的程序无法将广播发送到我们程序的内部,因此不需要担心安全漏洞的隐患。
    • 发送本地广播比发送系统全局广播将会更加高效
  • 相关阅读:
    在Winform框架界面中改变并存储界面皮肤样式
    基于主从表数据录入的处理
    使用ew完成多场景下内网代理穿透
    内网渗透中的端口转发——工具很全
    内网渗透常见端口转发方式——lcx netsh rinetd warthworm regeorg msf portfwd sccat metasploit socks4a tunna
    内网渗透代理和转发
    内网渗透代理——reGeorg 利用 webshell 建立一个 socks 代理进行内网穿透,本质上就是在webshell上做了一个代理转发而已
    内网渗透代理——内网的防火墙只配置了入站规则比如只有80端口
    web未授权访问漏洞总结——mongodb、redis、memcache、jboss、vnc、docker、zk、rsync
    web未授权访问漏洞总结——非常全而细致 redis、mongodb、jenkins、zk、es、memcache、hadoop、couchdb、docker
  • 原文地址:https://www.cnblogs.com/code-fun/p/12873537.html
Copyright © 2020-2023  润新知