Yur*_*uri 7 android alarmmanager android-notifications
我正在开发一个android应用程序,其主要用途是在设定的时间显示通知(某些特定的日历应用程序).其中一个主要的抱怨是,用户不会(总是)接收通知,而我最终会陷入困境.
我们在仿真器上对Android 4.4,6,7.0,7.1,8.0,8.1进行了内部测试,并使用了大约10个真实设备(6到8.1),所有设备都按时收到了通知.即使在重新启动时,通知也都按时收到.
我们遇到的一件事是Samsung设备上的SecurityException(> 500个已注册的警报),我们之前因为无法取消而触发了这些警报.它看起来不再是一个问题.
那么,这些缺失通知的原因是什么?它是特定于设备的设置,它是一个简单的错误吗?或者还有其他因素在这里发挥作用?
这是我们使用的代码:
private void cancelAlarm(String notificationId, Class<? extends AbstractReceiver> receiverClass)
throws BroadcastException {
/*
* Create an intent that looks similar, to the one that was registered using add. Making sure the notification id in the action is the same. Now we can search for
* such an intent using the 'getService' method and cancel it.
*/
final Intent intent = new Intent(this.context, receiverClass);
intent.setAction(notificationId);
final PendingIntent pi = PendingIntent.getBroadcast(this.context, 0, intent, 0);
final AlarmManager am = getAlarmManager();
try {
am.cancel(pi);
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(), e.getMessage());
throw new BroadcastException(e.getMessage());
}
}
private void addOrUpdateAlarm(...){
try {
cancelAlarm(notificationId, OurReceiver.class);
} catch (BroadcastException e) {
Log.e(AlarmHelper.class.getSimpleName(), "addOrUpdateAlarm: Can't cancel current alarm before reinserting.", e);
}
Intent intent = new Intent(this.context, receiverClass);
intent.setAction(notificationId);
// some intent.setExtra() calls.
PendingIntent sender = PendingIntent.getBroadcast(this.context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
/* Get the AlarmManager service */
final AlarmManager am = getAlarmManager();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
am.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}else{
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}
Run Code Online (Sandbox Code Playgroud)
}
然后在OurReceiver中我们创建一个notificationchannel:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this
// channel, if the device supports this feature.
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mNotificationManager.createNotificationChannel(mChannel);
}
Run Code Online (Sandbox Code Playgroud)
最后发送通知:
PendingIntent pIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), intent, 0);
Notification n = new NotificationCompat.Builder(context, channel)
.setContentTitle(notificationTitle)
.setContentText(notificationSubText)
.setSmallIcon(R.drawable.logo)
.setContentIntent(pIntent)
.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE)
.setAutoCancel(true).build();
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, n);
Run Code Online (Sandbox Code Playgroud)
Mar*_*ada 10
关于通知,我可以告诉你以下内容:
经过很长一段时间开发一个使用了很多Alarms来自AlarmManager 的应用程序后,我发现了很多关于某些冲突设备的东西.(我没有尝试过JobScheduler,但在大多数情况下,这项技术也会失败).
有一些制造商(众所周知,华为,小米,三星等)在生命周期中干涉AlarmManager.
华为和小米
在锁定屏幕时,华为默认会杀死所有未受保护的应用程序.就是这样,杀敌的应用程序,包括所有的资源alarms,boradcast receivers和services.屏幕锁定后应用程序完全被杀死,因此alarms未收到,并且通知未按逻辑显示.为了避免这种情况,华为提供了一种将应用程序置于保护模式的方法,这意味着当屏幕被锁定时,这些受保护的应用程序不会被杀死.然后,受保护的应用仍会接收alarms和broadcast receivers.
三星
三星有一个"功能"(开发人员不需要的功能)与华为和小米设备"相同",略有不同.锁定scree时,Samsung不会杀死不受保护的应用程序,但是当应用程序未在3天内打开时.在用户停用3天后,应用程序将像华为和小米一样被杀死,因此alarms未收到通知().三星还提供了一种保护应用程序并避免这种情况的方法.
结论
还有其他制造商具有相同的行为,但我不知道所有这些.我可以告诉你华为,小米和三星是他们最知名的.
因此,首先要了解所有发生故障的设备是否都是由这些冲突的制造商生产的.
然后,有一些方法可以让用户知道此设备中的通知可能无法触发,并邀请他们将您的应用程序作为受保护的应用程序.
以编程方式,您可以执行类似的操作(源代码):
if("huawei".equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.huawei_headline).setMessage(R.string.huawei_text)
.setPositiveButton(R.string.go_to_protected, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
startActivity(intent);
}
}).create().show();
}
Run Code Online (Sandbox Code Playgroud)
你可以和其他冲突的制造商一样做.这就是我在这些设备中处理这种情况的方法,并且在大多数情况下通知都很有效.
希望这可以帮助.
一段时间后你没有得到任何通知的问题是因为DOZE.
您有2个选项可以解决您的问题:
从你的应用程序"删除"打盹(https://www.greenbot.com/article/2993199/android/how-to-turn-off-doze-mode-for-specific-apps-in-android-marshmallow.html) (不推荐,每个用户都必须这样做,你不能将其设置为默认值)
根据文档使用FCM高优先级:
*打瞌睡清单
如果可能,请使用FCM进行下游消息传递.如果您的用户必须立即看到通知,请确保使用FCM高优先级消息.在初始消息有效负载内提供足够的信息,因此不需要后续的网络访问.使用setAndAllowWhileIdle()和setExactAndAllowWhileIdle()设置严重警报.在Doze中测试你的应用程序.*
小智 1
一些文档说应用程序最多可以处理 50 个通知。(没有把握)
但是如果您尝试提供不同的通知 ID:
for (int i...>500)
notificationManager.notify(i, n);
Run Code Online (Sandbox Code Playgroud)
希望这有效
| 归档时间: |
|
| 查看次数: |
1402 次 |
| 最近记录: |