Android开发——静态注册的BroadcastReceiver怎么收到广播

如果你不想看那么多字,可以直接点更简单的方法


跟着教材学习Android的BroadcastReceiver时发现静态注册的BroadcastReceiver无法收到广播,但是动态注册的却可以!

静态注册

定义一个广播接收器先
.receiver.MyBroadcastReceiver

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "接收到Intent的action为"+intent.getAction()
                +"\n消息内容是"+intent.getStringExtra("msg"),Toast.LENGTH_LONG).show();
    }
}

发送广播
.BroadcastActivity

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class BroadcastActivity extends AppCompatActivity {

    private Button mSendBroadcastBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        
        mSendBroadcastBtn=findViewById(R.id.btn_send_broadcast);
        mSendBroadcastBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.putExtra("msg", "这是一条广播消息!");
                sendBroadcast(intent);
            }
        });
    }
}

BroadcastReceiver属于Android四大组件之一,需要在AndroidManifest.xml文件中注册
AndroidManifest.xml

		<receiver android:name=".receiver.MyBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
            </intent-filter>
        </receiver>

这是看了书之后写的,按理说没什么问题,然而,就是收不到广播!换动态注册试一下!

动态注册

动态注册就不需要在AndroidManifest.xml文件中注册广播接收器了,直接在代码中注册就行了
.BroadcastActivity

		IntentFilter filter=new IntentFilter(Intent.ACTION_SEND);
        MyBroadcastReceiver receiver=new MyBroadcastReceiver();
        registerReceiver(receiver, filter);

然后就可以收到广播了,但是这tm是为什么啊???

可恶的API 8.0(级别26)

经过不懈的努力(baidu),我机智的小脑壳发现了问题所在,Android的官方文档里写了这样一段话:

适配 Android 8.0 或更高版本的应用无法继续在其清单中为隐式广播注册广播接收器。 隐式广播是一种不专门针对该应用的广播。 例如,ACTION_PACKAGE_REPLACED 就是一种隐式广播,因为该广播将被发送给所有已注册侦听器,让后者知道设备上的某些软件包已被替换。 不过,ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为不管已为该广播注册侦听器的其他应用有多少,它都会只被发送给软件包已被替换的应用。
应用可以继续在它们的清单中注册显式广播。
应用可以在运行时使用 Context.registerReceiver() 为任意广播(不管是隐式还是显式)注册接收器。
需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用。

所以,如果想要静态注册的BroadcastReceiver管用,就要添加签名权限!

自定义权限

在AndroidManifest.xml文件中定义权限并使用权限
AndroidManifest.xml

	<uses-permission android:name="com.example.servicetest.SEND_BROADCASTRECEIVER"/>
    <permission android:name="com.example.servicetest.SEND_BROADCASTRECEIVER"
        android:protectionLevel="signature"/>
		<receiver android:name=".receiver.MyBroadcastReceiver"
            android:permission="com.example.servicetest.SEND_BROADCASTRECEIVER">
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
            </intent-filter>
        </receiver>

permission的name命名的时候要注意:

系统不允许多个软件包声明具有相同名称的权限,除非所有软件包都使用相同的证书进行签名。如果某个软件包声明了一个权限,则系统不允许用户安装具有相同权限名称的其他软件包,除非这些软件包使用与第一个软件包相同的证书进行签名。为了避免命名冲突,我们建议为自定义权限使用反向域式命名,例如 com.example.myapp.ENGAGE_HYPERSPACE。

protectionLevel有好几个值,每个值的含义如下:

含义
“normal”默认值。具有较低风险的权限,此类权限允许请求授权的应用访问隔离的应用级功能,对其他应用、系统或用户的风险非常小。系统会自动向在安装时请求授权的应用授予此类权限,无需征得用户的明确许可(但用户始终可以选择在安装之前查看这些权限)。
“dangerous”具有较高风险的权限,此类权限允许请求授权的应用访问用户私人数据或获取可对用户造成不利影响的设备控制权。由于此类权限会带来潜在风险,因此系统可能不会自动向请求授权的应用授予此类权限。例如,应用请求的任何危险权限都可能会向用户显示并且获得确认才会继续执行操作,或者系统会采取一些其他方法来避免用户自动允许使用此类功能。
“signature”只有在请求授权的应用使用与声明权限的应用相同的证书进行签名时系统才会授予的权限。如果证书匹配,则系统会在不通知用户或征得用户明确许可的情况下自动授予权限。
“signatureOrSystem”“signature|privileged” 的旧同义词。在 API 级别 23 中已弃用。
系统仅向位于 Android 系统映像的专用文件夹中的应用或使用与声明权限的应用相同的证书进行签名的应用授予的权限。不要使用此选项,因为 signature 保护级别应足以满足大多数需求,无论应用安装在何处,该保护级别都能正常发挥作用。“signatureOrSystem”权限适用于以下特殊情况:多个供应商将应用内置到一个系统映像中,并且需要明确共享特定功能,因为这些功能是一起构建的。

在这个例子里要使用"signature"!
在发送广播的时候也要加上权限
.BroadcastActivity

		mSendBroadcastBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String permission="com.example.servicetest.SEND_BROADCASTRECEIVER";
                Intent intent=new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.putExtra("msg", "这是一条广播消息!");
                sendBroadcast(intent,permission);
            }
        });

现在就能成功发送广播了!看效果:
在这里插入图片描述

更简单的方法

如果你觉得自定义权限很麻烦,但是又想用静态注册,你可以这样:
.BroadcastActivity

intent.setComponent(new ComponentName("com.example.servicetest","com.example.servicetest.receiver.MyBroadcastReceiver"));

ComponentName的第一个参数指的是应用的包名,第二个参数指的是要启动的广播接收器的路径
就是这么简单粗暴!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值