记录一次android12的精准闹钟崩溃的处理

376 阅读1分钟

由于Target31对前台服务的限制,现在尝试用精准闹钟来启动前台服务,进而避免ForegroundServiceStartNotAllowedException异常。但是项目在实际运行中却发现了另外的问题。

调用的代码片段如下:

AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || checkSelfPermission(Manifest.permission.SCHEDULE_EXACT_ALARM) == PackageManager.PERMISSION_GRANTED) {
    PendingIntent alarmIntent;
    Intent intent = new Intent(context, TestFGService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        alarmIntent = PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
    } else {
        alarmIntent = PendingIntent.getService(context, 0, intent, 0);
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + duration, alarmIntent);
    } else {
        alarmMgr.setExact(AlarmManager.RTC, System.currentTimeMillis() + duration, alarmIntent);
    }
}

这里已经检查了SCHEDULE_EXACT_ALARM权限,但是线上还是统计到了少数的crash,其中有下面这段日志:

Unable to create application com.skyline.fgserviceapplication.AppContext: java.lang.SecurityException: Caller com.skyline.fgserviceapplication needs to hold android.permission.SCHEDULE_EXACT_ALARM to set exact alarms.

我又检查了一遍代码,我确实给了权限,并且在设置闹钟前检查是否得到权限。但当我在应用设置里把对应app的闹钟与提醒功能关闭时,我发现checkSelfPermission并没有按照预期返回PERMISSION_DENIED,而是返回PERMISSION_GRANTED。后来才知道闹钟与提醒功能那里关闭时并没有拒绝精准闹钟权限,应对这种情况需要使用AlarmManagercanScheduleExactAlarms方法来进一步检查是否可以启动闹钟。示例代码如下:

AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || alarmMgr.canScheduleExactAlarms()) {
    PendingIntent alarmIntent;
    Intent intent = new Intent(context, TestFGService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        alarmIntent = PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
    } else {
        alarmIntent = PendingIntent.getService(context, 0, intent, 0);
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + duration, alarmIntent);
    } else {
        alarmMgr.setExact(AlarmManager.RTC, System.currentTimeMillis() + duration, alarmIntent);
    }
}