记动态注册广播权限问题

最近在开发过程中遇到一个需求,就是跨进程的广播通信,一番尝试之后发现首先好像静态注册广播的方式行不通了,因为Android 8.0的改动中,限制了大部分的隐式广播注册,常见的解决方案有两种:一种是通过intent.setComponent方法将意图改为显式的。另一种方法就是改为动态注册了。

ps:关于Android 8.0中关于广播的改动可以查看官方文档Android 8.0 行为变更中的后台执行限制部分。

跨进程的广播发送与接收解决了之后,我还想添加一个权限限制,让其他程序如果碰巧发送了同样Action的广播后我自己注册的接收器不会接受,其他程序注册的接收器不会收到我自己发出的同样Action的广播。但是经过一番想当然的尝试之后失败了,于是再次去翻文档,然后通过demo测试实践了一番。这里先简单小结一下=:

  1. 简单的权限限制分为两类,一类是带有权限的发送,用于限制接收器的,只有申请了相应权限的接收器才能接收到广播。另一类是带有权限的接收,用于限制发送广播的一方,在发送广播时使用sendBroadcast(Intent,String)方法发送广播。
  2. 如果想要实现A应用发送的广播只有B应用可以接收到,B应用只能接收到A应用发出的广播(注意这里虽然两句话表述好像一致,但是其实包含的情况是不同的),应该就需要在注册广播时通过permissionGroup以及protectionLevel等属性去做更近一步的限制了,具体的实现这里就没有再继续下去了,后面有时间的话可以通过文档permission对这两个属性的介绍尝试一下。

下面根据官方文档广播概况以及具体的Demo实际感受一下两种通过权限限制的广播:

带权限的发送

这种方式可以用来限制广播接收器,在发送广播的一方通过sendBroadcast(Intent,String)方法发送他广播,然后声明了相应权限的的一方中注册的广播接收器才能收到广播。使用这种方式权限需要声明在广播发送方

Project A -- (BroadcastTest1):

<!-- AndroidManifest.xml  -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest1">

    <!--    声明权限 -->
    <permission android:name="com.yu.hu.permissions.BUGREPORT"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
    </application>

</manifest>
class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "MainActivity"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.send_btn)
        //添加button点击事件
        button.setOnClickListener {
            val intent = Intent(ACTION)
            intent.putExtra("test", "test")
            Log.d(TAG, "send BroadcastReceiver with permission")
            //带有权限的发送 接收方必须申请相应权限才能正常接受到
            sendBroadcast(intent,PERMISSION)
        }
    }
}

Project B -- (BroadcastTest2):

<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest2">

    <!-- 申请权限 -->
    <uses-permission android:name="com.yu.hu.permissions.BUGREPORT" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
    </application>

</manifest>
class BugReportReceiver : BroadcastReceiver() {

    companion object {
        const val TAG = "BugReportReceiver"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onReceive(context: Context?, intent: Intent?) {

        val value = intent?.getStringExtra("test")
        Log.d(TAG, "onReceive: msg = $value")
        Toast.makeText(context, "msg2 = $value", Toast.LENGTH_SHORT).show()
    }
}
class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MainActivity2"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val ifl = IntentFilter()
        ifl.addAction(BugReportReceiver.ACTION)
        registerReceiver(BugReportReceiver(), ifl)
    }
}

Project C -- (BroadcastTest3):

class BugReportReceiver : BroadcastReceiver() {

    companion object {
        const val TAG = "BugReportReceiver"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onReceive(context: Context?, intent: Intent?) {=

        val value = intent?.getStringExtra("test")
        Log.d(TAG, "onReceive: msg = $value")
        Toast.makeText(context, "msg2 = $value", Toast.LENGTH_SHORT).show()
    }
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        registerReceiver(BugReportReceiver(), IntentFilter(BugReportReceiver.ACTION))
    }
}

点击Button后输出结果:

2020-07-10 12:51:27.155 25951-25951/com.example.broadcasttest1 D/MainActivity: send BroadcastReceiver with permission
2020-07-10 12:51:27.157 31322-31336/? W/BroadcastQueue: Permission Denial: receiving Intent { act=com.yu.hu.action.BUGREPPORT flg=0x10 (has extras) } to ProcessRecord{3b20417 25865:com.example.boradcasttest3/u0a164} (pid=25865, uid=10164) requires com.yu.hu.permissions.BUGREPORT due to sender com.example.broadcasttest1 (uid 10155)
2020-07-10 12:51:27.161 25907-25907/com.example.broadcasttest2 D/BugReportReceiver: onReceive: msg = test

可以看到只有B收到了广播了而C没有收到,因为BAndroidManifest.xml中申请了权限,而C没有,所以报了Permission Denial的错误。在C中也申请了权限后就同样能接收到广播了。

带权限的接收

这种方式可以用来限制发送广播的一方,只有申请了相应的权限才能成功发送广播。使用这种方式权限需要声明在广播接收器的注册方
Project A -- (BroadcastTest1): - 申请权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest1">

    <uses-permission android:name="com.test.permission.receiver"/>
    ...
</manifest>
class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "MainActivity"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.send_btn)
        button.setOnClickListener {
            val intent = Intent(ACTION)
            intent.putExtra("test", "test")
            Log.d(TAG, "send Broadcast with permission")
            sendBroadcast(intent)
        }
    }
}

Project B -- (BroadcastTest2): - 不申请权限

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MainActivity2"
        const val ACTION = "com.yu.hu.action.BUGREPPORT"
        const val PERMISSION = "com.yu.hu.permissions.BUGREPORT"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.send_btn)
        button.setOnClickListener {
            val intent = Intent(ACTION)
            intent.putExtra("test", "test")
            Log.d(TAG, "send Broadcast without permission")
            //不申请权限发送
            sendBroadcast(intent)
        }
    }
}

Project C -- (BroadcastTest3): - 声明权限并在注册时添加权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.boradcasttest3">

    <permission android:name="com.test.permission.receiver"/>
    ...

</manifest>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        registerReceiver(BugReportReceiver(), IntentFilter(BugReportReceiver.ACTION), "com.test.permission.receiver", null)
    }
}

A中发送广播:

2020-07-10 14:07:36.187 12843-12843/com.example.broadcasttest1 D/MainActivity: send Broadcast with permission
2020-07-10 14:07:36.191 12600-12600/com.example.boradcasttest3 D/BugReportReceiver: onReceive2: msg = test

成功发送也成功接收处理。下面是在B中发送广播的日志:

2020-07-10 14:08:04.368 13003-13003/com.example.broadcasttest2 D/MainActivity2: send Broadcast without permission
2020-07-10 14:08:04.370 31322-31336/? W/BroadcastQueue: Permission Denial: broadcasting Intent { act=com.yu.hu.action.BUGREPPORT flg=0x10 (has extras) } from com.example.broadcasttest2 (pid=13003, uid=10162) requires com.test.permission.receiver due to registered receiver BroadcastFilter{37dbe8b u0 ReceiverList{7706c5a 12600 com.example.boradcasttest3/10164/u0 remote:8530405}}

发送之后报了Permission Denial,所以接收器没有接收到这条广播。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266