适配Android 12的行为变更—–精确的闹钟权限

为了鼓励应用节省系统资源,以 Android 12 及更高版本为目标平台且设置了精确的闹钟的应用必须能够访问“闹钟和提醒”功能,该功能显示在系统设置的特殊应用访问权限屏幕中。如需获取这种特殊应用访问权限,需在清单中请求 SCHEDULE_EXACT_ALARM 权限。

开发者网站请参考:

行为变更:以 Android 12 为目标平台的应用 | Android Developers

   简单来说就是代码中如果使用了setAlarmClock()、setExact()、setExactAndAllowWhileIdle()这几种方法,则设置的是精准的闹钟。在Android12环境下,调用这些方法时,如果SCHEDULE_EXACT_ALARM权限未打开,应用就会crash(做之前先测试一下,要是权限关闭以后,调用这些方法,要是应用不会crash,应该不需要对应)。所以,在调用这些方法时,要增加权限检查。

应对方法:

(1).申请权限

(2).跳转到授权画面

Google Pixel的处理流程:在一打开应用的时候就进行权限检查,如果check到SCHEDULE_EXACT_ALARM权限没打开,就使用toast提示用户打开授权界面,若用户不打开设置的闹钟都不好用(我的建议是弹dialog,要是用户拒绝就直接退出应用,省得后面麻烦)

Uri uri = Uri.parse("package:"+this.getPackageName());
Intent i = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM,uri);
startActivity(i,200);

SCHEDULE_EXACT_ALARM权限 授权画面

(3).判断是否具有权限

alarmManager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
boolean  hasPermission = alarmManager.canScheduleExactAlarms();//true:有权限,false:没有权限
if(hasPermission){
    setAlarmClock();//设置精准闹钟的方法
    setExact();
    setExactAndAllowWhileIdle();
}else{
    //如果没检查到权限,应该做出相应的处理
    //(1).什么都不做,写一条log。如果权限关闭闹钟将无法使用
    //(2).设置不精准的闹钟
    //(3).使用dialog、toast等提示用户打开权限(具体项目,具体设计,不建议在每次设置精准闹钟时候都对用户进行提示,这样的用户体验感不好)
}

注意点:

1.如果用户在SCHEDULE_EXACT_ALARM权限打开的时候设置闹钟,在闹钟到点前将闹钟关闭,到时间闹钟是不会响的,如果用户发现闹钟到点没响,就将SCHEDULE_EXACT_ALARM权限打开,闹钟可以响(闹钟过时,闹钟会被miss掉)

对应方法:设定一个广播接收器(静态,动态都可以),接收”AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED”
这里要注意:只有在打开精准闹钟权限的时候才能收到广播;关闭时是收不到的,只能每次使用方法的时候checkPermission。
如果收不到广播的话,在终端运行以下命令,启用行为更:(模拟器也要运行)
adb shell am compat enable REQUIRE_EXACT_ALARM_PERMISSION [packageName]

正常来说,SCHEDULE_EXACT_ALARM权限是默认打开的,用户应该也不会找到这个将它关闭,更不太可能进行这么非人类的操作,但是我们作为开发者应该考虑滴全面些。我就打算等Android 12适配了,我就给各个手机厂商找茬去。Google Pixel已经被我找过一次茬了,我这里面说的情况,Google就还没做出处理(11月为止)。

2.App info和System Setting都有SCHEDULE_EXACT_ALARM 权限,它们俩的授权界面虽然长得一样,但是是不一样的界面。这将会导致一个问题,要是在App info中将权限关闭,在跳转授权界面的时候可能会跳转两个授权界面。
对应方法:在点击跳转按钮的时候再startActivity,这样就能把App info的授权界面(AlarmsAndRemindersAppActivity)给覆盖掉

public void createAlertDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.extra_alarm_permission_descript_title);
        builder.setPositiveButton(R.string.extra_alarm_permission_turn_on, new DialogInterface.OnClickListener() {
            Uri uri = Uri.parse("package:" + "com.android.deskclock");
            Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, uri);
            public void onClick(DialogInterface dialog, int which) {
                startActivity(intent);
            }
        });
        builder.setNegativeButton(R.string.extra_alarm_permission_ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        mExtraAlarmDialog = builder.create();
        mExtraAlarmDialog.setCancelable(false);
        mExtraAlarmDialog.show();
    }

Share